摘要:進(jìn)階細(xì)節(jié)根據(jù)慕課網(wǎng)七月老師視頻整理一切皆對(duì)象對(duì)與來(lái)說(shuō),一切皆對(duì)象,包括函數(shù)。閉包的意義在于返回了一個(gè)現(xiàn)場(chǎng),如果沒(méi)有閉包,很容易被外部的變量所影響。重復(fù)定義可見(jiàn)此時(shí)返回了不再是閉包了。注意該方法的返回值只能是布爾類(lèi)型,即或。
Python進(jìn)階細(xì)節(jié)
根據(jù)慕課網(wǎng)七月老師視頻整理
一切皆對(duì)象對(duì)與Python來(lái)說(shuō),一切皆對(duì)象,包括函數(shù)。在其他語(yǔ)言比如c++中,函數(shù)只是一段可執(zhí)行的代碼,只要你獲得入口地址就可以調(diào)用這段代碼。但是Python中不一樣,Python中一切皆對(duì)象。Python中的函數(shù),可以作為另一個(gè)函數(shù)的參數(shù)傳入到另外一個(gè)函數(shù)里,也可以當(dāng)作另外一個(gè)函數(shù)的返回值,甚至可以賦值給一個(gè)變量。
def a(): pass print(type(a))閉包# 可見(jiàn)是一個(gè)class,是一個(gè)類(lèi)。
閉包指的是:函數(shù)+環(huán)境變量(環(huán)境變量不能是全局變量)。
python在函數(shù)內(nèi)部還可以定義函數(shù),但該函數(shù)作用域只在外部函數(shù)內(nèi)部有效,除非作為外部函數(shù)的返回值被返回,在外部函數(shù)的外部用一個(gè)變量接收后就可以調(diào)用它了。
def curve_pre(): a = 25 # 這里定義了環(huán)境變量 def curve(x): return a*x*x return curve a = 10 # 在外部定義了a為10 f = curve_pre() print(f(2)) print(f.__closure__) # 可以通過(guò)這個(gè)內(nèi)置變量來(lái)查看閉包里的內(nèi)容 print(f.__closure__[0].cell_contents) 100 (,) 25 |
可見(jiàn)返回了一個(gè)對(duì)象。你再在外面定義了變量,也不會(huì)改變閉包內(nèi)的環(huán)境變量。
閉包的意義在于返回了一個(gè)現(xiàn)場(chǎng),如果沒(méi)有閉包,很容易被外部的變量所影響。
閉包返回現(xiàn)場(chǎng)的環(huán)境變量,不能在閉包里定義的函數(shù)里面再被定義了,而且函數(shù)里必須要有調(diào)用環(huán)境變量的地方,否則就不叫做閉包了。
def f1(): a = 20 def f2(): a = 10 # 重復(fù)定義 return a return f2 f = f1() print(f.__closure__) None # 可見(jiàn)此時(shí)返回了None,不再是閉包了。本質(zhì)上是認(rèn)為此時(shí)a被認(rèn)為是一個(gè)局部變量,不再是環(huán)境變量了! -------------------------------------------------------------------------- # 如果想要環(huán)境變量在函數(shù)里被改變,可以這樣: def f1(): a = 25 def f2(): nonlocal a # nonlocal關(guān)鍵字強(qiáng)制讓a不再為局部變量,跳到上一級(jí)作為了環(huán)境變量。 a = a + 10 return a return f2 f = f1() print(f.__closure__) print(f()) print(f()) print(f()) (2. 閉包的優(yōu)點(diǎn),) 35 45 55 # 可以看到a的值是可以保存的,這是因?yàn)殚]包的環(huán)境變量具有保存現(xiàn)場(chǎng)的功能,記憶住上次調(diào)用的狀態(tài),所以可以這樣做。 --------------------------------------------------------------------------- def f1(): a = 20 def f2(): return 2 # 里面不再調(diào)用a了 return f2 f = f1() print(f.__closure__) None # 可見(jiàn)此時(shí)仍然不是閉包 --------------------------------------------------------------------------- def f1(): a = 20 def f2(): s = a+20 return 2 return f2 f = f1() print(f.__closure__) ( | ,) # 可見(jiàn)就算返回值里不包括a,但是只要調(diào)用了,就可以是一個(gè)閉包。 |
從閉包可以看出函數(shù)式編程的優(yōu)點(diǎn)。如果出現(xiàn)需要保存值進(jìn)行迭代的情況,就不得不定義一個(gè)全局變量來(lái)保存上一次的值。但是在閉包里不需要使用到全局變量,只需要閉包里定義的環(huán)境變量即可記憶上一次的狀態(tài),這樣就具有了封閉性,否則過(guò)多的使用全局變量會(huì)使代碼變得混亂。這里再注意一個(gè)問(wèn)題:
a = 10 def f1(x): a_new = a + x a = a_new print(f1(5)) Traceback (most recent call last): File "c4.py", line 7, in3. 閉包的一個(gè)經(jīng)典例子print(f1(5)) File "c4.py", line 4, in f1 a_new = a + x UnboundLocalError: local variable "a" referenced before assignment # 看起來(lái)美滋滋其實(shí)報(bào)錯(cuò)了。再Python里,如果再定義了a的話,無(wú)論是在哪里,在定義的時(shí)候系統(tǒng)會(huì)默認(rèn)a是局部變量不再是全局變量了。所以在執(zhí)行代碼的時(shí)候,就會(huì)出現(xiàn)了找不到局部變量a的情況,因?yàn)閒1中第一段代碼中用到了局部變量a,但是此時(shí)還沒(méi)有定義啊。 ---------------------------------------------------------------------- # 可以這么解決: a = 10 def f1(x): global a # 定義global關(guān)鍵字強(qiáng)制認(rèn)為是全局變量 a_new = a + x a = a_new return a print(f1(5)) print(f1(10)) 15 25 # 可見(jiàn)這時(shí)候全局變量起到了保存的功能,但相對(duì)閉包,就顯得很Low了。
def testFun(): temp = [lambda x : i*x for i in range(4)] return temp for everyLambda in testFun(): print (everyLambda(2)) # 運(yùn)行后結(jié)果竟然是: 6 6 6 6
這里testfun()返回一個(gè)temp,temp是一個(gè)列表,everyLambda每次返回的都是temp里列表的值,參數(shù)2賦給x。
三元表達(dá)式python中的三元表達(dá)式和其他語(yǔ)言中的不太一樣。
條件為真時(shí)返回的結(jié)果 if 判斷條件 else 條件為假時(shí)返回的結(jié)果
x if x > y else y
其他很多語(yǔ)言中是這么定義的:
x > y ? x:y
map不是一個(gè)函數(shù)而是一個(gè)類(lèi)。map和lambda表示結(jié)合起來(lái)一起用會(huì)非常好。
map(func, *iterables) --> map object
iterables是可迭代的類(lèi)型,序列和元組都可以。*號(hào)表示是可變參數(shù),可以傳入多個(gè)不同值的取值。
a = [1,2,3,4,5] def square(x): return x*x r = map(square, a) print(r) print(list(r))匿名函數(shù)(lambda表達(dá)式)
lambda表達(dá)式也叫做匿名函數(shù)。
lambda的定義:lambda parameter_list: expression
expression意思是表達(dá)式,所以后面只能是表達(dá)式,不能是語(yǔ)句,比如賦值語(yǔ)句等是不可以的。
lambda表達(dá)式最后返回的是表達(dá)式計(jì)算出的值,和return后是一樣的。
def add(x, y): return x+y lambda x, y : x + y
lambda表達(dá)式一般和三元表達(dá)式和map連接在一起用會(huì)更加整潔。
x = 1,2,3,4,5,6 y = 1,2,3,4,5,6 r = map(lambda x,y:x+y, x,y) print(tuple(r)) (2, 4, 6, 8, 10, 12)reduce函數(shù)
reduce 是一個(gè)函數(shù)。
def reduce(function, sequence, initial=None)
function : 這里需要注意函數(shù)必須且只能有兩個(gè)參數(shù)
sequence: 序列
initial: 初始值
reduce的含義是連續(xù)調(diào)用函數(shù)進(jìn)行連續(xù)計(jì)算
from functools import reduce # 需要引入這個(gè)函數(shù)才可以使用 list_x = ["1","2","3"] r = reduce(lambda x,y:x+y, list_x, "a") print(r) a123 # 執(zhí)行情況 :(("a"+"1")+"2")+"3" # 每次執(zhí)行完一次函數(shù)的結(jié)果在下一次調(diào)用函數(shù)的時(shí)候會(huì)傳入到函數(shù)的參數(shù)中進(jìn)行計(jì)算。初始值是給出的開(kāi)始的參數(shù)之一。filter類(lèi)
class filter(function or None, iterable)
表示過(guò)濾不符合條件的值。當(dāng)函數(shù)返回為T(mén)rue時(shí)保留,F(xiàn)alse時(shí)剔除。當(dāng)函數(shù)為None時(shí),剔除調(diào)iterable中本來(lái)就為False的值
# ord()返回ascII碼值 list_x = ["a", "B", "c", "D"] r = filter(lambda x: False if ord(x)>64 and ord(x)<91 else True, list_x) print(list(r)) ["a", "c"]裝飾器
編寫(xiě)代碼一個(gè)原則是:對(duì)修改是封閉的,對(duì)拓展是開(kāi)放的。
如果想在很多個(gè)函數(shù)里,每個(gè)函數(shù)都實(shí)現(xiàn)相同的功能,用裝飾器是最方便的,不用在每個(gè)函數(shù)里重復(fù)定義,而且調(diào)用起來(lái)很方便,和“裝飾”的意思很像。
import time def decorator(func): def wrapper(*args, **kw): # *args是可變參數(shù),**kw是可變關(guān)鍵字參數(shù),這樣可以接受除了有默認(rèn)參數(shù)類(lèi)型以外所有類(lèi)型的函數(shù)參數(shù) print(time.time()) func(*args, **kw) return wrapper # 就是一個(gè)閉包,傳入的函數(shù)func是環(huán)境變量 @decorator # @ 是一個(gè)語(yǔ)法糖 def f1(func_name): print("this is f1" + func_name) @decorator def f2(func_name1, func_name2): print("this is f2" + func_name1 + func_name2) @decorator def f3(func_name1, func_name2="f3",*args, **kw): print("this is f3"+func_name1+func_name2) print(kw) f1("f1") # 可見(jiàn)雖然在定義的時(shí)候麻煩了一些,但是調(diào)用的時(shí)候很方便。 f2("f2","f2") f3("f3","f3",a="1",b="2",c="3") # 可變關(guān)鍵字參數(shù) 1519276076.973657 #時(shí)間戳 this is f1f1 1519276076.9746575 this is f2f2f2 1519276076.9746575 this is f3f3f3 {"a": "1", "b": "2", "c": "3"}生成器
通過(guò)列表生成式可以直接創(chuàng)建一個(gè)列表,但是我們?nèi)绻幌朐L問(wèn)前面幾個(gè)元素,不想利用后面的元素,我們可以定義一個(gè)生成器(generator),一邊循環(huán)一邊計(jì)算,有一種方法很簡(jiǎn)單,只要把列表生成式的[]改為()就可以創(chuàng)建一個(gè)generator.
L = [x * x for x in range(10)] L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] g = (x * x for x in range(10)) gat 0x104feab40>
如果需要打印出來(lái)元素,可以通過(guò)生成器的next()方法。
g.next() 0 g.next() 1 g.next() 4
generator是可以迭代的:
g = (x * x for x in range(10)) for n in g: ... print n ... 0 1 4 9
可以把一個(gè)函數(shù)寫(xiě)成生成器,把return改為yield:
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 fib(6)for n in fib(6): ... print n ... 1 1 2 3 5 8
定義成生成器后,generator的執(zhí)行流程和函數(shù)并不一樣,函數(shù)是順序執(zhí)行,遇到return語(yǔ)句或者最后一行函數(shù)語(yǔ)句就返回。而變成generator的函數(shù),在每次調(diào)用next()的時(shí)候執(zhí)行,遇到y(tǒng)ield語(yǔ)句返回,再次執(zhí)行時(shí)從上次返回的yield語(yǔ)句處繼續(xù)執(zhí)行。
另外一個(gè)例子:
def odd(): ... print "step 1" ... yield 1 ... print "step 2" ... yield 3 ... print "step 3" ... yield 5 ... o = odd() o.next() step 1 1 o.next() step 2 3 o.next() step 3 5 o.next() Traceback (most recent call last): File "字典來(lái)代替swich", line 1, in StopIteration
Python中沒(méi)有swich這種結(jié)構(gòu),可以用字典來(lái)實(shí)現(xiàn)。
day = 0 def get_monday(): return "Monday" def get_Tuseday(): return "Tuseday" def get_Wednesday(): return "Wednesday" def default(): return "Unknow" #返回函數(shù)可以定義跟多操作,也可以直接返回值 swicher = { 0: get_monday, 1: get_Tuseday, 2: get_Wednesday } # 字典的get方法可以獲取鍵對(duì)應(yīng)的值,如果鍵不存在則返回指定的默認(rèn)值 day_time = swicher.get(day, default())() # 后面再加一個(gè)括號(hào)來(lái)調(diào)用函數(shù) print(day_time) monday列表推導(dǎo)式
對(duì)于列表推導(dǎo)式,其實(shí)不只是列表,也可以是元組,集合,字典進(jìn)行推倒
a = [1,2,3,4,5] b = [i**2 for i in a if i>=3] print(b) [9,16,25] --------------------------------------------------- # 對(duì)于字典可以這樣: sdict = { "q":"烈焰沖擊", "w":"天女散花", "e":"致命一擊" } dic = {value:key for key,value in sdict.items()} # 最外面加花括號(hào)就是字典或者集合 dic1 = [key for key,value in sdict.items()] dic2 = (key for key,value in sdict.items()) print(dic) print(dic1) print(dic2) # 如果是元組,元組是不可遍歷的對(duì)象,所以需要下面這樣取出對(duì)象 for i in dic2: print(i,end=" ") {"烈焰沖擊": "q", "天女散花": "w", "致命一擊": "e"} ["q", "w", "e"]Noneat 0x0000021A3430E150> q w e
None代表空,并不是False,也不是[],""
print(type(None)) print(type(False)) print(type([])) print(type(""))
我們可以看見(jiàn),這些在本質(zhì)上都是不一樣的,類(lèi)型都不一樣,只不過(guò)我們?cè)谶M(jìn)行邏輯判斷的時(shí)候,有時(shí)會(huì)像下面這樣做:
a = None/false/[]/"" if not a: ..... # 判斷的時(shí)候會(huì)這樣做
不建議使用if a is None:這種語(yǔ)句,我們可以看到類(lèi)型是不一樣的,有時(shí)會(huì)出錯(cuò)。
對(duì)象存在不一定是True在上面對(duì)None的分析中,在邏輯判斷的時(shí)候之所以可以判斷None為False,是因?yàn)槊總€(gè)對(duì)象和bool類(lèi)型之間都是有聯(lián)系的,所以可以進(jìn)行邏輯判斷。但是我們自定義的對(duì)象卻不一定了,返回True和False因不同的對(duì)象而不同。我們自定義的對(duì)象,如類(lèi),和我們的內(nèi)置方法有關(guān)系。
類(lèi)中有兩個(gè)內(nèi)置方法會(huì)影響對(duì)類(lèi)的布爾類(lèi)型的取值:
__len__:這個(gè)內(nèi)置方法返回的是類(lèi)的長(zhǎng)度,外部調(diào)用len()時(shí)會(huì)返回該方法的返回值,返回值只有布爾類(lèi)型或者int類(lèi)型。
__bool__:這個(gè)內(nèi)置方法返回的類(lèi)的bool類(lèi)型的取值,當(dāng)這個(gè)方法在類(lèi)里面定義以后,返回值只看其返回值,__len__的返回值不再起作用。注意該方法的返回值只能是布爾類(lèi)型,即True或False。
class Rest(): def __len__(self): return 5 def __bool__(self): return False print(len(Rest())) print(bool(Rest())) 5 False裝飾器的副作用
加上裝飾器后會(huì)改變函數(shù)的名字。
def decorator(func): def wrapper(): print("this is decorator") func() return wrapper @decorator def f1(): print(f1.__name__) # 打印函數(shù)名字,不加裝飾器是f1 f1() this is decorator wrapper
可見(jiàn)會(huì)出錯(cuò),加上裝飾器后,如果不想改變名字,可以這樣做:
from functools import wraps def decorator(func): @wraps(func) def wrapper(): print("this is decorator") func() return wrapper @decorator def f1(): print(f1.__name__) # 打印函數(shù)名字,不加裝飾器是f1 f1() this is decorator f1可哈希(hashable)對(duì)象和不可變性(immutable)
可哈希(hashable)和不可改變性(immutable)
如果一個(gè)對(duì)象在自己的生命周期中有一哈希值(hash value)是不可改變的,那么它就是可哈希的(hashable)的,因?yàn)檫@些數(shù)據(jù)結(jié)構(gòu)內(nèi)置了哈希值,每個(gè)可哈希的對(duì)象都內(nèi)置了__hash__方法,所以可哈希的對(duì)象可以通過(guò)哈希值進(jìn)行對(duì)比,也可以作為字典的鍵值和作為set函數(shù)的參數(shù),但是list是unhashable,所以不可以作為字典的鍵值。所有python中所有不可改變的的對(duì)象(imutable objects)都是可哈希的,比如字符串,元組,也就是說(shuō)可改變的容器如字典,列表不可哈希(unhashable)。我們用戶所定義的類(lèi)的實(shí)例對(duì)象默認(rèn)是可哈希的(hashable),它們都是唯一的,而hash值也就是它們的id()。
哈希
它是一個(gè)將大體量數(shù)據(jù)轉(zhuǎn)化為很小數(shù)據(jù)的過(guò)程,甚至可以?xún)H僅是一個(gè)數(shù)字,以便我們可以用在固定的時(shí)間復(fù)雜度下查詢(xún)它,所以,哈希對(duì)高效的算法和數(shù)據(jù)結(jié)構(gòu)很重要。
不可改變性
它指一些對(duì)象在被創(chuàng)建之后不會(huì)因?yàn)槟承┓绞礁淖?,特別是針對(duì)任何可以改變哈希對(duì)象的哈希值的方式
聯(lián)系
因?yàn)楣fI一定是不可改變的,所以它們對(duì)應(yīng)的哈希值也不改變。如果允許它們改變,,那么它們?cè)跀?shù)據(jù)結(jié)構(gòu)如哈希表中的存儲(chǔ)位置也會(huì)改變,因此會(huì)與哈希的概念違背,效率會(huì)大打折扣
具體的我們可以參考官方文檔和以下博客:
關(guān)于python內(nèi)置__eq__函數(shù)的探索
關(guān)于可哈希對(duì)象的理解
1.賦值方法:
list1 = [1,2,3] list2 = list1 print(id(list1),id(list2)) 2577180416904 2577180416904
可見(jiàn)這和在c語(yǔ)言中不一樣,二者的id是一樣的,換句話說(shuō),你改變 list2,同時(shí)也會(huì)改變 list1
2.淺拷貝:
import copy list1 = [1,2,3] list2 = copy.copy(list1) print(id(list1),id(list2)) list2.append(4) print(list1,list2) 2522465131400 2522465130824 [1, 2, 3] [1, 2, 3, 4]
但是淺拷貝,對(duì)于里面的元素,如果是不可變類(lèi)型,會(huì)直接拷貝,但是對(duì)于可變類(lèi)型只是指向它而已,例如看下面的代碼:
import copy list1 = [1,2,[1,2,3]] list2 = copy.copy(list1) print(id(list1),id(list2)) list2[2].append(4) print(list1,list2) 2710366738760 2710368236680 [1, 2, [1, 2, 3, 4]] [1, 2, [1, 2, 3, 4]] # 都變化了
3.深拷貝
import copy list1 = [1,2,[1,2,3]] list2 = copy.deepcopy(list1) print(id(list1),id(list2)) list2[2].append(4) print(list1,list2) 1660389185864 1660390683784 [1, 2, [1, 2, 3]] [1, 2, [1, 2, 3, 4]]
可見(jiàn)深拷貝才是真正的拷貝。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44702.html
摘要:很簡(jiǎn)單,這個(gè)模塊實(shí)現(xiàn)了開(kāi)辟一塊共享內(nèi)存空間,就好比中的方法一樣,有興趣的同學(xué)可以去查閱。查了下資料,返回的對(duì)象控制了一個(gè)進(jìn)程,可用于多進(jìn)程之間的安全通信,其支持的類(lèi)型有和等。 有關(guān)于 multiprocessing 中共享變量的問(wèn)題 現(xiàn)在的cpu都很強(qiáng)大,比方我用的至強(qiáng)2620有24核可以同時(shí)工作,并行執(zhí)行進(jìn)程程序。這在計(jì)算密集型的程序是很需要的,如沙漠中的綠洲,令人重獲新生。那么,問(wèn)...
摘要:楚江數(shù)據(jù)是專(zhuān)業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲(chóng)技術(shù)以供學(xué)習(xí),。本文來(lái)源知乎作者路人甲鏈接楚江數(shù)據(jù)提供網(wǎng)站數(shù)據(jù)采集和爬蟲(chóng)軟件定制開(kāi)發(fā)服務(wù),服務(wù)范圍涵蓋社交網(wǎng)絡(luò)電子商務(wù)分類(lèi)信息學(xué)術(shù)研究等。 楚江數(shù)據(jù)是專(zhuān)業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲(chóng)技術(shù)以供學(xué)習(xí),http://www.chujiangdata.com。 第一:Python爬蟲(chóng)學(xué)習(xí)系列教程(來(lái)源于某博主:htt...
摘要:學(xué)單片機(jī)多去官網(wǎng)上查資料,下載手冊(cè),像我入門(mén)的單片機(jī)經(jīng)常去官網(wǎng),還有學(xué)的系列板子,公司的官網(wǎng)的官方例程給的很詳細(xì),在英文視角閱讀對(duì)你大有益處。 目錄 1.C語(yǔ)言經(jīng)典 2.單片機(jī)系列 3.Python方面 4.嵌入式LWip協(xié)議 5.Android 6.C++經(jīng)典書(shū)籍 7.Linux開(kāi)發(fā) ...
摘要:可選控制所返回的函數(shù)的屬性。模式被用到,因?yàn)槎x函數(shù)需要用多個(gè)語(yǔ)句。聚合全部?jī)?nèi)容,并將動(dòng)態(tài)創(chuàng)建的函數(shù)指定給一個(gè)變量。寫(xiě)完之后,我偶然發(fā)現(xiàn),在自己列的計(jì)劃轉(zhuǎn)載清單中,有這一篇相關(guān)的文章,它介紹了動(dòng)態(tài)定義函數(shù)的方法。 showImg(https://segmentfault.com/img/bVbp3eZ?w=4272&h=2828);標(biāo)題:Python Tips: Dynamic fun...
閱讀 1714·2021-11-12 10:36
閱讀 1628·2021-11-12 10:36
閱讀 3454·2021-11-02 14:46
閱讀 3826·2019-08-30 15:56
閱讀 3586·2019-08-30 15:55
閱讀 1472·2019-08-30 15:44
閱讀 1061·2019-08-30 14:00
閱讀 2746·2019-08-29 18:41