Android在佈局XML中的空格轉義符(佔位符)
阿新 • • 發佈:2022-12-04
1.裝飾器簡介
python的裝飾器本質上是一個Python函式,它可以讓其他函式在不需要做任何程式碼變動的前提下增加額外功能,裝飾器的返回值也是一個函式物件。 簡單的說裝飾器就是一個用來返回函式的函式。 它經常用於有切面需求的場景,比如:插入日誌、效能測試、事務處理、快取、許可權校驗等場景。裝飾器是解決這類問題的絕佳設計, 有了裝飾器,我們就可以抽離出大量與函式功能本身無關的雷同程式碼並繼續重用。 概括的講,裝飾器的作用就是為已經存在的物件新增額外的功能。 認識裝飾器之前,需要明確的事情: # 裝飾器在不改變函式內部的基礎上,可以統一新增某些功能,讓函式在執行之前或之後做一些操作 # 定義完函式未呼叫,函式內部不執行 # 函式名(不加括號),代指函式整體;加括號:執行函式 # 函式名可以當作引數傳遞 # 只要函式用上裝飾器,那麼函式就會被重新定義為裝飾器的內層函式
2.為什麼使用裝飾器
首先有個函式: 1 def foo(): 2 print('i am foo') 現在希望記錄函式執行的日誌,可以寫成下面這樣: 1 def foo(): 2 print('i am foo') 3 print("foo is running") 那麼如果有100個函式都要增加記錄日誌的需求呢? 這樣我們可以寫一個專門的函式,讓它幹記錄日誌的活: 複製程式碼 複製程式碼 # 專門記錄日誌的函式 def use_logging(func): print("%s is running" % func.__name__) func() # 原函式 def bar(): print('i am bar') # 使用,把原函式當作引數傳給use_logging use_logging(bar) # 結果如下 bar is running i am bar
3.裝飾器的使用
3-1 裝飾器語法
# python提供了@符號作為裝飾器的語法糖,使我們更方便的應用裝飾函式。但使用語法糖要求裝飾函式必須return一個函式物件。 # 只要函式用上裝飾器,那麼會發生以下事情: # 原函式就會被重新定義為裝飾器的內層函式 # 哪個函式呼叫了裝飾器,就會將哪個函式的函式名當作引數傳給裝飾器函式 # 將裝飾器函式的返回值,重新賦值給原函式 def use_logging(func): # 這裡的func就是bar # 這裡的inner函式,就是bar函式 def inner(): print("{} is running!".format(func.__name__)) # 新增加的功能 return func() # func就是bar,因為裝飾器不能改變原函式,所以還要返回一個老的bar的值 return inner # 返回包裝過的函式,這裡的inner也就是bar,這裡先沒有帶(),在最後執行bar時(也就是執行inner)才帶上() @use_logging #含義:use_logging(bar) def bar(): # 函式bar呼叫了裝飾器,會將bar當引數傳給use_logging print("i am bar") bar()
3-2 帶引數的函式使用裝飾器
def use_logging(func):
def inner(a, b):
print("{} is running!".format(func.__name__))
return func(a, b)
return inner
@use_logging
def bar(a, b):
print("The sum of a and b is {}".format(a+b))
bar(1, 2)
# 我們裝飾的函式可能引數的個數和型別都不一樣,每一次我們都需要對裝飾器做修改嗎?
# 這樣做當然是不科學的,因此我們使用python的變長引數*args和**kwargs來解決我們的引數問題。
# 這樣就可以適應帶引數的函數了
def use_logging(func):
def inner(*args, **kwargs):
print("{} is running!".format(func.__name__))
return func(*args, **kwargs)
return inner
@use_logging
def bar(a, b):
print("The sum of a and b is {}".format(a+b))
bar(1, 2)
3-3 帶引數的裝飾器
# 某些情況我們需要讓裝飾器帶上引數,那就需要編寫一個返回一個裝飾器的高階函式,比較複雜
def use_logging(level):
def inner1(func): # 這裡的func是bar
def inner2(*args, **kwargs):
if level == "warn":
print("{} is running!".format(func.__name__))
return func(*args, **kwargs)
return inner2
return inner1
@use_logging(level="warn")
def bar(a, b):
print("The sum of a and b is {}".format(a+b))
bar(1, 2)
3-4 functools.wraps
def use_logging(func):
def inner(*args, **kwargs):
print("%s is running" % func.__name__)
func(*args, **kwargs)
return inner
@use_logging
def bar():
print('i am bar')
print(bar.__name__) # 結果成了:inner
bar()
# 結果:
bar is running
i am bar
inner
#函式名變為inner而不是bar,這個情況在使用反射的特性的時候就會造成問題。因此引入functools.wraps解決這個問題。
from functools import wraps # 導包
def use_logging(func):
@wraps(func)
def inner(*args, **kwargs):
print("%s is running" % func.__name__)
func(*args, **kwargs)
return inner
@use_logging
def bar():
print('i am bar')
print(bar.__name__) # OK了,結果是bar
bar()
# 結果
bar is running
i am bar
bar
3-5 雙層裝飾器
# 雙層裝飾器,執行順序是從上往下執行(outer1-->outer2); 呼叫(解釋)順序是先outer2再outer1
# 返回順序也是outer1-->outer2
def outer1(func):
def inner(*arg, **kwargs):
print("outer1")
return func(*arg, **kwargs)
return inner
def outer2(func):
def inner(*arg, **kwargs):
print("outer2")
return func(*arg, **kwargs)
return inner
@outer1
@outer2
def a1():
print("a1")
a1()
# 結果
outer1
outer2
a1
4.類裝飾器
from functools import wraps
class loging(object):
def __init__(self, level="warn"):
self.level = level
def __call__(self, func):
@wraps(func)
def inner(*args, **kwargs):
if self.level == "warn":
self.notify(func)
return func(*args, **kwargs)
return inner
def notify(self, func): # 列印日誌的函式
print("{} is running".format(func.__name__))
@loging(level="warn") # 執行__call__方法
def bar(a, b):
print("The sum of a and b is {}".format(a+b))
bar(1, 2)