[python 進階] 第7章 函數裝飾器和閉包

文章目錄

    • 7.1 裝飾器基礎知識
    • 7.2 Python何時執行裝飾器
    • 7.3 使用裝飾器改進“策略”
    • 7.4 變量作用域(global)
    • 備注 -比較字節碼(暫略)
    • 7.5 閉包
    • 7.6 nonlocal聲明
    • global和nonlocal的區別
    • 7.7 實現一個簡單的裝飾器
    • 7.8 標準庫中的裝飾器
      • 7.8.1 使用functools.lru_cache做備忘
      • 補充 @functools.lru_cache()可以配置參數
      • 7.8.2 單分派泛函數( @functools.singledispatch)
    • 7.9 疊放裝飾器
    • 7.10 參數化裝飾器
      • 7.10.1 一個參數化的注冊裝飾器
      • 7.10.2 參數化clock裝飾器

函數裝飾器用于在源碼中“標記”函數,以某種方式增強函數的行為。這是一項強大的功能,但是若想掌握,必須理解閉包。
nonlocal 是新近出現的保留關鍵字,在 Python 3.0 中引入。
除了在裝飾器中有用處之外,閉包還是 回調式異步編程函數式編程風格的基礎。
本章的最終目標是解釋清楚函數裝飾器的工作原理,包括最簡單的 注冊裝飾器和較復雜的 參數化裝飾器。但是,在實現這一目標之前,我們要討論下述話題:

  • Python 如何計算裝飾器句法
  • Python 如何判斷變量是不是局部的
  • 閉包存在的原因和工作原理
  • nonlocal 能解決什么問題
    掌握這些基礎知識后,我們可以進一步探討裝飾器:
  • 實現行為良好的裝飾器
  • 標準庫中有用的裝飾器
  • 實現一個參數化裝飾器

7.1 裝飾器基礎知識

裝飾器是可調用的對象,其參數是另一個函數(被裝飾的函數)。 裝飾器可能會處理被裝飾的函數,然后把它返回,或者將其替換成另一個函數或可調用對象。
假如有個名為 decorate 的裝飾器:

@decorate
def target():
print('running target()')

上述代碼的效果與下述寫法一樣:

def target():
print('running target()')
target = decorate(target)

兩種寫法的最終結果一樣:上述兩個代碼片段執行完畢后得到的 target 不一定是原來那
個 target 函數,而是 decorate(target) 返回的函數。

為了確認被裝飾的函數會被替換,請看示例 7-1 中的控制臺會話。
示例 7-1 裝飾器通常把函數替換成另一個函數

>>> def deco(func):
... def inner():
... print('running inner()')
... return inner 
...
>>> @deco
... def target(): 
... print('running target()')
...
>>> target() 
running inner()
>>> target 
<function deco.<locals>.inner at 0x10063b598>

嚴格來說,裝飾器只是語法糖。如前所示,裝飾器可以像常規的可調用對象那樣調用,其
參數是另一個函數。有時,這樣做更方便,尤其是做元編程(在運行時改變程序的行
為)時。
綜上,裝飾器的一大特性是,能把被裝飾的函數替換成其他函數。第二個特性是,裝飾器
在加載模塊時立即執行。

7.2 Python何時執行裝飾器

裝飾器的一個關鍵特性是,它們在被裝飾的函數定義之后立即運行。這通常是在導入時
(即 Python 加載模塊時)

registry = []
def register(func):print('running register(%s)' % func)registry.append(func)return func
@register
def f1():print('running f1()')
@register
def f2():print('running f2()')
def f3():print('running f3()')
def main():print('running main()')print('registry ->', registry)  # 發現registry這個數組并不是空f1()f2()f3()
if __name__=='__main__':main()

輸出后是什么樣子呢?

running register(<function f1 at 0x7ff079e400d0>)
running register(<function f2 at 0x7ff06c9e37b8>)
running main()
registry -> [<function f1 at 0x7ff079e400d0>, <function f2 at 0x7ff06c9e37b8>]
running f1()
running f2()
running f3()

注意:在調用f1()和f2()時,輸出的是 runnint f1()和running f2()。
上面的例子主要是強調:函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時運行。這突出了 Python 程序員所說的導入時和運行時之間的區別。
考慮到裝飾器在真實代碼中的常用方式,示例 7-2 有兩個不尋常的地方。裝飾器函數與被裝飾的函數在同一個模塊中定義。實際情況是,裝飾器通常在一個模塊中定義,然后應用到其他模塊中的函數上。
register 裝飾器返回的函數與通過參數傳入的相同。實際上,大多數裝飾器會在內部定義一個函數,然后將其返回。

雖然上示例中的 register 裝飾器原封不動地返回被裝飾的函數,但是這種技術并非沒有用處。很多 Python Web 框架使用這樣的裝飾器把函數添加到某種中央注冊處,例如把URL模式映射到生成 HTTP 響應的函數上的注冊處。這種注冊裝飾器可能會也可能不會修改被裝飾的函數。

7.3 使用裝飾器改進“策略”

使用注冊裝飾器可以改進之前的第六章中的電商促銷折扣示例。
回顧一下,示例 6-6 的主要問題是,定義體中有函數的名稱,但是 best_promo 用來判斷哪個折扣幅度最大的 promos 列表中也有函數名稱。這種重復是個問題,因為新增策略函數后可能會忘記把它添加到 promos 列表中,導致 best_promo 忽略新策略,而且不報錯,為系統引入了不易察覺的缺陷。以下這個例子使用注冊裝飾器解決了這個問題。

  • promos 列表中的值使用 promotion 裝飾器

      from collections import namedtupleCustomer = namedtuple('Customer', 'name fidelity')class LineItem:def __init__(self, product, quantity, price):self.product = productself.quantity = quantityself.price = pricedef total(self):return self.price * self.quantitypromos =[]def promotion(promo_func):promos.append(promo_func)return promo_func@promotiondef fidelity(order):"""為積分為1000或者以上的顧客提供5%折扣"""return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0@promotiondef bulk_item(order):"""單個商品為20個或者以上時提供10%折扣"""discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() * 0.01return discount@promotiondef large_order(order):"""訂單中的不同商品達到10個以上時提供7%折扣"""distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * 0.07return 0def best_promo(order):"""選擇可用的最佳折扣"""return max(promo(order) for promo in promos)class Order: #上下文def __init__(self, customer, cart, promotion=None):self.customer = customerself.cart = list(cart)self.promotion = promotiondef total(self):if not hasattr(self, '__total'):self.__total = sum(item.total() for item in self.cart)return self.__totaldef due(self):if self.promotion is None:discount = 0else:discount = self.promotion(self)return self.total() - discountdef __repr__(self):fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(), self.due())if __name__ == '__main__':joe = Customer('John Doe', 0)ann = Customer('Ann Smith', 1000)cart = [LineItem('banana', 4, 0.5),LineItem('apple', 10, 1.5),LineItem('watermellon', 5, 5.0)]print(Order(joe, cart, fidelity))   # <Order total: 42.00 due: 42.00>print(Order(ann, cart, fidelity))   #<Order total: 42.00 due: 39.90>
    

與 6.1 節給出的方案相比,這個方案有幾個優點。

  • 促銷策略函數無需使用特殊的名稱(即不用以 _promo 結尾)。
  • @promotion 裝飾器突出了被裝飾的函數的作用,還便于臨時禁用某個促銷策略:只需把裝飾器注釋掉。
  • 促銷折扣策略可以在其他模塊中定義,在系統中的任何地方都行,只要使用@promotion 裝飾即可。

不過,多數裝飾器會修改被裝飾的函數。通常,它們會定義一個內部函數,然后將其返
回,替換被裝飾的函數。使用內部函數的代碼幾乎都要靠閉包才能正確運作。

7.4 變量作用域(global)

在示例 7-4 中,我們定義并測試了一個函數,它讀取兩個變量的值:一個是局部變量 a,
是函數的參數;另一個是變量 b,這個函數沒有定義它。

示例 7-4 一個函數,讀取一個局部變量和一個全局變量

>>> def f1(a):
... print(a)
... print(b)
...
>>> f1(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f1
NameError: global name 'b' is not defined

出現錯誤并不奇怪。 在示例 7-4 中,如果先給全局變量 b 賦值,然后再調用 f,那就不
會出錯。

示例 7-5 b 是局部變量,因為在函數的定義體中給它賦值了

>>> b = 6
>>> def f2(a):
... print(a)
... print(b)
... b = 9
...
>>> f2(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f2
UnboundLocalError: local variable 'b' referenced before assignment

注意,首先輸出了 3,這表明 print(a) 語句執行了。但是第二個語句 print(b) 執行不了。一開始我很吃驚,我覺得會打印 6,因為有個全局變量 b,而且是在 print(b) 之后為局部變量 b 賦值的。
可事實是,Python 編譯函數的定義體時,它判斷 b 是局部變量,因為在函數中給它賦值了。生成的字節碼證實了這種判斷,Python 會嘗試從本地環境獲取 b。后面調用 f2(3)時, f2 的定義體會獲取并打印局部變量 a 的值,但是嘗試獲取局部變量 b 的值時,發現b 沒有綁定值。
這不是缺陷,而是設計選擇:Python 不要求聲明變量,但是假定在函數定義體中賦值的變量是局部變量。這比 JavaScript 的行為好多了,JavaScript 也不要求聲明變量,但是如果忘記把變量聲明為局部變量(使用 var),可能會在不知情的情況下獲取全局變量。
如果在函數中賦值時想讓解釋器把 b 當成全局變量,要使用 global 聲明:

>>> b = 6
>>> def f3(a):
... global b
... print(a)
... print(b)
... b = 9
...
>>> f3(3)
3
6
>>> b
9
>>> f3(3)
3
9
>>> b = 30
>>> b
30
>>>

了解 Python 的變量作用域之后,下一節可以討論閉包了。如果好奇示例 7-4 和示例 7-5 中的兩個函數生成的字節碼有什么區別,可以下面的備注:

備注 -比較字節碼(暫略)

7.5 閉包

在博客圈,人們有時會把閉包和匿名函數弄混。這是有歷史原因的:在函數內部定義函數不常見,直到開始使用匿名函數才會這樣做。而且,只有涉及嵌套函數時才有閉包問題。
因此,很多人是同時知道這兩個概念的。
其實,閉包指延伸了作用域的函數,其中包含函數定義體中引用、但是不在定義體中定義的非全局變量。函數是不是匿名的沒有關系,關鍵是它能訪問定義體之外定義的非全局變量。
這個概念難以掌握,最好通過示例理解。
假如有個名為 avg 的函數,它的作用是計算不斷增加的系列值的均值;例如,整個歷史中某個商品的平均收盤價。每天都會增加新價格,因此平均值要考慮至目前為止所有的價格。

示例 7-8 average_oo.py:計算移動平均值

class Averager():def __init__(self):self.series=[]def __call__(self, new_value):self.series.append(new_value)total = sum(self.series)return total/len(self.series)
avg=Averager()
print(avg(10)) #10.0
print(avg(11)) #10.5
print(avg(12)) #11.0

Averager 的實例是可調用對象

示例 7-9 是函數式實現,使用高階函數 make_averager。

示例 7-9 average.py:計算移動平均值的高階函數

def make_averager():series = []def averager(new_value):series.append(new_value)total = sum(series)return total/len(series)
return averager

調用 make_averager 時,返回一個 averager 函數對象。每次調用 averager 時,它會
把參數添加到系列值中,然后計算當前平均值,如示例 7-10 所示。
示例 7-10 測試示例 7-9

>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0

注意,這兩個示例有共通之處:調用 Averager() 或 make_averager() 得到一個可調用對象 avg,它會更新歷史值,然后計算當前均值。在示例 7-8 中,avg 是 Averager 的實例;在示例 7-9 中是內部函數 averager。不管怎樣,我們都只需調用 avg(n),把 n 放入系列值中,然后重新計算均值。
Averager 類的實例 avg 在哪里存儲歷史值很明顯:self.series 實例屬性。但是第二個示例中的 avg 函數在哪里尋找 series 呢?
注意,series 是 make_averager 函數的局部變量,因為那個函數的定義體中初始化了series:series = []。可是,調用 avg(10) 時,make_averager 函數已經返回了,而它的本地作用域也一去不復返了。
在 averager 函數中,series 是自由變量(free variable)。這是一個技術術語,指未在本地作用域中綁定的變量。

在這里插入圖片描述
averager 的閉包延伸到那個函數的作用域之外,包含自由變量 series 的綁定。
綜上,閉包是一種函數,它會保留定義函數時存在的自由變量的綁定,這樣調用函數時,雖然定義作用域不可用了,但是仍能使用那些綁定。
注意,只有嵌套在其他函數中的函數才可能需要處理不在全局作用域中的外部變量。

7.6 nonlocal聲明

前面實現 make_averager 函數的方法效率不高。在示例 7-9 中,我們把所有值存儲在歷史數列中,然后在每次調用 averager 時使用 sum 求和。更好的實現方式是,只存儲目前的總值和元素個數,然后使用這兩個數計算均值。
示例 7-13 中的實現有缺陷,只是為了闡明觀點。你能看出缺陷在哪兒嗎?

示例 7-13 計算移動平均值的高階函數,不保存所有歷史值,但有缺陷
def make_averager():
count = 0
total = 0def averager(new_value):count += 1total += new_valuereturn total / count
return averager

Python 3 引入了 nonlocal 聲明。它的作用是把變量標記為自由變量,即使在函數中為變量賦予新值了,也會變成自由變量。如果為 nonlocal 聲明的變量賦予新值,閉包中保存的綁定會更新。

示例 7-14 計算移動平均值,不保存所有歷史(使用 nonlocal 修正)
def make_averager():
count = 0
total = 0def averager(new_value):nonlocal count, totalcount += 1total += new_valuereturn total / count
return averager

global和nonlocal的區別

global 表示將變量聲明為全局變量
nonlocal 表示將變量聲明為外層變量(外層函數的局部變量,而且不能是全局變量)。

    1. global關鍵字用來在函數或其他局部作用域中使用全局變量。但是如果不修改全局變量也可以不使用global關鍵字。
    1. 聲明全局變量,如果在局部要對全局變量修改,需要在局部也要先聲明該全局變量。

         gcount = 0def global_test():global gcountgcount +=1print (gcount)global_test()
      
  • 3.在局部如果不聲明全局變量,并且不修改全局變量。則可以正常使用全局變量:

      			gcount = 0def global_test():print(gcount)global_test()
    
    1. nonlocal關鍵字用來在函數或其他作用域中使用外層(非全局)變量

         def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter def make_counter_test(): mc = make_counter() print(mc())print(mc())print(mc())make_counter_test()
      

7.7 實現一個簡單的裝飾器

定義了一個裝飾器,它會在每次調用被裝飾的函數時計時,然后把經過的時間、傳入的參數和調用的結果打印出來。
import time

def clock(func):def clocked(*args):t0=time.perf_counter()result = func(*args)elapsed = time.perf_counter()name = func.__name__arg_str = ','.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s)-> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@clock
def snooze(seconds):time.sleep(seconds)
@clock
def factorial(n):return 1 if n < 2 else n*factorial(n-1)
if __name__ == '__main__':print('*' * 40, 'Calling snooze(.123)')snooze(.123)print('*' * 40, 'Calling factorial(6)')print('6! =', factorial(6))

這是裝飾器的典型行為:把被裝飾的函數替換成新函數,二者接受相同的參數,而且(通常)返回被裝飾的函數本該返回的值,同時還會做些額外操作。

將上述例子改進一下:

7.8 標準庫中的裝飾器

Python 內置了三個用于裝飾方法的函數:property、classmethod 和
staticmethod。另一個常見的裝飾器是 functools.wraps,它的作用是協助構建行為良好的裝飾器。我
們在示例 7-17 中用過。標準庫中最值得關注的兩個裝飾器是 lru_cache 和全新的
singledispatch(Python 3.4 新增)。這兩個裝飾器都在 functools 模塊中定義。

7.8.1 使用functools.lru_cache做備忘

示例 7-18 生成第 n 個斐波納契數,遞歸方式非常

import timedef clock(func):def clocked(*args):print(*args)t0 = time.perf_counter()result = func(*args)elapsed = time.perf_counter()name = func.__name__arg_str = ','.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s)-> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@clock
def fibonacci(n):return n if n < 2 else fibonacci(n-2)+fibonacci(n-1)if __name__ == '__main__':print(fibonacci(6))

示例 7-19 使用緩存實現,速度

import time
import functools
def clock(func):def clocked(*args):print(*args)t0 = time.perf_counter()result = func(*args)elapsed = time.perf_counter()name = func.__name__arg_str = ','.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s)-> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@functools.lru_cache() #注意,必須像常規函數那樣調用 lru_cache。這一行中有一對括號:@functools.lru_cache()。這么做的原因是,lru_cache 可以接受配置參數
@clock
def fibonacci(n):return n if n < 2 else fibonacci(n-2)+fibonacci(n-1)if __name__ == '__main__':print(fibonacci(6))

補充 @functools.lru_cache()可以配置參數

7.8.2 單分派泛函數( @functools.singledispatch)

7.9 疊放裝飾器

示例 7-19 演示了疊放裝飾器的方式:@lru_cache 應用到 @clock 裝飾 fibonacci 得到的結果上。在示例 7-21 中,模塊中最后一個函數應用了兩個 @htmlize.register 裝飾器。
把 @d1 和 @d2 兩個裝飾器按順序應用到 f 函數上,作用相當于 f = d1(d2(f))。
也就是說,下述代碼:

@d1
@d2
def f():print('f')

等同于:

def f():print('f')f = d1(d2(f))

除了疊放裝飾器之外,本章還用到了幾個接受參數的裝飾器,

7.10 參數化裝飾器

解析源碼中的裝飾器時,Python 把被裝飾的函數作為第一個參數傳給裝飾器函數。那怎么讓裝飾器接受其他參數呢?答案是:創建一個裝飾器工廠函數,把參數傳給它,返回一個裝飾器,然后再把它應用到要裝飾的函數上。

registry = []
def register(func):print('running register(%s)' % func)registry.append(func)return func
@register
def f1():print('running f1()')
print('running main')
print('registry ->',registry)
f1()

7.10.1 一個參數化的注冊裝飾器

為了便于啟用或禁用 register 執行的函數注冊功能,我們為它提供一個可選的 active參數,設為 False 時,不注冊被裝飾的函數。實現方式參見下面這個例子。從概念上看,這個新的 register 函數不是裝飾器,而是裝飾器工廠函數。調用它會返回真正的裝飾器,這才是應用到目標函數上的裝飾器。

registry = []
def register(active=True):def decorate(func):print('running register(active=%s)->decorate(%s)'%(active, func))if active:registry.add(func)else:registry.discard(func)return func #decorate 是裝飾器,必須返回一個函數return decorate # register 是裝飾器工廠函數,因此返回 decorate
@register(active=True)
def f1():print('running f1()')
@register() #即使不傳入參數,register 也必須作為函數調用(@register()),即要返回真正的裝飾器 decorate。
def f2():print('running f2()')
def f3():print('running f3()')

如果不使用 @ 句法,那就要像常規函數那樣使用 register;若想把 f 添加到 registry中,則裝飾 f 函數的句法是 register()(f);不想添加(或把它刪除)的話,句法是register(active=False)(f)。

參數化裝飾器的原理相當復雜,我們剛剛討論的那個比大多數都簡單。參數化裝飾器通常會把被裝飾的函數替換掉,而且結構上需要多一層嵌套。

7.10.2 參數化clock裝飾器

本節再次探討 clock 裝飾器,為它添加一個功能:讓用戶傳入一個格式字符串,控制被裝飾函數的輸出。
import time
DEFAULT_FMT=’[{elapsed:0.8f}s] {name}({args})-> {result}’

def clock(fmt=DEFAULT_FMT):def decorate(func):def clocked(*_args):t0 = time.time()_result= func(*_args)elapsed=time.time-t0name = func._name__args = ','.join(repr(arg) for arg in _args)result = repr(_result)print(fmt.format(**locals()))return _resultreturn clockedreturn decorate
if __name__ == '__main__':@clockdef snooze(seconds):time.sleep(seconds)for i in range(3):snooze(.123)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/273795.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/273795.shtml
英文地址,請注明出處:http://en.pswp.cn/news/273795.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自制“低奢內”CSS3登入表單,包含JS驗證,請別嫌棄哦。

要求 必備知識 基本了解CSS語法,初步了解CSS3語法知識。和JS/JQuery基本語法。 開發環境 Adobe Dreamweaver CS6 演示地址 演示地址 預覽截圖(抬抬你的鼠標就可以看到演示地址哦): 制作步驟: 一, html結構 <div id"home"><form id"login" class…

class里面只能寫以下5種

轉載于:https://www.cnblogs.com/phplearnings/p/3650849.html

【排序】算法(python實現)

文章目錄python 排序算法1 插入排序1.1 直接插入排序算法思想1.2 希爾排序算法思想2. 選擇排序2.1 簡單選擇排序2.2 堆排序參考python 排序算法 1 插入排序 1.1 直接插入排序 算法思想 直接插入排序的核心思想就是&#xff1a;將數組中的所有元素依次跟前面已經排好的元素相…

OpenSSL漏洞補救辦法詳解(轉)

CVE-2014-0160漏洞背景 2014年4月7日OpenSSL發布了安全公告&#xff0c;在OpenSSL1.0.1版本中存在嚴重漏洞(CVE-2014-0160)。OpenSSL Heartbleed模塊存在一個BUG&#xff0c;問題存在于ssl/dl_both.c文件中的心跳部分&#xff0c;當攻擊者構造一個特殊的數據包&#xff0c;滿足…

SharePoint 自定義WebPart之間的連接

1、創建SharePoint解決方案&#xff0c;添加兩個WebPart分別用來發送和接收&#xff1b; 2、發送值的WebPart需要繼承自IWebPartField(當然&#xff0c;根據需要還可以選擇IWebPartField,IWebPartParameters,IWebPartRow,IWebPartTable&#xff0c;具體參見msdn)&#xff0c;原…

[python 進階] 9. 符合Python風格的對象

文章目錄9.1 對象表示形式9.2 再談向量類9.3 備選構造方法9.4 classmethod與staticmethod9.5 格式化顯示9.6 可散列的Vector2d什么是可散列的數據類型9.6 可散列的Vector9.7 Python的私有屬性和“受保護的”屬性9.8 使用 __slots__ 類屬性節省空間本章包含以下話題&#xff1a;…

android軟件獲取系統簽名

有時候有的功能必須要有系統簽名才能使用&#xff0c;例如調用系統自帶的Surface.screenShot方法時&#xff0c;就必須在androidManifest.xml里聲明android:sharedUserId"android.uid.system" 但是這個時候在編譯生成的apk很有可能無法安裝的情況 并且報這個錯誤&…

Python3中的可變與不可變類型

在描述變量是否是可變類型時&#xff0c;可變與否實際上說的是對變量進行“修改”時變量的內存地址是否會發生變化&#xff0c;而非值是否可變。在Python中&#xff0c;對不可變的變量進行“修改”實際上是重新賦值&#xff0c;對可變的變量進行修改才是真正的修改&#xff0c;…

python中帶*(單星號)的變量和**(雙星號)的變量

一、*args的使用方法 *args 用來將參數打包成tuple給函數體調用二、**kwargs的使用方法 **kwargs 打包關鍵字參數成dict給函數體調用注意點&#xff1a;參數arg、*args、**kwargs三個參數的位置必須是一定的。必須是(arg,*args,**kwargs)這個順序&#xff0c;否則程序會報錯。單…

百度知道回答的依賴注入

oC 或者 DI 或者 ...一大堆的縮寫詞不管是面向對象&#xff0c;還是面向過程&#xff0c;都需要分成許多的塊&#xff0c;然后由這些部件協同工作完成任務 要協同工作就會產生依賴&#xff0c;一個方法調用另一個方法&#xff0c;一個對象包含另一個對象 如果對象A包含對象B的話…

Django model中的 class Meta 詳解

參考 (1) https://www.cnblogs.com/tongchengbin/p/7670927.html

C\C++ 獲取當前路徑

C\C 獲取當前路徑 獲取當前工作目錄是使用函數&#xff1a;getcwd。cwd指的是“current working directory”&#xff0c;這樣就好記憶了。 函數說明&#xff1a; 函數原型&#xff1a;char* getcwd(char* buffer, int len); 參數&#xff1a;buffer是指將當前工作…

[python進階]11接口:從協議到抽象基類

本章討論的話題是接口&#xff1a;從鴨子類型的代表特征動態協議&#xff0c;到使接口更明確、能驗證實現是否符合規定的抽象基類&#xff08;Abstract Base Class&#xff0c;ABC&#xff09;。 首先&#xff0c;本章說明抽象基類的常見用途&#xff1a;實現接口時作為**超類(…

ie11瀏覽器不能顯示最新修改的程序,調試出現代碼邏輯錯誤卻依舊執行

1、問題&#xff1a;ie11瀏覽器不能顯示最新修改的程序&#xff0c;調試也不能&#xff0c;出現代碼邏輯錯誤卻依舊執行 2、百度解決方案&#xff1a;http://blog.163.com/wang_hj138126/blog/static/1408001062012631508444/ FireFox每次訪問頁面時檢查最新版本 2012-07-31 …

C# 基礎備忘錄

1. decimal 類型調用ToString()方法后沒把末尾的0去掉的解決辦法: 例子&#xff1a;decimal? money Convert.ToDecimal(10.8950);string moneyStrmoney.Value.ToString(); 結果在同一臺機子&#xff0c;兩個項目里面會出現兩個不同的結果。結果一&#xff1a;moneyStr"1…

[python進階]12.繼承的優缺點

本章探討繼承和子類化&#xff0c;重點是說明對 Python 而言尤為重要的兩個細節&#xff1a; 子類化內置類型的缺點多重繼承和方法解析順序 12.1 子類化內置類型很 12.2 多重繼承和方法解析

Android中用GridView實現九宮格的兩種方法(轉)

Android中用GridView實現九宮格的兩種方法http://blog.csdn.net/shakespeare001/article/details/7768455 1.傳統辦法&#xff1a;實現一個繼承BaseAdapter的 ImageAdapter package com.test; import android.app.Activity; import android.content.Context; import andro…

django框架中的模型

文章目錄關聯關系Many-to-one relationshipsMany-to-many relationshipsdjango學習——model中的get和filter方法的區別模型模型是您的數據唯一而且準確的信息來源。它包含您正在儲存的數據的重要字段和行為。一般來說&#xff0c;每一個模型都映射一個數據庫表。基礎&#xff…

虛擬主機TOMCAT配置

在tomcat中添加虛擬主機&#xff1a;   編輯"tomcat\conf\server.xml"&#xff0c;在"<Engine></Engine>"元素中新加子元素"<Host></Host>"&#xff0c;如下&#xff1a;  </Host>     <Host name&quo…