包
包是一種通過使用‘.模塊名’來組織python模塊名稱空間的方式,
1. 無論是import形式還是from...import形式,凡是在匯入陳述句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關于包才有的匯入語法
2. 包是目錄級的(檔案夾級),檔案夾是用來組成py檔案(包的本質就是一個包含__init__.py檔案的目錄)
3. import匯入檔案時,產生名稱空間中的名字來源于檔案,import 包,產生的名稱空間的名字同樣來源于檔案,即包下的__init__.py,匯入包本質就是在匯入該檔案
強調:
1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯
2. 創建包的目的不是為了運行,而是被匯入使用,記住,包只是模塊的一種形式而已,包即模塊
包A和包B下有同名模塊也不會沖突,如A.a與B.a來自倆個命名空間
import os
os.makedirs('glance/api')
os.makedirs('glance/cmd')
os.makedirs('glance/db')
l = []
l.append(open('glance/__init__.py','w'))
l.append(open('glance/api/__init__.py','w'))
l.append(open('glance/api/policy.py','w'))
l.append(open('glance/api/versions.py','w'))
l.append(open('glance/cmd/__init__.py','w'))
l.append(open('glance/cmd/manage.py','w'))
l.append(open('glance/db/models.py','w'))
map(lambda f:f.close() ,l)
glance/ #Top-level package
├── __init__.py #Initialize the glance package
├── api #Subpackage for api
│ ├── __init__.py
│ ├── policy.py
│ └── versions.py
├── cmd #Subpackage for cmd
│ ├── __init__.py
│ └── manage.py
└── db #Subpackage for db
├── __init__.py
└── models.py
#檔案內容
#policy.py
def get():
print('from policy.py')
#versions.py
def create_resource(conf):
print('from version.py: ',conf)
#manage.py
def main():
print('from manage.py')
#models.py
def register_models(engine):
print('from models.py: ',engine)
注意事項
1.關于包相關的匯入陳述句也分為import和from ... import ...兩種,但是無論哪種,無論在什么位置,在匯入時都必須遵循一個原則:凡是在匯入時帶點的,點的左邊都必須是一個包,否則非法,可以帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則,
2.對于匯入后,在使用時就沒有這種限制了,點的左邊可以是包,模塊,函式,類(它們都可以用點的方式呼叫自己的屬性),
3.對比import item 和from item import name的應用場景:
如果我們想直接使用name那必須使用后者,
import
我們在與包glance同級別的檔案中測驗
1 import glance.db.models
2 glance.db.models.register_models('mysql')
from...import...
需要注意的是from后import匯入的模塊,必須是明確的一個不能帶點,否則會有語法錯誤,如:from a import b.c是錯誤語法
我們在與包glance同級別的檔案中測驗
1 from glance.db import models
2 models.register_models('mysql')
3
4 from glance.db.models import register_models
5 register_models('mysql')
__init__.py檔案
不管是哪種方式,只要是第一次匯入包或者是包的任何其他部分,都會依次執行包下的__init__.py檔案(我們可以在每個包的檔案內都列印一行內容來驗證一下),這個檔案可以為空,但是也可以存放一些初始化包的代碼,
from galnce.api import *
在講模塊時,我們已經討論過了從一個模塊內匯入所有*,此處我們研究從一個包匯入所有*,
此處是想從包api中匯入所有,實際上該陳述句只會匯入包api下__init__.py檔案中定義的名字,我們可以在這個檔案中定義__all___:
#在__init__.py中定義
x=10
def func():
print('from api.__init.py')
__all__=['x','func','policy']
此時我們在于glance同級的檔案中執行from glance.api import *就匯入__all__中的內容(versions仍然不能匯入),
glance/
├── __init__.py
├── api
│ ├── __init__.py __all__ = ['policy','versions']
│ ├── policy.py
│ └── versions.py
├── cmd __all__ = ['manage']
│ ├── __init__.py
│ └── manage.py
└── db __all__ = ['models']
├── __init__.py
└── models.py
from glance.api import *
policy.get()
絕對匯入和相對匯入
我們的最頂級包glance是寫給別人用的,然后在glance包內部也會有彼此之間互相匯入的需求,這時候就有絕對匯入和相對匯入兩種方式:
絕對匯入:以glance作為起始
相對匯入:用.或者..的方式最為起始(只能在一個包中使用,不能用于不同目錄內)
例如:我們在glance/api/version.py中想要匯入glance/cmd/manage.py
在glance/api/version.py
#絕對匯入
from glance.cmd import manage
manage.main()
#相對匯入
from ..cmd import manage
manage.main()
測驗結果:注意一定要在于glance同級的檔案中測驗
1 from glance.api import versions
注意:在使用pycharm時,有的情況會為你多做一些事情,這是軟體相關的東西,會影響你對模塊匯入的理解,因而在測驗時,一定要回到命令列去執行,模擬我們生產環境,你總不能拿著pycharm去上線代碼吧!!!
特別需要注意的是:可以用import匯入內置或者第三方模塊(已經在sys.path中),但是要絕對避免使用import來匯入自定義包的子模塊(沒有在sys.path中),應該使用from... import ...的絕對或者相對匯入,且包的相對匯入只能用from的形式,
比如我們想在glance/api/versions.py中匯入glance/api/policy.py,有的同學一抽這倆模塊是在同一個目錄下,十分開心的就去做了,它直接這么做
1 #在version.py中
2
3 import policy
4 policy.get()
沒錯,我們單獨運行version.py是一點問題沒有的,運行version.py的路徑搜索就是從當前路徑開始的,于是在匯入policy時能在當前目錄下找到
但是你想啊,你子包中的模塊version.py極有可能是被一個glance包同一級別的其他檔案匯入,比如我們在于glance同級下的一個test.py檔案中匯入version.py,如下
from glance.api import versions
'''
執行結果:
ImportError: No module named 'policy'
'''
'''
分析:
此時我們匯入versions在versions.py中執行
import policy需要找從sys.path也就是從當前目錄找policy.py,
這必然是找不到的
'''
glance/
├── __init__.py from glance import api
from glance import cmd
from glance import db
├── api
│ ├── __init__.py from glance.api import policy
from glance.api import versions
│ ├── policy.py
│ └── versions.py
├── cmd from glance.cmd import manage
│ ├── __init__.py
│ └── manage.py
└── db from glance.db import models
├── __init__.py
└── models.py
glance/
├── __init__.py from . import api #.表示當前目錄
from . import cmd
from . import db
├── api
│ ├── __init__.py from . import policy
from . import versions
│ ├── policy.py
│ └── versions.py
├── cmd from . import manage
│ ├── __init__.py
│ └── manage.py from ..api import policy
#..表示上一級目錄,想再manage中使用policy中的方法就需要回到上一級glance目錄往下找api包,從api匯入policy
└── db from . import models
├── __init__.py
└── models.py
單獨匯入包
單獨匯入包名稱時不會匯入包中所有包含的所有子模塊,如
#在與glance同級的test.py中
import glance
glance.cmd.manage.main()
'''
執行結果:
AttributeError: module 'glance' has no attribute 'cmd'
'''
解決方法:
1 #glance/__init__.py
2 from . import cmd
3
4 #glance/cmd/__init__.py
5 from . import manage
執行:
1 #在于glance同級的test.py中
2 import glance
3 glance.cmd.manage.main()
千萬別問:__all__不能解決嗎,__all__是用于控制from...import *
import glance之后直接呼叫模塊中的方法
glance/
├── __init__.py from .api import *
from .cmd import *
from .db import *
├── api
│ ├── __init__.py __all__ = ['policy','versions']
│ ├── policy.py
│ └── versions.py
├── cmd __all__ = ['manage']
│ ├── __init__.py
│ └── manage.py
└── db __all__ = ['models']
├── __init__.py
└── models.py
import glance
policy.get()
軟體開發規范

#=============>bin目錄:存放執行腳本 #start.py import sys,os BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from core import core from conf import my_log_settings if __name__ == '__main__': my_log_settings.load_my_logging_cfg() core.run() #=============>conf目錄:存放組態檔 #config.ini [DEFAULT] user_timeout = 1000 [egon] password = 123 money = 10000000 [alex] password = alex3714 money=10000000000 [yuanhao] password = ysb123 money=10 #settings.py import os config_path=r'%s\%s' %(os.path.dirname(os.path.abspath(__file__)),'config.ini') user_timeout=10 user_db_path=r'%s\%s' %(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),\ 'db') #my_log_settings.py """ logging配置 """ import os import logging.config # 定義三種日志輸出格式 開始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' #其中name為getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定義日志輸出格式 結束 logfile_dir = r'%s\log' %os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # log檔案的目錄 logfile_name = 'all2.log' # log檔案名 # 如果不存在定義的日志目錄就創建一個 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log檔案的全路徑 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, 'handlers': { #列印到終端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 列印到螢屏 'formatter': 'simple' }, #列印到檔案的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到檔案 'formatter': 'standard', 'filename': logfile_path, # 日志檔案 'maxBytes': 1024*1024*5, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志檔案的編碼,再也不用擔心中文log亂碼了 }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], # 這里把上面定義的兩個handler都加上,即log資料既寫入檔案又列印到螢屏 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)傳遞 }, }, } def load_my_logging_cfg(): logging.config.dictConfig(LOGGING_DIC) # 匯入上面定義的logging配置 logger = logging.getLogger(__name__) # 生成一個log實體 logger.info('It works!') # 記錄該檔案的運行狀態 if __name__ == '__main__': load_my_logging_cfg() #=============>core目錄:存放核心邏輯 #core.py import logging import time from conf import settings from lib import read_ini config=read_ini.read(settings.config_path) logger=logging.getLogger(__name__) current_user={'user':None,'login_time':None,'timeout':int(settings.user_timeout)} def auth(func): def wrapper(*args,**kwargs): if current_user['user']: interval=time.time()-current_user['login_time'] if interval < current_user['timeout']: return func(*args,**kwargs) name = input('name>>: ') password = input('password>>: ') if config.has_section(name): if password == config.get(name,'password'): logger.info('登錄成功') current_user['user']=name current_user['login_time']=time.time() return func(*args,**kwargs) else: logger.error('用戶名不存在') return wrapper @auth def buy(): print('buy...') @auth def run(): print(''' 購物 查看余額 轉賬 ''') while True: choice = input('>>: ').strip() if not choice:continue if choice == '1': buy() if __name__ == '__main__': run() #=============>db目錄:存放資料庫檔案 #alex_json #egon_json #=============>lib目錄:存放自定義的模塊與包 #read_ini.py import configparser def read(config_file): config=configparser.ConfigParser() config.read(config_file) return config #=============>log目錄:存放日志 #all2.log [2017-07-29 00:31:40,272][MainThread:11692][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:31:41,789][MainThread:11692][task_id:core.core][core.py:25][ERROR][用戶名不存在] [2017-07-29 00:31:46,394][MainThread:12348][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:31:47,629][MainThread:12348][task_id:core.core][core.py:25][ERROR][用戶名不存在] [2017-07-29 00:31:57,912][MainThread:10528][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:32:03,340][MainThread:12744][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:32:05,065][MainThread:12916][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:32:08,181][MainThread:12916][task_id:core.core][core.py:25][ERROR][用戶名不存在] [2017-07-29 00:32:13,638][MainThread:7220][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:32:23,005][MainThread:7220][task_id:core.core][core.py:20][INFO][登錄成功] [2017-07-29 00:32:40,941][MainThread:7220][task_id:core.core][core.py:20][INFO][登錄成功] [2017-07-29 00:32:47,222][MainThread:7220][task_id:core.core][core.py:20][INFO][登錄成功] [2017-07-29 00:32:51,949][MainThread:7220][task_id:core.core][core.py:25][ERROR][用戶名不存在] [2017-07-29 00:33:00,213][MainThread:7220][task_id:core.core][core.py:20][INFO][登錄成功] [2017-07-29 00:33:50,118][MainThread:8500][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!] [2017-07-29 00:33:55,845][MainThread:8500][task_id:core.core][core.py:20][INFO][登錄成功] [2017-07-29 00:34:06,837][MainThread:8500][task_id:core.core][core.py:25][ERROR][用戶名不存在] [2017-07-29 00:34:09,405][MainThread:8500][task_id:core.core][core.py:25][ERROR][用戶名不存在] [2017-07-29 00:34:10,645][MainThread:8500][task_id:core.core][core.py:25][ERROR][用戶名不存在]View Code
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/194773.html
標籤:Python
上一篇:Python_常用模塊
下一篇:Python_初識面向物件
