裝飾器:裝飾器的實質就是一個閉包,而閉包又是嵌套函數的一種。因此也能夠理解裝飾器是一種特殊的函數。
由於程序通常都遵照開放封閉原則,軟件在設計初期不可能把全部狀況都想到,因此通常軟件都支持功能上的擴展,而對源代碼的修改是封閉的。
開放封閉原則主要體如今兩個方面:程序員
對於上述的開放封閉原則有的時候確實很難完成,幸虧裝飾器能夠知足放封閉的原則。express
首先咱們來看下什麼是裝飾器?緩存
def fun(function): # 參數是接收裝飾的函數 def decorator(*args,**kwargs): # 裝飾器 ret = function(*args,**kwargs) # 接收最大數 print(f"最大的數是:{ret}") # 將最大數打印出來 print(decorator) # 查看裝飾器與函數的區別 return decorator # 假如num_max(num1,num2):是咱們的源碼,源碼只是返回最大數。 # 如今有個需求讓咱們在不修改num_max(num1,num2)源碼的狀況下 # 以調用num_max(num1,num2)的方式將最大數打印出來 def num_max(num1,num2): if num1 > num2: return num1 else: return num2 num_max = fun(num_max) # 裝飾函數num_max(num1,num2) num_max(3,5) # 以正常 的方式調用函數 # 打印結果: <function fun.<locals>.decorator at 0x00000000021F47B8> 最大的數是:5
Python爲咱們裝飾函數的時候,提供了一個簡便的方法語法糖@,能夠直接裝飾一個函數,仍是以上面的例子演示:閉包
def fun(function): # 參數是接收裝飾的函數 def decorator(*args,**kwargs): # 裝飾器 ret = function(*args,**kwargs) # 接收最大數 print(f"最大的數是:{ret}") # 將最大數打印出來 print(decorator) # 查看裝飾器與函數的區別 return decorator
# 假如num_max(num1,num2):是咱們的源碼,源碼只是返回最大數。 # 如今有個需求讓咱們在不修改num_max(num1,num2)源碼的狀況下 # 以調用num_max(num1,num2)的方式將最大數打印出來 @fun # 語法糖 def num_max(num1,num2): if num1 > num2: return num1 else: return num2 num_max(3,5) # 以正常 的方式調用函數 # 打印結果 最大的數是5
使用語法糖要注意,就是要裝飾哪一個函數,必定要將語法糖放在哪一個函數的正上方。裝飾器通常用於插入日誌,驗證碼,性能測試,事務處理,緩存等等場景。app
固然上面的例子只是爲了演示裝飾器的用法,下面咱們來演示一個計算fun循環和while循環的例子:ssh
import time def fun(function): # 參數是接收裝飾的函數 def decorator(): # 裝飾器 start_time = time.time() function() end_time = time.time() return (end_time - start_time) return decorator @fun # 語法糖 def for_fun(): for i in range(10000000): i += 1 ret = for_fun() print(f"for循環用了:{ret}") @fun # 語法糖 def while_fun(): count = 0 while count < 10000000: count += 1 ret = while_fun() print(f"while循環用了:{ret}") # 打印內容以下 for循環用了:0.7150406837463379 while循環用了:0.7400426864624023
上面的作法彷佛還差點什麼,就是當咱們執行'函數名.__doc__'或'函數名.__name__'時咱們會發現結果不對,這是須要用到wraps裝飾器來解決這個問題,以下:函數
from functools import wraps def inner(func): @wraps(func) #加在最內層函數正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @inner def func(): '''我是註釋''' print('from index') print(func.__doc__) print(func.__name__)
經常使用內置函數用法:
abs(x):x是一個數,函數返回一個絕對值。性能
print(abs(-9)) # 打印內容以下: 9
all(iterable):參數,可迭代對象,檢查可迭代對象中的元素是否爲True,若是元素中有False、None、0、""空字符串返回False,不然返回True。測試
print(all([1,2,"a"])) print(all([1,"a",2,""])) print(all([1,"a",2,None])) print(all([1,"a",2,0])) # 打印內容以下: True False False False
any(iterable):參數是可迭代對象,若是可迭代對象是空返回False,不然返回True。spa
print(any([1,2,"",False])) print(any([])) # 打印內容以下: True False
bin(x):參數是數字,將數字轉換成二進制。
print(bin(4)) # 打印內容以下: 0b100
chr(i):參數i是一個數字,範圍是0 - 1,114,111轉換成Unicode碼
print(chr(97)) # 打印內容以下: a
oct(x):x是一個數字,返回這個數字的八進制。
hex(x):x是一個數字,返回這個數字的十六進制。
ord(c):返回一個字符的Unicode對應的數字。
delattr(object, name):參數object是一個對象,name是對象的屬性,功能刪除對象的屬性。
class A: def __init__(self,name): self.name = name obj = A("小明") print(obj.__dict__) # 打印對象全部屬性 delattr(obj, 'name') # 刪除對象屬性 print(obj.__dict__) # 打印對象全部屬性 # 打印內容以下: {'name': '小明'} {}
divmod(a,b):參數a是一個數字,參數b是一個數字,計算a除b返回(商和餘數)。
print(divmod(11,3)) #打印內容以下: (3, 2)
eval(expression, globals=None, locals=None):實際項目中最好不要用,由於它能夠將表達式的參數解析成Python語句執行,這樣用戶就能夠經過eveal()來對咱們的程序進行一些不可預知的操做。
expression:表達式
globals -- 變量做用域,全局命名空間,若是被提供,則必須是一個字典對象。
locals -- 變量做用域,局部命名空間,若是被提供,能夠是任何映射對象。
下面假設咱們代碼中引入了os模塊,經過eval演示咱們不想看到的結果.以下:
import os eval("os.system('cmd.exe')")
執行完成後咱們會看到以下界面,雖然中文是亂碼,但咱們也能看出這是執行了咱們傳入的cmd命令,程序已經爲咱們打開cmd窗口並等待輸入,要知道這絕對不是咱們想要的。
在例如咱們有個函數fun(),用戶無心間恰巧輸入了fun(),咱們會看到以下效果:
# 假設這是咱們源碼中的函數 def fun(): print("我是fun") # 用戶無心間輸入了"fun()"並傳給了eval eval("fun()") # 打印結果以下 我是fun
咱們能夠發現函數fun()被執行了,我相信每一個程序員都不但願用戶能夠這樣隨意的操縱咱們的程序。
雖然eval有不少弊端,但它有時也有點用。咱們知道任何數據類型都不能夠強轉成字典的。可是eval能夠作到,哈哈。
dict_1 = {"a":1,"b":2} str_1 = str(eval("dict_1")) # 將字典轉換成字符串 dict_2 = dict(eval(str_1)) # 將字符串轉換成字典 print(str_1,type(str_1)) print(dict_2,type(dict_2)) # 打印內容以下: {'a': 1, 'b': 2} <class 'str'> {'a': 1, 'b': 2} <class 'dict'>
若是一個程序只是爲了給本身測試用,那麼能夠考慮使用eval由於有的時候它仍是頗有用的。但若是是實際上線產品是禁止使用eval的,由於有的時候它雖然頗有用,可是它的弊端是大於它的利端的。
exec(object,globals,locals):這個也是個神奇的傢伙,與eval相似能夠動態執行Python代碼,實際開發中也是禁止使用的。
以下:我就很少說了由於它和eval差很少。總能給咱們意想不到的驚喜。
import os exec("os.popen('calc')") # 打開系統自帶的計算器
下面還能夠執行for循環。
exec("for i in range(5):print(i,end=\" \")") # 打印內容 0 1 2 3 4
要知道exec在咱們實際開發中是禁止使用的。切記,切記,切記
help(object):返回對象的幫助頁面。
help(print) # 打印內容以下: print(...) print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream. print(self, *args, sep=' ', end='\n', file=None)
print(self, *args, sep=' ', end='\n', file=None):
*args:用戶傳入的參數。
sep:當用戶輸入多個用逗號","分隔的參數時,默認sep是空格分開每一個值,能夠指定sep="_"等其它符號來對值進行分隔。例如:
print("Hello","World","!!!",sep="_|_") # 打印內容以下: Hello_|_World_|_!!!
end:用於指定每一個print結尾,默認是換行符,也就是每一個print佔一行能夠指定參數讓print不進行換行,以下:
print("Hello","World","!!!",sep="_|_",end="****") print("無語呀") # 打印內容以下: Hello_|_World_|_!!!****無語呀
最終實現了兩個print在一行上。
hash(對象):獲取對象的hash值。
id(對象):獲取對象內存地址。
round(*args, **kwargs): *args:是一個小數 **kwargs:用於控制小數的位數,若是不填寫默認只顯示整數。
print(round(1.2345)) print(round(1.2345,2)) # 打印結果以下 1 1.23
pow(a,b) :求a的b次冪,若是有個三次參數,則求完次冪後對第三方個數取餘。
sum() :求和。
max() :求最大值。
enumerate() :獲取枚舉對象,並列出下標。
list_ = [1,2,3] for i,k in enumerate(list_): print(i,k,end=" ") print("\n") for i in enumerate(list_): print(i,end=" ") # 打印結果以下 0 1 1 2 2 3 (0, 1) (1, 2) (2, 3)
dir(object) :若是沒有參數,則返回當前局部做用域中的名稱列表。使用參數,嘗試返回該對象的有效屬性列表。
list_ = [1,2,3] print(dir(list_)) print(dir(input)) # 打印內容以下: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']
callable() :用於檢查一個對象是不是可調用的,若是返回True,object有可能調用失敗,要是返回False調用失敗。
def num_sum(a,b): return a+b print(num_sum(1,2)) print(callable(num_sum)) # 打印內容以下: 3 True
zip(): 函數用於將可迭代的對象做爲參數,將多個對象中對應的元素打包成一個元祖,而後返回由這些元祖組成的內容,若是各個迭代器的元素個數不一致,則按照長度最短的返回。
list_ = [1,2,3] list_1 = ["a","b","c"] list_2 = ["1","2","3"] print(list(zip(list_,list_1,list_2))) # 打印內容以下: [(1, 'a', '1'), (2, 'b', '2'), (3, 'c', '3')]
lambda匿名函數:
變量名 = lambda 參數:返回值
一、函數的參數能夠有多個,多個參數之間用逗號隔開。
二、匿名函數無論多複雜,只能寫一行,且邏輯結束後直接返回數據。
三、返回值和正常的函數同樣,能夠是任意數據類型,可是隻能一個,不能返回多個。
匿名函數並非說必定沒有名字,這裏前面的變量就是一個函數名,說他是匿名緣由是咱們經過name查看的時候是沒有名字的,統一都叫作lambda,在調用的時候沒有什麼特別之處像正常的函數調用既可。
關於lambda的簡單示例:
# 示例1合併列表 x=(1,3,5) y=(0,2,4) list_1 = list(map(lambda x,y:(x,y),y,x)) print(list_1) # 打印內ring以下: [(0, 1), (2, 3), (4, 5)] # 示例2 對列表進行排序 list_1 = [(1,2),(3,5),(8,4),(6,1)] print(sorted(list_1,key=lambda x:x[1])) print(list_1) # 打印內容以下 [(6, 1), (1, 2), (8, 4), (3, 5)] [(1, 2), (3, 5), (8, 4), (6, 1)]
sorted排序函數
語法:sorted(iterable,key=None,reverse=False)
iterable:可迭代對象。
key:排序規則(函數),在sorted內部會將可迭代對象中的每個元素傳遞給這個函數做爲參數,根據函數運算的結果進行排序。
reverse:是不是倒序,True 倒敘 False 正序。
# 示例1 array = [{"age":20,"name":"a"},{"age":25,"name":"b"},{"age":10,"name":"c"}] print(sorted(array,key=lambda k:k["age"])) # 默認是升序排序 # 打印內容以下: [{'age': 10, 'name': 'c'}, {'age': 20, 'name': 'a'}, {'age': 25, 'name': 'b'}] # 示例2 array = [{"age":20,"name":"a"},{"age":25,"name":"b"},{"age":10,"name":"c"}] print(sorted(array,key=lambda k:k["age"]*-1)) # 在值後面*-1和reverse=True相似倒敘排列 # 打印內容以下: [{'age': 25, 'name': 'b'}, {'age': 20, 'name': 'a'}, {'age': 10, 'name': 'c'}] # 示例3 list_1 = [(1,2),(3,5),(8,4),(6,1)] print(sorted(list_1,key=lambda x:x[1],reverse=True)) print(list_1) # 打印內容以下 [(3, 5), (8, 4), (1, 2), (6, 1)] [(1, 2), (3, 5), (8, 4), (6, 1)]
篩選過濾
語法:filter(function,iterable)
function:用來篩選的函數,在filter中會自動的把iterable中的元素傳遞給function,而後根據function返回的True或者False來判斷是否保留此項數據。
iterable:可迭代對象。
array = [{"age":20,"name":"a"},{"age":25,"name":"b"},{"age":10,"name":"c"}] # 過濾掉年齡小於10的 print(list(filter(lambda k:k["age"]>10,array))) # 打印內容以下: [{'age': 20, 'name': 'a'}, {'age': 25, 'name': 'b'}]
映射函數
語法:map(function,iterable) 能夠對可迭代對象中的每個元素進映射,分別取執行function。
計算列表中每一個元素的平方,返回新列表。
list_1 = [1,2,3,4,5] print(list(map(lambda x:x**2,list_1))) # 打印內容以下 [1, 4, 9, 16, 25]
簡單示例
# 示例1 lst = [10,2,30,4,5,6,70,8,9] print(list(map(lambda x:x>10,lst))) # 若是是條件表達式則返回的是 # True或者是Fales # 打印內容以下: [False, False, True, False, False, False, True, False, False] # 示例2 lst1 = list(range(0,6,2)) lst2 = list(range(1,6,2)) print(list(map(lambda x,y:(x,y),lst1,lst2))) # 打印內容以下: [(0, 1), (2, 3), (4, 5)]
reduce(function, iterable[, initializer) 函數會對參數序列中元素進行累積。
函數將一個數據集合(鏈表,元組等)中的全部數據進行下列操做:用傳給 reduce 中的函數 function(有兩個參數)
先對集合中的第 一、2 個元素進行操做,獲得的結果再與第三個數據用 function 函數運算,最後獲得一個結果。
function:函數,有兩個參數
iterable :可迭代對象
initializer : 可選,初始參數
在Python2.x版本中recude是直接 import就能夠的, Python3.x版本中須要從functools這個包中導入。
龜叔本打算將 lambda 和 reduce 都從全局名字空間都移除, 輿論說龜叔不喜歡lambda 和 reduce
最後lambda沒刪除是由於和一我的寫信寫了好多封,進行交流而後把lambda保住了。
# 示例1 from functools import reduce list_1 = [1,2,3,4,5] print(reduce(lambda x,y:x+y,list_1)) # 打印內容以下 15 # 示例2 str_1 = "abcabbcacda" word_count =reduce(lambda a,x:a+x.count("a"),str_1,0) print(word_count) # 打印內容以下 4