python 高級編程

1.1==缚陷,is的使用

·is是比較兩個引用是否指向了同一個對象(引用比較)。

·==是比較兩個對象是否相等。

1.2深拷貝、淺拷貝

1.2.1淺拷貝

淺拷貝是對于一個對象的頂層拷貝

通俗的理解是:拷貝了引用归斤,并沒有拷貝內(nèi)容

1.2.2深拷貝

copy.deepcopy

1.2.3拷貝的其他方式

淺拷貝對不可變類型和可變類型的copy不同

In [88]: a = [11,22,33]

In [89]: b = copy.copy(a)

In [90]: id(a)

Out[90]:59275144

In [91]: id(b)

Out[91]:59525600

In [92]: a.append(44)

In [93]: a

Out[93]: [11,22,33,44]

In [94]: b

Out[94]: [11,22,33]

In [95]:

In [95]:

In [95]: a = (11,22,33)

In [96]: b = copy.copy(a)

In [97]: id(a)

Out[97]:58890680

In [98]: id(b)

Out[98]:58890680

·分片表達式可以賦值一個序列

a ="abc"

b = a[:]

·字典的copy方法可以拷貝一個字典

d = dict(name="zhangsan", age=27)

co = d.copy()

·有些內(nèi)置函數(shù)可以生成拷貝(list)

a = list(range(10))

b = list(a)

·copy模塊中的copy函數(shù)

importcopy

a = (1,2,3)

b = copy.copy(a)

1.3屬性property

面試題:

1、你對面向?qū)ο蟮睦斫?/p>

2刁岸、面向?qū)ο蟮奶卣魇鞘裁?/p>

3脏里、對封裝的理解?

封裝难捌,類本身就是一個封裝,封裝了屬性和方法鸦难。方法也是封裝根吁,對一些業(yè)務(wù)邏輯的封裝。私有也是封裝合蔽,將一些方法和屬性私有化击敌,對外提供可訪問的接口。

4拴事、對繼承的理解

將共性的內(nèi)容放在父類中沃斤,子類只需要關(guān)注自己特有的內(nèi)容,共性的繼承過來就行了刃宵。

這樣簡化開發(fā)衡瓶,符合邏輯習(xí)慣,利于擴展牲证。

5哮针、多態(tài)的理解

多態(tài),一個對象在不同的情況下顯示不同的形態(tài)十厢。在python中因為是弱類型語言等太,對類型沒有限定,所有python中不完全支持多態(tài)春瞬,但是多態(tài)的思想呢,python也是能體現(xiàn)的。

1.3.1私有屬性添加getter和setter方法

classMoney(object):

def__init__(self):

self.__money =0

defgetMoney(self):

returnself.__money

defsetMoney(self, value):

ifisinstance(value, int):

self.__money = value

else:

print("error:不是整型數(shù)字")

1.3.2使用property升級getter和setter方法

classMoney(object):

def__init__(self):

self.__money =0

defgetMoney(self):

returnself.__money

defsetMoney(self, value):

ifisinstance(value, int):

self.__money = value

else:

print("error:不是整型數(shù)字")

money = property(getMoney, setMoney)

運行結(jié)果:

In [1]:fromget_setimportMoney

In [2]:

In [2]: a = Money()

In [3]:

In [3]: a.money

Out[3]:0

In [4]: a.money =100

In [5]: a.money

Out[5]:100

In [6]: a.getMoney()

Out[6]:100

1.3.3使用property取代getter和setter方法

@property成為屬性函數(shù)英古,可以對屬性賦值時做必要的檢查,并保證代碼的清晰短小蛮浑,主要有2個作用

·將方法轉(zhuǎn)換為只讀

·重新實現(xiàn)一個屬性的設(shè)置和讀取方法,可做邊界判定

classMoney(object):

def__init__(self):

self.__money =0

@property

defmoney(self):

returnself.__money

@money.setter

defmoney(self, value):

ifisinstance(value, int):

self.__money = value

else:

print("error:不是整型數(shù)字")

運行結(jié)果

In [3]: a = Money()

In [4]:

In [4]:

In [4]: a.money

Out[4]:0

In [5]: a.money =100

In [6]: a.money

Out[6]:100

1.4生成器

1.4.1什么是生成器

通過列表生成式唠叛,我們可以直接創(chuàng)建一個列表。但是沮稚,受到內(nèi)存限制艺沼,列表容量肯定是有限的。而且蕴掏,創(chuàng)建一個包含100萬個元素的列表障般,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素盛杰,那后面絕大多數(shù)元素占用的空間都白白浪費了挽荡。所以,如果列表元素可以按照某種算法推算出來即供,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢定拟?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間逗嫡。在Python中青自,這種一邊循環(huán)一邊計算的機制,稱為生成器:generator驱证。

1.4.2創(chuàng)建生成器方法1

要創(chuàng)建一個生成器延窜,有很多種方法。第一種方法很簡單雷滚,只要把一個列表生成式的[ ]改成( )

In [15]: L = [ x*2forxinrange(5)]

In [16]: L

Out[16]: [0,2,4,6,8]

In [17]: G = ( x*2forxinrange(5))

In [18]: G

Out[18]: at0x7f626c132db0>

In [19]:

創(chuàng)建L和G的區(qū)別僅在于最外層的[ ]和( )需曾,L是一個列表吗坚,而G是一個生成器祈远。我們可以直接打印出L的每一個元素,但我們怎么打印出G的每一個元素呢商源?如果要一個一個打印出來车份,可以通過next()函數(shù)獲得生成器的下一個返回值:

In [19]: next(G)

Out[19]: 0

In [20]: next(G)

Out[20]: 2

In [21]: next(G)

Out[21]: 4

In [22]: next(G)

Out[22]: 6

In [23]: next(G)

Out[23]: 8

In [24]: next(G)

---------------------------------------------------------------------------

StopIteration ????????????????????????????Traceback (most recent call last)

in ()

----> 1 next(G)

StopIteration:

In [25]:

In [26]: G = ( x*2forxinrange(5))

In [27]:forxinG:

....: ????print(x)

....:

0

2

4

6

8

In [28]:

生成器保存的是算法,每次調(diào)用next(G)牡彻,就計算出G的下一個元素的值扫沼,直到計算到最后一個元素出爹,沒有更多的元素時,拋出StopIteration的異常缎除。當(dāng)然严就,這種不斷調(diào)用next()實在是太變態(tài)了,正確的方法是使用for循環(huán)器罐,因為生成器也是可迭代對象梢为。所以,我們創(chuàng)建了一個生成器后轰坊,基本上永遠不會調(diào)用next()铸董,而是通過for循環(huán)來迭代它,并且不需要關(guān)心StopIteration異常肴沫。

1.4.3創(chuàng)建生成器方法2

generator非常強大粟害。如果推算的算法比較復(fù)雜,用類似列表生成式的for循環(huán)無法實現(xiàn)的時候颤芬,還可以用函數(shù)來實現(xiàn)悲幅。

比如,著名的斐波拉契數(shù)列(Fibonacci)驻襟,除第一個和第二個數(shù)外夺艰,任意一個數(shù)都可由前兩個數(shù)相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契數(shù)列用列表生成式寫不出來,但是沉衣,用函數(shù)把它打印出來卻很容易:

In [28]:deffib(times):

....: ????n =0

....: ????a,b =0,1

....:whilen

....: ????????print(b)

....: ????????a,b = b,a+b

....: ????????n+=1

....:return'done'

....:

In [29]: fib(5)

1

1

2

3

5

Out[29]:'done'

仔細(xì)觀察郁副,可以看出,fib函數(shù)實際上是定義了斐波拉契數(shù)列的推算規(guī)則豌习,可以從第一個元素開始存谎,推算出后續(xù)任意的元素,這種邏輯其實非常類似generator肥隆。

也就是說既荚,上面的函數(shù)和generator僅一步之遙。要把fib函數(shù)變成generator栋艳,只需要把print(b)改為yield b就可以了:

In [30]: def fib(times):

....: ????n = 0

....: ????a,b = 0,1

....: ????while n

....: ????????yield b

....: ????????a,b = b,a+b

....: ????????n+=1

....: ????return 'done'

....:

In [31]: F = fib(5)

In [32]: next(F)

Out[32]: 1

In [33]: next(F)

Out[33]: 1

In [34]: next(F)

Out[34]: 2

In [35]: next(F)

Out[35]: 3

In [36]: next(F)

Out[36]: 5

In [37]: next(F)

---------------------------------------------------------------------------

StopIteration ????????????????????????????Traceback (most recent call last)

in ()

----> 1 next(F)

StopIteration: done

在上面fib的例子恰聘,我們在循環(huán)過程中不斷調(diào)用yield,就會不斷中斷吸占。當(dāng)然要給循環(huán)設(shè)置一個條件來退出循環(huán)晴叨,不然就會產(chǎn)生一個無限數(shù)列出來。同樣的矾屯,把函數(shù)改成generator后兼蕊,我們基本上從來不會用next()來獲取下一個返回值,而是直接使用for循環(huán)來迭代:

In [38]:forninfib(5):

....: ????print(n)

....:

1

1

2

3

5

In [39]:

但是用for循環(huán)調(diào)用generator時件蚕,發(fā)現(xiàn)拿不到generator的return語句的返回值孙技。如果想要拿到返回值产禾,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中:

In [39]: g = fib(5)

In [40]:whileTrue:

....:try:

....: ????????x = next(g)

....: ????????print("value:%d"%x)

....:exceptStopIterationase:

....: ????????print("生成器返回值:%s"%e.value)

....:break

....:

value:1

value:1

value:2

value:3

value:5

生成器返回值:done

In [41]:

1.4.4send

例子:執(zhí)行到y(tǒng)ield時牵啦,gen函數(shù)作用暫時保存亚情,返回i的值;temp接收下次c.send("python"),send發(fā)送過來的值哈雏,c.next()等價c.send(None)

In [10]:defgen():

....: ????i =0

....:whilei<5:

....: ????????temp =yieldi

....: ????????print(temp)

....: ????????i+=1

....:

使用next函數(shù)

In [11]: f = gen()

In [12]: next(f)

Out[12]: 0

In [13]: next(f)

None

Out[13]: 1

In [14]: next(f)

None

Out[14]: 2

In [15]: next(f)

None

Out[15]: 3

In [16]: next(f)

None

Out[16]: 4

In [17]: next(f)

None

---------------------------------------------------------------------------

StopIteration ????????????????????????????Traceback (most recent call last)

in ()

----> 1 next(f)

StopIteration:

使用__next__()方法

In [18]: f = gen()

In [19]: f.__next__()

Out[19]: 0

In [20]: f.__next__()

None

Out[20]: 1

In [21]: f.__next__()

None

Out[21]: 2

In [22]: f.__next__()

None

Out[22]: 3

In [23]: f.__next__()

None

Out[23]: 4

In [24]: f.__next__()

None

---------------------------------------------------------------------------

StopIteration ????????????????????????????Traceback (most recent call last)

in ()

----> 1 f.__next__()

StopIteration:

使用send

In [43]: f = gen()

In [44]: f.__next__()

Out[44]:0

In [45]: f.send('haha')

haha

Out[45]:1

In [46]: f.__next__()

None

Out[46]:2

In [47]: f.send('haha')

haha

Out[47]:3

In [48]:

1.4.5實現(xiàn)多任務(wù)

模擬多任務(wù)實現(xiàn)方式之一:協(xié)程

def test1():

while True:

print("--1--")

yield None

def test2():

while True:

print("--2--")

yield None

t1 = test1()

t2 = test2()

while True:

t1.__next__()

t2.__next__()

總結(jié)

生成器是這樣一個函數(shù)势似,它記住上一次返回時在函數(shù)體中的位置。對生成器函數(shù)的第二次(或第n次)調(diào)用跳轉(zhuǎn)至該函數(shù)中間僧著,而上次調(diào)用的所有局部變量都保持不變履因。

生成器不僅“記住”了它數(shù)據(jù)狀態(tài);生成器還“記住”了它在流控制構(gòu)造(在命令式編程中盹愚,這種構(gòu)造不只是數(shù)據(jù)值)中的位置栅迄。

生成器的特點:

1.節(jié)約內(nèi)存

2.迭代到下一次的調(diào)用時,所使用的參數(shù)都是第一次所保留下的皆怕,即是說毅舆,在整個所有函數(shù)調(diào)用的參數(shù)都是第一次所調(diào)用時保留的,而不是新創(chuàng)建的

1.5迭代器

迭代是訪問集合元素的一種方式愈腾。迭代器是一個可以記住遍歷的位置的對象憋活。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結(jié)束虱黄。迭代器只能往前不會后退悦即。

1.5.1可迭代對象

以直接作用于for循環(huán)的數(shù)據(jù)類型有以下幾種:

一類是集合數(shù)據(jù)類型,如list橱乱、tuple辜梳、dict、set泳叠、str等作瞄;

一類是generator,包括生成器和帶yield的generator function。

這些可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象:Iterable。

1.5.2判斷是否可以迭代

可以使用isinstance()判斷一個對象是否是Iterable對象:

In [50]:fromcollectionsimportIterable

In [51]: isinstance([], Iterable)

Out[51]:True

In [52]: isinstance({}, Iterable)

Out[52]:True

In [53]: isinstance('abc', Iterable)

Out[53]:True

In [54]: isinstance((xforxinrange(10)), Iterable)

Out[54]:True

In [55]: isinstance(100, Iterable)

Out[55]:False

而生成器不但可以作用于for循環(huán)维费,還可以被next()函數(shù)不斷調(diào)用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續(xù)返回下一個值了契耿。

1.5.3迭代器

可以被next()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器:Iterator。

可以使用isinstance()判斷一個對象是否是Iterator對象:

In [56]:fromcollectionsimportIterator

In [57]: isinstance((xforxinrange(10)), Iterator)

Out[57]:True

In [58]: isinstance([], Iterator)

Out[58]:False

In [59]: isinstance({}, Iterator)

Out[59]:False

In [60]: isinstance('abc', Iterator)

Out[60]:False

In [61]: isinstance(100, Iterator)

Out[61]:False

1.5.4iter()函數(shù)

生成器都是Iterator對象蛤吓,但list宵喂、dict糠赦、str雖然是Iterable会傲,卻不是Iterator锅棕。

把list、dict淌山、str等Iterable變成Iterator可以使用iter()函數(shù):

In [62]: isinstance(iter([]), Iterator)

Out[62]:True

In [63]: isinstance(iter('abc'), Iterator)

Out[63]:True

總結(jié)

·凡是可作用于for循環(huán)的對象都是Iterable類型裸燎;

·凡是可作用于next()函數(shù)的對象都是Iterator類型

·集合數(shù)據(jù)類型如list、dict泼疑、str等是Iterable但不是Iterator德绿,不過可以通過iter()函數(shù)獲得一個Iterator對象。

·目的是在使用集合的時候退渗,減少占用的內(nèi)存移稳。

1.6閉包

1.61.1.1什么是閉包.1函數(shù)引用

deftest1():

print("--- in test1 func----")

#調(diào)用函數(shù)

test1()

#引用函數(shù)

ret = test1

print(id(ret))

print(id(test1))

#通過引用調(diào)用函數(shù)

ret()

運行結(jié)果:

---intest1 func----

140212571149040

140212571149040

---intest1 func----

1.6.2 什么是閉包

定義一個函數(shù)

deftest(number):

#在函數(shù)內(nèi)部再定義一個函數(shù),并且這個函數(shù)用到了外邊函數(shù)的變量会油,那么將這個函數(shù)以及用到的一些變量稱之為閉包

deftest_in(number_in):

print("in test_in函數(shù), number_in is %d"%number_in)

returnnumber+number_in

#其實這里返回的就是閉包的結(jié)果

returntest_in

#給test函數(shù)賦值个粱,這個20就是給參數(shù)number

ret = test(20)

#注意這里的100其實給參數(shù)number_in

print(ret(100))

#注意這里的200其實給參數(shù)number_in

print(ret(200))

運行結(jié)果:

intest_in函數(shù), number_inis100

120

intest_in函數(shù), number_inis200

220

1.6.3看一個閉包的實際例子:

defline_conf(a, b):

defline(x):

returna*x + b

returnline

line1 = line_conf(1,1)

line2 = line_conf(4,5)

print(line1(5))

print(line2(5))

這個例子中,函數(shù)line與變量a,b構(gòu)成閉包翻翩。在創(chuàng)建閉包的時候都许,我們通過line_conf的參數(shù)a,b說明了這兩個變量的取值,這樣嫂冻,我們就確定了函數(shù)的最終形式(y = x + 1和y = 4x + 5)胶征。我們只需要變換參數(shù)a,b,就可以獲得不同的直線表達函數(shù)桨仿。由此睛低,我們可以看到,閉包也具有提高代碼可復(fù)用性的作用服傍。

如果沒有閉包暇昂,我們需要每次創(chuàng)建直線函數(shù)的時候同時說明a,b,x。這樣伴嗡,我們就需要更多的參數(shù)傳遞急波,也減少了代碼的可移植性。

閉包思考:

1.閉包似優(yōu)化了變量瘪校,原來需要類對象完成的工作澄暮,閉包也可以完成

2.由于閉包引用了外部函數(shù)的局部變量,則外部函數(shù)的局部變量沒有及時釋放阱扬,消耗內(nèi)存

1.7.裝飾器

裝飾器是程序開發(fā)中經(jīng)常會用到的一個功能泣懊,用好了裝飾器,開發(fā)效率如虎添翼麻惶,所以這也是Python面試中必問的問題馍刮,但對于好多初次接觸這個知識的人來講,這個功能有點繞窃蹋,自學(xué)時直接繞過去了卡啰,然后面試問到了就掛了静稻,因為裝飾器是程序開發(fā)的基礎(chǔ)知識,這個都不會匈辱,別跟人家說你會Python,看了下面的文章振湾,保證你學(xué)會裝飾器。

1.7.1裝飾器理解

1亡脸、先明白這段代碼

####第一波####

deffoo():

print('foo')

foo#表示是函數(shù)

foo()#表示執(zhí)行foo函數(shù)

####第二波####

deffoo():

print('foo')

foo =lambdax: x +1

foo()#執(zhí)行下面的lambda表達式押搪,而不再是原來的foo函數(shù),因為foo這個名字被重新指向了另外一個匿名函數(shù)

2浅碾、需求來了

初創(chuàng)公司有N個業(yè)務(wù)部門大州,1個基礎(chǔ)平臺部門,基礎(chǔ)平臺負(fù)責(zé)提供底層的功能垂谢,如:數(shù)據(jù)庫操作摧茴、redis調(diào)用、監(jiān)控API等功能埂陆。業(yè)務(wù)部門使用基礎(chǔ)功能時苛白,只需調(diào)用基礎(chǔ)平臺提供的功能即可。如下:

###############基礎(chǔ)平臺提供的功能如下###############

deff1():

print('f1')

deff2():

print('f2')

deff3():

print('f3')

deff4():

print('f4')

###############業(yè)務(wù)部門A調(diào)用基礎(chǔ)平臺提供的功能###############

f1()

f2()

f3()

f4()

###############業(yè)務(wù)部門B調(diào)用基礎(chǔ)平臺提供的功能###############

f1()

f2()

f3()

f4()

目前公司有條不紊的進行著焚虱,但是购裙,以前基礎(chǔ)平臺的開發(fā)人員在寫代碼時候沒有關(guān)注驗證相關(guān)的問題,即:基礎(chǔ)平臺的提供的功能可以被任何人使用【樵裕現(xiàn)在需要對基礎(chǔ)平臺的所有功能進行重構(gòu)躏率,為平臺提供的所有功能添加驗證機制,即:執(zhí)行功能前民鼓,先進行驗證薇芝。

老大把工作交給Low B,他是這么做的:

跟每個業(yè)務(wù)部門交涉丰嘉,每個業(yè)務(wù)部門自己寫代碼夯到,調(diào)用基礎(chǔ)平臺的功能之前先驗證。誒饮亏,這樣一來基礎(chǔ)平臺就不需要做任何修改了耍贾。太棒了,有充足的時間泡妹子...

當(dāng)天Low B被開除了…

老大把工作交給Low BB路幸,他是這么做的:

###############基礎(chǔ)平臺提供的功能如下###############

deff1():

#驗證1

#驗證2

#驗證3

print('f1')

deff2():

#驗證1

#驗證2

#驗證3

print('f2')

deff3():

#驗證1

#驗證2

#驗證3

print('f3')

deff4():

#驗證1

#驗證2

#驗證3

print('f4')

###############業(yè)務(wù)部門不變###############

###業(yè)務(wù)部門A調(diào)用基礎(chǔ)平臺提供的功能###

f1()

f2()

f3()

f4()

###業(yè)務(wù)部門B調(diào)用基礎(chǔ)平臺提供的功能###

f1()

f2()

f3()

f4()

過了一周Low BB被開除了…

老大把工作交給Low BBB荐开,他是這么做的:

只對基礎(chǔ)平臺的代碼進行重構(gòu),其他業(yè)務(wù)部門無需做任何修改

###############基礎(chǔ)平臺提供的功能如下###############

defcheck_login():

#驗證1

#驗證2

#驗證3

pass

deff1():

check_login()

print('f1')

deff2():

check_login()

print('f2')

deff3():

check_login()

print('f3')

deff4():

check_login()

print('f4')

老大看了下Low BBB的實現(xiàn)简肴,嘴角漏出了一絲的欣慰的笑晃听,語重心長的跟Low BBB聊了個天:

老大說:

寫代碼要遵循開放封閉原則,雖然在這個原則是用的面向?qū)ο箝_發(fā),但是也適用于函數(shù)式編程能扒,簡單來說佣渴,它規(guī)定已經(jīng)實現(xiàn)的功能代碼不允許被修改,但可以被擴展赫粥,即:

·封閉:已實現(xiàn)的功能代碼塊

·開放:對擴展開發(fā)

如果將開放封閉原則應(yīng)用在上述需求中,那么就不允許在函數(shù)f1予借、f2越平、f3、f4的內(nèi)部進行修改代碼灵迫,老板就給了Low BBB一個實現(xiàn)方案:

defw1(func):

definner():

#驗證1

#驗證2

#驗證3

func()

returninner

@w1

deff1():

print('f1')

@w1

deff2():

print('f2')

@w1

deff3():

print('f3')

@w1

deff4():

print('f4')

對于上述代碼秦叛,也是僅僅對基礎(chǔ)平臺的代碼進行修改,就可以實現(xiàn)在其他人調(diào)用函數(shù)f1 f2 f3 f4之前都進行【驗證】操作瀑粥,并且其他業(yè)務(wù)部門無需做任何操作挣跋。

Low BBB心驚膽戰(zhàn)的問了下,這段代碼的內(nèi)部執(zhí)行原理是什么呢狞换?

老大正要生氣避咆,突然Low BBB的手機掉到地上,恰巧屏保就是Low BBB的女友照片修噪,老大一看一緊一抖查库,喜笑顏開,決定和Low BBB交個好朋友黄琼。

詳細(xì)的開始講解了:

單獨以f1為例:

defw1(func):

definner():

#驗證1

#驗證2

#驗證3

func()

returninner

@w1

deff1():

print('f1')

python解釋器就會從上到下解釋代碼樊销,步驟如下:

1.def w1(func): ==>將w1函數(shù)加載到內(nèi)存

2.@w1

沒錯,從表面上看解釋器僅僅會解釋這兩句代碼脏款,因為函數(shù)在沒有被調(diào)用之前其內(nèi)部代碼不會被執(zhí)行围苫。

從表面上看解釋器著實會執(zhí)行這兩句,但是@w1這一句代碼里卻有大文章撤师,@函數(shù)名 是python的一種語法糖剂府。

上例@w1內(nèi)部會執(zhí)行一下操作:

執(zhí)行w1函數(shù)

執(zhí)行w1函數(shù) ,并將@w1下面的函數(shù)作為w1函數(shù)的參數(shù)剃盾,即:@w1等價于w1(f1)所以周循,內(nèi)部就會去執(zhí)行:

definner():

#驗證1

#驗證2

#驗證3

f1()# func是參數(shù),此時func等于f1

returninner#返回的inner万俗,inner代表的是函數(shù)湾笛,非執(zhí)行函數(shù),其實就是將原來的f1函數(shù)塞進另外一個函數(shù)中

w1的返回值

將執(zhí)行完的w1函數(shù)返回值 賦值 給@w1下面的函數(shù)的函數(shù)名f1即將w1的返回值再重新賦值給f1,即:

新f1 =definner():

#驗證1

#驗證2

#驗證3

原來f1()

returninner

所以闰歪,以后業(yè)務(wù)部門想要執(zhí)行f1函數(shù)時嚎研,就會執(zhí)行 新f1函數(shù),在新f1函數(shù)內(nèi)部先執(zhí)行驗證,再執(zhí)行原來的f1函數(shù)临扮,然后將原來f1函數(shù)的返回值返回給了業(yè)務(wù)調(diào)用者论矾。

如此一來,即執(zhí)行了驗證的功能杆勇,又執(zhí)行了原來f1函數(shù)的內(nèi)容贪壳,并將原f1函數(shù)返回值 返回給業(yè)務(wù)調(diào)用著

Low BBB你明白了嗎?要是沒明白的話蚜退,我晚上去你家?guī)湍憬鉀Q吧H蜓ァ!钻注!

1.1.2多個裝飾器

#定義函數(shù):完成包裹數(shù)據(jù)

defmakeBold(fn):

defwrapped():

return""+ fn() +""

returnwrapped

#定義函數(shù):完成包裹數(shù)據(jù)

defmakeItalic(fn):

defwrapped():

return""+ fn() +""

returnwrapped

@makeBold

deftest1():

return"hello world-1"

@makeItalic

deftest2():

return"hello world-2"

@makeBold

@makeItalic

deftest3():

return"hello world-3"

print(test1()))

print(test2()))

print(test3()))

運行結(jié)果:

hello world-1

hello world-2

hello world-3

1.7.3裝飾器(decorator)功能

1.引入日志

2.函數(shù)執(zhí)行時間統(tǒng)計

3.執(zhí)行函數(shù)前預(yù)備處理

4.執(zhí)行函數(shù)后清理功能

5.權(quán)限校驗等場景

6.緩存

1.7.4裝飾器示例

1.7.4.1例1:無參數(shù)的函數(shù)

fromtimeimportctime, sleep

deftimefun(func):

defwrappedfunc():

print("%s called at %s"%(func.__name__, ctime()))

func()

returnwrappedfunc

@timefun

deffoo():

print("I am foo")

foo()

sleep(2)

foo()

上面代碼理解裝飾器執(zhí)行行為可理解成

foo = timefun(foo)

#foo先作為參數(shù)賦值給func后,foo接收指向timefun返回的wrappedfunc

foo()

#調(diào)用foo(),即等價調(diào)用wrappedfunc()

#內(nèi)部函數(shù)wrappedfunc被引用蚂且,所以外部函數(shù)的func變量(自由變量)并沒有釋放

#func里保存的是原foo函數(shù)對象

1.7.2例2:被裝飾的函數(shù)有參數(shù)

fromtimeimportctime, sleep

deftimefun(func):

defwrappedfunc(a, b):

print("%s called at %s"%(func.__name__, ctime()))

print(a, b)

func(a, b)

returnwrappedfunc

@timefun

deffoo(a, b):

print(a+b)

foo(3,5)

sleep(2)

foo(2,4)

1.7.3例3:被裝飾的函數(shù)有不定長參數(shù)

fromtimeimportctime, sleep

deftimefun(func):

defwrappedfunc(*args, **kwargs):

print("%s called at %s"%(func.__name__, ctime()))

func(*args, **kwargs)

returnwrappedfunc

@timefun

deffoo(a, b, c):

print(a+b+c)

foo(3,5,7)

sleep(2)

foo(2,4,9)

1.7.4例4:裝飾器中的return

fromtimeimportctime, sleep

deftimefun(func):

defwrappedfunc():

print("%s called at %s"%(func.__name__, ctime()))

func()

returnwrappedfunc

@timefun

deffoo():

print("I am foo")

@timefun

defgetInfo():

return'----hahah---'

foo()

sleep(2)

foo()

print(getInfo())

執(zhí)行結(jié)果:

foo called at Fri Nov421:55:352016

I am foo

foo called at Fri Nov421:55:372016

I am foo

getInfo called at Fri Nov421:55:372016

None

如果修改裝飾器為return func(),則運行結(jié)果:

foo called at Fri Nov421:55:572016

I am foo

foo called at Fri Nov421:55:592016

I am foo

getInfo called at Fri Nov421:55:592016

----hahah---

總結(jié):

·一般情況下為了讓裝飾器更通用幅恋,可以有return

1.7.5例5:裝飾器帶參數(shù),在原有裝飾器的基礎(chǔ)上杏死,設(shè)置外部變量

#decorator2.py

fromtimeimportctime, sleep

deftimefun_arg(pre="hello"):

deftimefun(func):

defwrappedfunc():

print("%s called at %s %s"%(func.__name__, ctime(), pre))

returnfunc()

returnwrappedfunc

returntimefun

@timefun_arg("wangcai")

deffoo():

print("I am foo")

@timefun_arg("python")

deftoo():

print("I am too")

foo()

sleep(2)

foo()

too()

sleep(2)

too()

可以理解為

foo()==timefun_arg("wangcai")(foo)()

1.2python是動態(tài)語言

1.2.1動態(tài)語言的定義

動態(tài)編程語言是高級程序設(shè)計語言的一個類別,在計算機科學(xué)領(lǐng)域已被廣泛應(yīng)用捆交。它是一類在運行時可以改變其結(jié)構(gòu)的語言:例如新的函數(shù)淑翼、對象、甚至代碼可以被引進品追,已有的函數(shù)可以被刪除或是其他結(jié)構(gòu)上的變化窒舟。動態(tài)語言目前非常具有活力。例如JavaScript便是一個動態(tài)語言诵盼,除此之外如PHP惠豺、Ruby、Python等也都屬于動態(tài)語言风宁,而C洁墙、C++等語言則不屬于動態(tài)語言。----來自 維基百科

1.2.2運行的過程中給對象綁定(添加)屬性

>>>classPerson(object):

def__init__(self, name = None, age = None):

self.name = name

self.age = age

>>>P = Person("小明","24")

>>>

在這里戒财,我們定義了1個類Person热监,在這個類里,定義了兩個初始屬性name和age饮寞,但是人還有性別靶⒖浮!如果這個類不是你寫的是不是你會嘗試訪問性別這個屬性呢幽崩?

>>>P.sex ="male"

>>>P.sex

'male'

>>>

這時候就發(fā)現(xiàn)問題了苦始,我們定義的類里面沒有sex這個屬性啊慌申!怎么回事呢陌选? 這就是動態(tài)語言的魅力和坑! 這里 實際上就是 動態(tài)給實例綁定屬性!

1.2.3運行的過程中給類綁定(添加)屬性

>>>P1 = Person("小麗","25")

>>>P1.sex

Traceback (most recent call last):

File"", line1,in

P1.sex

AttributeError: Person instance has no attribute'sex'

>>>

我們嘗試打印P1.sex咨油,發(fā)現(xiàn)報錯您炉,P1沒有sex這個屬性!----給P這個實例綁定屬性對P1這個實例不起作用役电! 那我們要給所有的Person的實例加上sex屬性怎么辦呢赚爵? 答案就是直接給Person綁定屬性!

>>>> Person.sex =None#給類Person添加一個屬性

>>>P1 = Person("小麗","25")

>>>print(P1.sex)#如果P1這個實例對象中沒有sex屬性的話法瑟,那么就會訪問它的類屬性

None#可以看到?jīng)]有出現(xiàn)異常

>>>

1.2.4運行的過程中給類綁定(添加)方法

我們直接給Person綁定sex這個屬性冀膝,重新實例化P1后,P1就有sex這個屬性了瓢谢! 那么function呢氓扛?怎么綁定?

>>>classPerson(object):

def__init__(self, name = None, age = None):

self.name = name

self.age = age

defeat(self):

print("eat food")

>>>defrun(self, speed):

print("%s在移動,速度是%d km/h"%(self.name, speed))

>>>P = Person("老王",24)

>>>P.eat()

eat food

>>>

>>>P.run()

Traceback (most recent call last):

File"", line1,in

P.run()

AttributeError: Person instance has no attribute'run'

>>>

>>>

>>>importtypes

>>>P.run = types.MethodType(run, P)

>>>P.run(180)

老王在移動,速度是180km/h

既然給類添加方法最楷,是使用類名.方法名= xxxx烈评,那么給對象添加一個方法也是類似的對象.方法名= xxxx

完整的代碼如下:

importtypes

#定義了一個類

classPerson(object):

num =0

def__init__(self, name = None, age = None):

self.name = name

self.age = age

defeat(self):

print("eat food")

#定義一個實例方法

defrun(self, speed):

print("%s在移動,速度是%d km/h"%(self.name, speed))

#定義一個類方法

@classmethod

deftestClass(cls):

cls.num =100

#定義一個靜態(tài)方法

@staticmethod

deftestStatic():

print("---static method----")

#創(chuàng)建一個實例對象

P = Person("老王",24)

#調(diào)用在class中的方法

P.eat()

#給這個對象添加實例方法

P.run = types.MethodType(run, P)

#調(diào)用實例方法

P.run(180)

#給Person類綁定類方法

Person.testClass = testClass

#調(diào)用類方法

print(Person.num)

Person.testClass()

print(Person.num)

#給Person類綁定靜態(tài)方法

Person.testStatic = testStatic

#調(diào)用靜態(tài)方法

Person.testStatic()

1.2.5運行的過程中刪除屬性适瓦、方法

刪除的方法:

1.del對象.屬性名

2.delattr(對象, "屬性名")

通過以上例子可以得出一個結(jié)論:相對于動態(tài)語言否彩,靜態(tài)語言具有嚴(yán)謹(jǐn)性!所以肌毅,玩動態(tài)語言的時候,小心動態(tài)的坑!

那么怎么避免這種情況呢?請使用__slots__乡范,

1.2.6__slots__

現(xiàn)在我們終于明白了宇整,動態(tài)語言與靜態(tài)語言的不同

動態(tài)語言:可以在運行的過程中霸饲,修改代碼

靜態(tài)語言:編譯時已經(jīng)確定好代碼埃儿,運行過程中不能修改

如果我們想要限制實例的屬性怎么辦精钮?比如,只允許對Person實例添加name和age屬性科雳。

為了達到限制的目的,Python允許在定義class的時候尿赚,定義一個特殊的__slots__變量屋讶,來限制該class實例能添加的屬性:

>>>classPerson(object):

__slots__ = ("name","age")

>>>P = Person()

>>>P.name ="老王"

>>>P.age =20

>>>P.score =100

Traceback (most recent call last):

File"", line1,in

AttributeError: Person instance has no attribute'score'

>>>

1.2.6.1注意:

·使用__slots__要注意,__slots__定義的屬性僅對當(dāng)前類實例起作用约计,對繼承的子類是不起作用的

In [67]:classTest(Person):

...:pass

...:

In [68]: t = Test()

In [69]: t.score =100

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尉桩,一起剝皮案震驚了整個濱河市翰苫,隨后出現(xiàn)的幾起案子屈扎,更是在濱河造成了極大的恐慌止毕,老刑警劉巖闯传,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妹窖,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門出嘹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垮斯,“玉大人牺氨,你說我怎么就攤上這事≌油罚” “怎么了爷绘?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長进倍。 經(jīng)常有香客問我土至,道長,這世上最難降的妖魔是什么猾昆? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任陶因,我火速辦了婚禮,結(jié)果婚禮上垂蜗,老公的妹妹穿的比我還像新娘楷扬。我一直安慰自己,他們只是感情好贴见,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布烘苹。 她就那樣靜靜地躺著,像睡著了一般片部。 火紅的嫁衣襯著肌膚如雪镣衡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天吞琐,我揣著相機與錄音捆探,去河邊找鬼然爆。 笑死站粟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的曾雕。 我是一名探鬼主播奴烙,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼剖张!你這毒婦竟也來了切诀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤搔弄,失蹤者是張志新(化名)和其女友劉穎幅虑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顾犹,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡倒庵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年褒墨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擎宝。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡郁妈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绍申,到底是詐尸還是另有隱情噩咪,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布极阅,位于F島的核電站胃碾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏筋搏。R本人自食惡果不足惜书在,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拆又。 院中可真熱鬧儒旬,春花似錦、人聲如沸帖族。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竖般。三九已至甚垦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涣雕,已是汗流浹背艰亮。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挣郭,地道東北人迄埃。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像兑障,于是被迫代替她去往敵國和親侄非。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.元類 1.1.1類也是對象 在大多數(shù)編程語言中流译,類就是一組用來描述如何生成一個對象的代碼段逞怨。在Python中這...
    TENG書閱讀 1,275評論 0 3
  • 屬性property 私有屬性添加getter和setter方法 對于類對象的私有屬性,我們不能直接調(diào)用棍好,可以添加...
    冰封心動閱讀 589評論 0 0
  • 1.1裝飾器 裝飾器是程序開發(fā)中經(jīng)常會用到的一個功能仗岸,用好了裝飾器,開發(fā)效率如虎添翼借笙,所以這也是Python面試中...
    PythonMaO閱讀 481評論 1 5
  • 本文展示一些高級的Python設(shè)計結(jié)構(gòu)和它們的使用方法扒怖。在日常工作中,你可以根據(jù)需要選擇合適的數(shù)據(jù)結(jié)構(gòu)业稼,例如對快速...
    蝴蝶蘭玫瑰閱讀 767評論 0 4
  • 曾經(jīng)我閱讀了很多小說盗痒、散文 、詩歌低散,報刊摘要俯邓。有名人名家,瓊瑤 熔号、岑凱倫稽鞭、巴金、冰心引镊、張愛玲朦蕴、張海迪、郭沬若弟头、魯迅...
    吉英子閱讀 301評論 0 0