圖片
圖片
裝飾器
Python的裝飾器是面試常被問到的問題之一,如果你的簡歷裡描述會Python.那麼大概率會被問到.
那麼我們應該怎麼回答這個問題呢?
這裡我從幾個角度來解釋裝飾器的作用,大家可以挑選符合自己的說法
1.python裝飾器原理基礎
Python中的裝飾器,本質上就是一個高階函數,這裡高階函數指定就是"一個返回值是函數的函數"
2.裝飾器的語法
在python中使用裝飾器,有兩個組成部分.
①@符號調用裝飾器
②定義被裝飾的方法
范例如下:
@裝飾器名字
定義被裝飾的函數
@logger
def func():
pass
3.一般用來做什麼?
裝飾器可以在不修改函數的情況下,增加額外的功能.這是官方給裝飾器的定義
實際上我們會把一些業務功能之外的,附屬需求用裝飾器來實現.比如:為我們的函數添加日志記錄,性能監控器,埋點計數器.大家也都知道,修改寫好的函數是非常麻煩並且容易出錯的一件事.所以很適合"在不修改函數內部代碼的前提下,為它包裝一些額外的功能"也就是裝飾器
4.常用的裝飾器
staticmethod 用來修飾類中的方法,使得該方法可以直接用類名訪問,如cls.foo()。
classmethod 和staticmehod類似,區別在於staticmethod,classmethod會將class傳入被修飾的方法中
class A(object):
a = 1
def init(self):
self.a = 2
@staticmethod
def foo1():
print A.a
@classmethod
def foo2(cls):
print "class a is", cls.a
print "instance a is", cls().a
property 可以將屬性的訪問和賦值用函數來實現,從而可以在函數裡添加參數檢查等一些功能,同時外部使用時訪問和賦值的方式並不發生變化。注意訪問和賦值的方法名是一樣的
class A(object):
def init(self):
self.__count = 0
@property
def count(self):
return self.__count
@count.setter
def count(self, value):
if not isinstance(value, int):
raise ValueError('count must be an integer!')
self.__count = value
a = A()
print a.count
a.count = 1
print a.count
a.count = “a” # raise ValueError
functools.wraps 用在裝飾器的代碼裡。可以把原始函數的name等屬性復制到wrapper()函數中,這樣就可以獲取到真實函數的name屬性,而不是wrapper
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print ‘%s %s():’ % (text, func.name)
return func(*args, **kw)
return wrapper
return decorator
5.怎麼手寫一個裝飾器
#!/anaconda3/envs/FEALPy/bin python3.7
def logger(func):#在python裡,一切都是對象
def wrapper(*args,**kw):
print(“進入裝飾器函數了”)
func(*args,**kw)#真正的函數在裝飾器重新調用
func(*args, **kw)
print("裝飾器功能執行完畢")
return wrapper
@logger#=logger(add)
def add(x,y):
print(‘進入被修飾的函數’)
print(f’{x}+{y}={x+y}')
def say_hello(contry):
def wrapper(func):
def second(*args,**kw):
if contry == ‘china’:
print(“來自裝飾器的‘你好’”)
elif contry == ‘america’:
print(‘來自裝飾器的"hello"’)
else:
return
func(*args,**kw)
return second
return wrapper
@say_hello(‘america’)
def american():
print(“I am from America”)
@say_hello(‘china’)
def china():
print(‘我來自中國’)
american()
print(‘*’*30)
china()