函式名是⼀個變數,但它是⼀個特殊的變數。與括號配合可以執⾏函式的變數
1. 做變數
def func():
print('呵呵')
a = func # 把函式當成變數賦值給另外乙個變數
a() # 通過變數a呼叫函式
2. 做容器元素
def func1():
print('func1')
def func2():
print('func2')
def func3():
print('func3')
def func4():
print('func4')
list1 = [func1, func2, func3, func4]
for i in list1:
i()
3. 做參
def func1():
print('func1')
def func2(arg):
print('start')
arg() # 執行傳遞進來的arg
print('end')
func2(func1) # 把func1當成引數傳遞給func2
4. 做返回值
def func1():
print('這裡是func1')
def func2():
print('這裡是func2')
return func2 # 把func2當成返回值返回
ret = func1() # 呼叫func1,把返回值賦值給ret
ret() # 呼叫ret
**1、定義:**乙個內層函式中,引用了外層函式(非全域性)的變數,這個內層函式就可以成為閉包。在python中,我們可以使用__closure__來檢測函式是否是閉包。
2、例子:
def print_msg(msg):
# 這是外層函式
def printer():
# 這是內層函式
print(msg)
return printer # 返回內層函式
func = print_msg("hello") #返回printer變數
func() #實際上執行是printer()函式
現在我們進行如下操作:
>>> del print_msg
>>> func()
hello
>>> print_msg("hello")
traceback (most recent call last):
...nameerror: name 'print_msg' is not defined
總結:
如果⼀個函式執⾏完畢,則這個函式中的變數以及區域性命名空間中的內容都將會被銷毀。在閉包中內部函式會引用外層函式的變數,而且這個變數將不會隨著外層函式的結束而銷毀,它會在記憶體中保留。也就是說,閉包函式可以保留其用到的變數的引用。
1、開放封閉原則是指對擴充套件**的功能是開放的,但是對修改源**是封閉的。這樣的軟體設計思路可以保證我們更好的開發和維護我們的**。
2、利用閉包解釋裝飾器:
def c():
print('11111111')
def a(func):
def b():
print('aaaa')
func()
return b
c = a(c) # 執行步驟:a(c)=>func()=c() =>返回值賦值 c=b
c() #實際執行 b()=>列印aaa=>執行c()=>列印1111111
3、裝飾器規範寫法如下:
def a(func):
def b():
print(1111')
func()
return b
@a # 裝飾器語法
def c():
print('cccccc!')
# 呼叫被裝飾函式
c()
4、帶引數的裝飾器
def f1(func): # f1是我們定義的裝飾器函式,func是被裝飾的函式
def f2(*arg, **kwargs): # *args和**kwargs是被裝飾函式的引數
func(*arg, **kwargs)
return f2
5、裝飾器修復技術
**(1)**被裝飾的函式最終都會失去本來的__doc__等資訊, python給我們提供了乙個修復被裝飾函式的工具。在裝飾器內部加入 @wraps(func)進行修復
(2)例子:
def a(func):
@wraps(func) #可以將這個除去試試
def b():
print('灑點水')
func()
return b
@a # 裝飾器語法糖
def create_people():
"""這是乙個女媧造人的功能函式"""
print('女媧真厲害,捏個泥吹口氣就成了人!')
create_people()
print(create_people.__doc__)
print(create_people.__name__)
6、多個裝飾器修飾乙個函式執行順序為從下至上
7、類裝飾器:
(1)基礎知識:__init__和__call__分別為類中的初始函式和直接呼叫函式,都屬於魔法函式(python內建的)
(2)例項:
class d(object):
def __init__(self, a=none): #初始函式,呼叫類首先執行這個函式
self.a = a
self.mode = "裝飾"
def __call__(self, *args, **kwargs):
if self.mode == "裝飾":
self.func = args[0] # 預設第乙個引數是被裝飾的函式
self.mode = "呼叫"
return self
# 當self.mode == "呼叫"時,執行下面的**(也就是呼叫使用類裝飾的函式時執行)
if self.a:
print("歡迎來到{}頁面。".format(self.a))
else:
print("歡迎來到首頁。")
self.func(*args, **kwargs)
@d()
def index(name):
print("hello {}.".format(name))
if __name__ == '__main__':
index('張三') #呼叫時呼叫類中的__call__函式
8、property屬性方法
(1)我們把類中的乙個唯讀屬性定義為property屬性方法,只有在訪問它時才參與計算,一旦訪問了該屬性,我們就把這個值快取起來,下次再訪問的時候無需重新計算。
(2)例子:
class lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
if instance is none:
return self
else:
value = self.func(instance)
setattr(instance, self.func.__name__, value)
return value
import math
class circle:
def __init__(self, radius):
self.radius = radius
@lazyproperty
def area(self):
print('計算面積')
return math.pi * self.radius ** 2
c1 = circle(10)
print(c1.area)
print(c1.area)#執行這個會發現這一步只返回了值,沒有重新執行函式。
python裝飾器 python 裝飾器詳解
def outer x def inner y return x y return inner print outer 6 5 11 如 所示,在outer函式內,又定義了乙個inner函式,並且inner函式又引用了外部函式outer的變數x,這就是乙個閉包了。在輸出時,outer 6 5 第乙個...
python裝飾器詳解 python裝飾器詳解
按照 python 的程式設計原則,當乙個函式被定義後,如要修改或擴充套件其功能應盡量避免直接修改函式定義的 段,否則該函式在其他地方被呼叫時將無法正常執行。因此,當需要修改或擴充套件已被定義的函式的功能而不希望直接修改其 時,可以使用裝飾器。先來看乙個簡單的例子 def func1 functio...
詳解Python裝飾器
裝飾器的難點 在梳理了裝飾器的整個內容之後,我認為難點不是裝飾器本身,而是直接呼叫被裝飾的函式,讓人無法理解背後究竟發生了什麼。一 引出裝飾器概念 引入問題 定義了乙個函式,想在執行時動態的增加功能,又不想改動函式本身的 示例 希望對下列函式呼叫增加log功能,列印出函式呼叫 def f1 x re...