第五篇:python基礎_5
本篇內容
- 協程函數
- 遞歸
- 二分法
- import語句
- from...import語句
- 模塊搜索路徑
- 包的導入
- 軟件開發規範
- logging模塊的使用
一、 協程函數
1.定義
協程函數就是使用了yield表達式形式的生成器。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei def eater(name): print("%s eat food" %name) while True: food = yield g = eater("yanglei") print(g)
2.執行過程
運行協程函數,要先next(),對協程函數進行初始化函數,然後再send() ,send會給yield傳一個值。
next()與send()的區別:
next():讓函數初始化。
send():觸發下一次代碼的執行時,會給yield賦值。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei def eater(name): print(‘%s 說:我開動啦‘ %name) food_list=[] while True: food=yield food_list food_list.append(food) print(‘%s eat %s‘ %(name,food)) def producer(): alex_g=eater(‘xiaolan‘) next(alex_g) while True: food=input(‘>>: ‘).strip() if not food:continue print(alex_g.send(food)) producer()
3.裝飾器擴展
協程函數與裝飾器的結合,可以避免忘記初始化函數
#!/usr/binl/env python #encoding: utf-8 #author: YangLei def init(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) next(res) return res return wrapper @init def eater(name): print("%s eat food" %name) food_list=[] while True: food = yield food_list print("%s star to eat %s" %(name,food)) food_list.append(food) g = eater("xiaolan") print(g.send("火鍋")) print(g.send("烤肉")) print(g.send("烤魚"))
4.面向過程應用
面向過程:核心是過程二字,過程即解決問題的步驟,基於面向過程去設計程序就像是在設計一條工業流水線,是一種機械式的思維方式。
優點:程序結構清晰,可以把復雜的問題簡單化,流程化。
缺點:可擴展性差,一條流線只是用來解決一個問題。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei #grep -rl ‘error‘ /dir/ import os def init(func): def wrapper(*args,**kwargs): g=func(*args,**kwargs) next(g) return g return wrapper #第一階段:找到所有文件的絕對路徑 @init def search(target): while True: filepath=yield g=os.walk(filepath) for pardir,_,files in g: for file in files: abspath=r‘%s\%s‘ %(pardir,file) target.send(abspath) #第二階段:打開文件 @init def opener(target): while True: abspath=yield with open(abspath,‘rb‘) as f: target.send((abspath,f)) #第三階段:循環讀出每一行內容 @init def cat(target): while True: abspath,f=yield #(abspath,f) for line in f: res=target.send((abspath,line)) if res:break #第四階段:過濾 @init def grep(pattern,target): tag=False while True: abspath,line=yield tag tag=False if pattern in line: target.send(abspath) tag=True #第五階段:打印該行屬於的文件名 @init def printer(): while True: abspath=yield print(abspath) g = search(opener(cat(grep(‘error‘.encode(‘utf-8‘), printer())))) g.send(r‘F:\python\s18‘)
二、 遞歸
1.遞歸調用
在調用一個函數的過程中,直接或間接地調用了函數本身,我們稱為遞歸的調用。
(1)直接調用
#!/usr/binl/env python #encoding: utf-8 #author: YangLei def func(): print(‘the is func‘) func() func()
(2)間接調用
#!/usr/binl/env python #encoding: utf-8 #author: YangLei def foo(): print(‘the is foo‘) bar() def bar(): print(‘the is bar‘) foo() foo()
2.遞歸的執行
遞歸的執行分為兩個階段遞推和回溯。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei def age(n): if n == 1: return 18 return age(n-1)+2 print(age(5))
三、 二分法
算法:當數據量很大適宜采用該方法。采用二分法查找時,數據需是排好序的。主要思想是:(設查找的數組區間為array[low, high])。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei l = [1,2,5,7,10,31,44,47,56,99,102,130,240] def binary_search(l,num): print(l) if len(l) > 1: mid_index=len(l)//2 if num > l[mid_index]: #in the right l=l[mid_index:] binary_search(l,num) elif num < l[mid_index]: #in the left l=l[:mid_index] binary_search(l,num) else: print(‘find it‘) else: if l[0] == num: print(‘find it‘) else: print(‘not exist‘) return binary_search(l,31)
四、import語句
1.執行源文件。
2.以一個源文件的全局名稱空間。
3.在當前位置拿到一個模塊名,指向2創建的名稱空間。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei print(‘from the spam.py‘) money=0 x=1 def read1(): print(‘spam->read1->money‘,money) def read2(): print(‘spam->read2 calling read‘) read1() def change(): global money money=0
#!/usr/binl/env python #encoding: utf-8 #author: YangLei import spam money=100000000000 def read1(): print(‘from test‘) print(spam.money) print(spam.read1) spam.read1() spam.read2() spam.change() print(money) spam.read1() import spam as s1 print(s1.money)
五、from...import語句
優點:使用源文件內的名字時無需加前綴,使用方便。
缺點:容易與當前文件的名稱空間內的名字混淆。
#!/usr/binl/env python #encoding: utf-8 #author: YangLei print(‘from the spam.py‘) money=0 x=1 def read1(): print(‘spam->read1->money‘,money) def read2(): print(‘spam->read2 calling read‘) read1() def change(): global money money=0
#!/usr/binl/env python #encoding: utf-8 #author: YangLei from spam import money,read1,read2,change money=0 print(money) print(read1) read1() def read1():print(‘ok‘) read2() money=10 change() print(money) from spam import money as m print(m)
六、模塊搜索路徑
註意:自定義的模塊名一定不要與python自帶的模塊名重名
內存中---> 內置模塊---> sys.path
#!/usr/binl/env python #encoding: utf-8 #author: YangLei print(‘from the spam.py‘) money=0 x=1 def read1(): print(‘spam->read1->money‘,money) def read2(): print(‘spam->read2 calling read‘) read1() def change(): global money money=0
#!/usr/binl/env python #encoding: utf-8 #author: YangLei import time import importlib import spam time.sleep(20) import spam print(spam.money) importlib.reload(spam) print(spam.money) import sys print(‘time‘ in sys.modules) import time print(‘time‘ in sys.modules)
當spam在別的路徑時
#!/usr/binl/env python #encoding: utf-8 #author: YangLei import sys # print(sys.path) sys.path.insert(0,r‘F:\python\s18\day5\test‘) import spam
七、包的導入
(1)無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的導入語法
(2)包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是一個包含__init__.py文件的目錄)
(3)import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字同樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
1.絕對導入
#!/usr/binl/env python #encoding: utf-8 #author: YangLei import sys print(sys.path) sys.path.append(r‘F:\python\s18\day5‘) import aaa print(aaa) print(aaa.x) print(aaa.y) aaa.m1.func1() aaa.bbb.m3.func3() aaa.func1() aaa.func2() aaa.func3() import aaa.bbb.m3 as abm abm.func3()
2.相對導入
#!/usr/binl/env python #encoding: utf-8 #author: YangLei import sys sys.path.append(r‘C:\Users\Administrator\PycharmProjects\python18期周末班\day5\a‘) import glance_v1 glance_v1.get() glance_v1.create_resource(‘test.conf‘) glance_v1.main() glance_v1.register_models(‘mysql‘)
八、軟件開發規範
以項目來命名,項目文件夾中要包含bin文件夾、conf文件夾、core文件夾、db文件夾、lib文件夾、log文件夾和readme。
九、logging模塊的使用
1.使用方法
(1)如果不指定filename,則默認打印到終端
(2)指定日誌級別:
指定方式:
1:level=10
2:level=logging.ERROR
日誌級別種類:
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
(3)指定日誌級別為ERROR,則只有ERROR及其以上級別的日誌會被打印
logging.basicConfig(filename=‘access.log‘, format=‘%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s‘, datefmt=‘%Y-%m-%d %H:%M:%S %p‘, level=10) logging.debug(‘debug‘) logging.info(‘info‘) logging.warning(‘warning‘) logging.error(‘error‘) logging.critical(‘critical‘) logging.log(10,‘log‘)
2.自定義logging
""" 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 = 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() logging配置文件
第五篇:python基礎_5