模塊與包python
什麼是模塊json
模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。api
#在python中,模塊的使用方式都是同樣的,但其實細說的話,模塊能夠分爲四個通用類別: app
1 使用python編寫的.py文件,是被導入使用的函數
2 已被編譯爲共享庫或DLL的C或C++擴展編碼
3 把一系列模塊組織到一塊兒的文件夾(注:文件夾下有一個__init__.py文件,該文件夾稱之爲包),包就是包含init的文件夾,也是被導入使用的spa
4 使用C編寫並連接到python解釋器的內置模塊命令行
導入模塊幹了那些事日誌
一、執行源文件code
二、以源文件爲基礎產生一個全局名稱空間,若是調用源空間中的函數,用.就行,做用域關係在調用的時候就已經固定了。
三、再當前位置拿到一個模塊名,指向2建立的名稱空間
import 使用
別名 用 as
1 import spam as sm
2 print(sm.money)
一行中導入多個模塊,用逗號隔開
import os,sys,spam
自定義模塊、內置模塊、第三方模塊、包 等等
from ... inmport ... 用法
from...import * # *表明全部(除了橫杆開頭的名字,如 _money()),通常不建議用,
#也能夠在模塊開頭增長 __all__=['money','x','y'] 來控制*的識別範圍,
#_ 和 __all__ 只是對from...import * 有用
#from sys import * 把spam中全部的不是如下劃線(_)開頭的名字都導入到當前位置
#大部分狀況下咱們的python程序不該該使用這種導入方式,由於*你不知道你導入什麼名字,頗有可能會覆蓋掉你以前已經定義的名字。並且可讀性極其的差,在交互式環境中導入時沒有問題。
#優勢:使用源文件內的名字時無需加前綴,使用方便
#缺點:容易與當前文件的名稱空間內的名字混淆
#能夠起別名
# from spam import money as m
==============
'''
查找模塊
模塊只有在第一次導入時纔會執行,以後的導入都是直接引用內存中已經存在的結果
import sys
print(sys.modules) #一個字典,存放的是已經加載到內存的模塊
print(sys.path) #一個列表,存放的是當前執行文件的路徑
模塊的搜索路徑
import sys
先從哪裏找?
先從內存裏找,而後再去硬盤上找
python文件修改完後必定要重啓程序,從新加載一遍纔會生效
模塊的查找順序是:內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊
好比找abc\abc.py模塊,若內存中和硬盤中都找不到,那就要去sys.path中找,這就須要吧abc.py所在的目錄路徑添加到sys.path裏去
sys.path.append(r'C:\Users\Administrator\PycharmProjects\python\abc') #將目錄添加到最後
sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\python\abc') #將目前插到最前面,找到的更快
注意:自定義的模塊必定不要與python自帶的模塊名重名
要明確 執行文件是誰,被導入的文件是誰
'''
'''
兩種使用方法:
被當作腳本使用
被當作模塊使用
__name__
#文件當作腳本運行時__name__等於__main__
#文件當作模塊被加載運行時__name__等於模塊名
寫模塊時添加以下代碼(只有被當作腳本使用時,纔會執行if裏的代碼):
if __name__ == '__main__':
#當作腳本使用
func1()
func2()
func3()
#導入模塊實際上就是導入文件下的 __init__.py 文件
#開發者經過修改 __init__.py 文件,方便使用者調用函數
#1.關於包相關的導入語句也分爲import和from ... import ...兩種,可是不管哪一種,不管在什麼位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,不然非法。能夠帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。但對於導入後,在使用時就沒有這種限制了,點的左邊能夠是包,模塊,函數,類(它們均可以用點的方式調用本身的屬性)。
#二、import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字一樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
#三、包A和包B下有同名模塊也不會衝突,如A.a與B.a來自倆個命名空間
三步:
一、執行文件
二、產生名稱空間
三、調用函數
絕對導入與相對導入
咱們的最頂級包glance是寫給別人用的,而後在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:
絕對導入:以glance做爲起始
相對導入:用.或者..的方式最爲起始(只能在一個包中使用,不能用於不一樣目錄內)
例如:咱們在glance/api/version.py中想要導入glance/cmd/manage.py
# 絕對導入: 以執行文件的sys.path爲起始點開始導入,稱之爲絕對導入
# 優勢: 執行文件與被導入的模塊中均可以使用
# 缺點: 全部導入都是以sys.path爲起始點,導入麻煩
# 相對導入: 參照當前所在文件的文件夾爲起始開始查找,稱之爲相對導入
# 符號: .表明當前所在文件的文件加,..表明上一級文件夾,...表明上一級的上一級文件夾
# 優勢: 導入更加簡單
# 缺點: 只能在導入包中的模塊時才能使用
#注意:
1. 相對導入只能用於包內部模塊之間的相互導入,導入者與被導入者都必須存在於一個包內
2. attempted relative import beyond top-level package # 試圖在頂級包以外使用相對導入是錯誤的,言外之意,必須在頂級包內使用相對導入,每增長一個.表明跳到上一級文件夾,而上一級不該該超出頂級包
軟件開發規範:
bin 目錄下是執行文件
conf 目錄下是控制文件
lib 目錄下是本程序須要依賴或開發的功能模塊文件
log 目錄下是日誌文件
db 目錄下存放數據文件
core 目錄下存放核心的邏輯
Readme
示例 :
1 ############### 2 #===============>star.py 3 import sys,os 4 ##該文件所在位置:D:\第1層\第2層\第3層\第4層\第5層\test_gfh.py 5 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 獲取當前運行腳本的絕對路徑 6 ''' 7 若是直接在python console 中或者命令行中運行上面代碼,則會報以下錯誤: 8 NameError: name '__file__' is not defined 9 10 緣由是:‘__file__'這個參數表明的是python解釋器正在執行的腳本文件,若是直接在命令行運行上面兩行代碼,則python解釋器找不到正在執行的腳本文件,即咱們將它寫在一個腳本文件中,再在解釋器中運行這個腳本文件就ok了 11 12 ''' 13 sys.path.append(BASE_DIR) #將路徑添加到sys.path 14 15 from core import src 16 17 if __name__ == '__main__': 18 src.run() 19 #===============>settings.py 20 import os 21 22 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 23 DB_PATH=os.path.join(BASE_DIR,'db','db.json') 24 LOG_PATH=os.path.join(BASE_DIR,'log','access.log') 25 LOGIN_TIMEOUT=5 26 27 """ 28 logging配置 29 """ 30 # 定義三種日誌輸出格式 31 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ 32 '[%(levelname)s][%(message)s]' #其中name爲getlogger指定的名字 33 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 34 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' 35 36 # log配置字典 37 LOGGING_DIC = { 38 'version': 1, 39 'disable_existing_loggers': False, 40 'formatters': { 41 'standard': { 42 'format': standard_format 43 }, 44 'simple': { 45 'format': simple_format 46 }, 47 }, 48 'filters': {}, 49 'handlers': { 50 #打印到終端的日誌 51 'console': { 52 'level': 'DEBUG', 53 'class': 'logging.StreamHandler', # 打印到屏幕 54 'formatter': 'simple' 55 }, 56 #打印到文件的日誌,收集info及以上的日誌 57 'default': { 58 'level': 'DEBUG', 59 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 60 'formatter': 'standard', 61 'filename': LOG_PATH, # 日誌文件 62 'maxBytes': 1024*1024*5, # 日誌大小 5M 63 'backupCount': 5, 64 'encoding': 'utf-8', # 日誌文件的編碼,不再用擔憂中文log亂碼了 65 }, 66 }, 67 'loggers': { 68 #logging.getLogger(__name__)拿到的logger配置 69 '': { 70 'handlers': ['default', 'console'], # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕 71 'level': 'DEBUG', 72 'propagate': True, # 向上(更高level的logger)傳遞 73 }, 74 }, 75 } 76 77 78 #===============>src.py 79 from conf import settings 80 from lib import common 81 import time 82 83 logger=common.get_logger(__name__) 84 85 current_user={'user':None,'login_time':None,'timeout':int(settings.LOGIN_TIMEOUT)} 86 def auth(func): 87 def wrapper(*args,**kwargs): 88 if current_user['user']: 89 interval=time.time()-current_user['login_time'] 90 if interval < current_user['timeout']: 91 return func(*args,**kwargs) 92 name = input('name>>: ') 93 password = input('password>>: ') 94 db=common.conn_db() 95 if db.get(name): 96 if password == db.get(name).get('password'): 97 logger.info('登陸成功') 98 current_user['user']=name 99 current_user['login_time']=time.time() 100 return func(*args,**kwargs) 101 else: 102 logger.error('用戶名不存在') 103 104 return wrapper 105 106 @auth 107 def buy(): 108 print('buy...') 109 110 @auth 111 def run(): 112 113 print(''' 114 購物 115 查看餘額 116 轉帳 117 ''') 118 while True: 119 choice = input('>>: ').strip() 120 if not choice:continue 121 if choice == '1': 122 buy() 123 124 125 126 #===============>db.json 127 {"egon": {"password": "123", "money": 3000}, "alex": {"password": "alex3714", "money": 30000}, "wsb": {"password": "3714", "money": 20000}} 128 129 #===============>common.py 130 from conf import settings 131 import logging 132 import logging.config 133 import json 134 135 def get_logger(name): 136 logging.config.dictConfig(settings.LOGGING_DIC) # 導入上面定義的logging配置 137 logger = logging.getLogger(name) # 生成一個log實例 138 return logger 139 140 141 def conn_db(): 142 db_path=settings.DB_PATH 143 dic=json.load(open(db_path,'r',encoding='utf-8')) 144 return dic 145 146 147 #===============>access.log 148 [2017-10-21 19:08:20,285][MainThread:10900][task_id:core.src][src.py:19][INFO][登陸成功] 149 [2017-10-21 19:08:32,206][MainThread:10900][task_id:core.src][src.py:19][INFO][登陸成功] 150 [2017-10-21 19:08:37,166][MainThread:10900][task_id:core.src][src.py:24][ERROR][用戶名不存在] 151 [2017-10-21 19:08:39,535][MainThread:10900][task_id:core.src][src.py:24][ERROR][用戶名不存在]