Python裝飾器、內置函數之金蘭契友

裝飾器:裝飾器的實質就是一個閉包,而閉包又是嵌套函數的一種。因此也能夠理解裝飾器是一種特殊的函數。
由於程序通常都遵照開放封閉原則,軟件在設計初期不可能把全部狀況都想到,因此通常軟件都支持功能上的擴展,而對源代碼的修改是封閉的。
開放封閉原則主要體如今兩個方面:程序員

  • 對功能擴展開放:意味着有新的需求或變化時,能夠對現有代碼進行擴展,以適應新的狀況。
  • 對源碼修改封閉:意味着類一旦設計完成,就能夠獨立完成其工做,而不要對源碼進行任何修改。

對於上述的開放封閉原則有的時候確實很難完成,幸虧裝飾器能夠知足放封閉的原則。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
相關文章
相關標籤/搜索