最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Python的一些整理

2020-06-12 22:43 作者:露保協(xié)  | 我要投稿

The Zen of Python, by Tim Peters(import this)


Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren't special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one-- and preferably only one --obvious way to do it.

Although that way may not be obvious at first unless you're Dutch.

Now is better than never.

Although never is often better than *right* now.

If the implementation is hard to explain, it's a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea -- let's do more of those!

關(guān)于Python的一些雜七雜八的remarks。

Python是Object-oriented的,所謂對(duì)象(Object)就是某一個(gè)類(Class)的實(shí)例(Instance)。調(diào)用對(duì)象方法(即綁定到對(duì)象的函數(shù))用instance.method(arguments),或者等價(jià)于Class.method(instance, arguments)。當(dāng)然有些不應(yīng)該在外面調(diào)用。類的好處在于封裝(保護(hù)內(nèi)部結(jié)構(gòu),只用接口去操作,不直接操作內(nèi)部)和抽象。整個(gè)Python語言就是圍繞著類和對(duì)象的概念構(gòu)造起來的。Python程序中的每一個(gè)實(shí)體都是一個(gè)object,屬于某個(gè)class。

Python是解釋型語言而不是編譯型的,所以在運(yùn)行期,動(dòng)態(tài)將代碼逐句解釋(interpret)為機(jī)器代碼(解釋器,interpreter)。這就帶來一些定義的先后問題。編譯型語言則是要通過編譯器先編譯為exe的。特別地,因?yàn)镻ython是不需要先編譯的,所以這決定了你調(diào)用函數(shù)之前得知道有這個(gè)函數(shù),所以執(zhí)行代碼前需要有要用到的函數(shù)的定義。但是程序執(zhí)行中,讀取到函數(shù)的定義的時(shí)候,這是記錄下函數(shù)的名單,知道有這么些函數(shù),但是不看函數(shù)里面的內(nèi)容,當(dāng)需要執(zhí)行函數(shù)的時(shí)候才去讀取這個(gè)函數(shù)里面的內(nèi)容。因此函數(shù)之間互相引用的時(shí)候并沒有順序要求(實(shí)際上也不可能有順序要求)。在調(diào)用函數(shù)的時(shí)候,會(huì)先建立局部名字空間,再執(zhí)行函數(shù)體。所以如果名字空間中出現(xiàn)什么問題(比如違背了定義唯一性原則),并不會(huì)按順序執(zhí)行下來,而是直接報(bào)錯(cuò)。return之后,撤銷局部名字空間(有例外:閉包)。

Python使用Off-side rule,用縮進(jìn)來定義結(jié)構(gòu)而不只是指示結(jié)構(gòu)。規(guī)范是使用4個(gè)空格來表示每級(jí)縮進(jìn)。使用Tab字符和其它數(shù)目的空格雖然都可以被解釋器識(shí)別,但不符合編碼規(guī)范。

Python是動(dòng)態(tài)語言,變量使用之前不需要類型聲明,通常變量的類型是被賦值的那個(gè)值的類型。?所以不像其他的靜態(tài)語言如CPascal那樣需要書寫聲明語句。

關(guān)于一些特殊的標(biāo)識(shí)。類定義中_foo這種屬性名或者函數(shù)名,表示是內(nèi)部使用,不應(yīng)該在類外面用類似game._turns = 1這種操作去修改一個(gè)對(duì)象。這并不是一個(gè)強(qiáng)制性的機(jī)制,只是相當(dāng)于一個(gè)人為的提醒。foo_這種則單純是為了避免和關(guān)鍵詞重復(fù)而做的常用的修飾。__foo這種是強(qiáng)制內(nèi)部使用的修飾,在類外面是根本不能找到的。而__foo__這種特殊方法名則是專門的,比如__init__,或者用來模擬加法的__add__等。

Python的表達(dá)式寫法和別的語言沒什么區(qū)別,有區(qū)別的地方隨便查一下就能知道,不是什么要緊的事情。

關(guān)于函數(shù)。首先是可變參數(shù)*args或**dictargs。*和**實(shí)際上是打包和拆分的動(dòng)作(packing/unpacking),def func(*args)是打包成tuple,def func(**dictargs)是打包成dict。調(diào)用的時(shí)候則是反過來,func(*tup)是拆分成多個(gè)參數(shù)輸入函數(shù)。

然后是參數(shù)傳遞。Python的賦值操作是把(變量)名字綁定到對(duì)象上,形實(shí)結(jié)合也是這種方式(call by object reference)。所以,如果形參綁定到一個(gè)可變的對(duì)象,則通過形參對(duì)此對(duì)象內(nèi)容的修改,在函數(shù)外也是可見的。如果形參綁定到一個(gè)不可變的對(duì)象,則通過形參是不能修改此對(duì)象內(nèi)容,但可以把形參重新綁定到其它對(duì)象上,這并不影響函數(shù)外的對(duì)象的值。[在Python中,數(shù)值類型int 、float、 字符串str 、元組tuple、boole 都是不可變對(duì)象
列表list、集合set、字典dict都是可變對(duì)象]

如果想要拷貝一個(gè)list,直接b = a會(huì)把object拷貝過來,這時(shí)候變動(dòng)b會(huì)同時(shí)變動(dòng)a。為了避免這種情況,需要用b = a.copy()來建立一個(gè)不用object的副本。這是很容易犯的錯(cuò)誤。

關(guān)于這點(diǎn)更深入的討論需要名字空間的概念。A namespace is a mapping from names to objects.這么一句話已經(jīng)說得很清楚了,Python的每一個(gè)實(shí)體就是一個(gè)object(屬于某一個(gè)class),另外有一個(gè)name指向它。理解的時(shí)候只要畫圖,從name指向object即可。所以說Python沒有指針,有的是namespace,每一個(gè)名字就相當(dāng)于一個(gè)指針,到處都是指針。Namespaces are one honking great idea,拿它來理解參數(shù)傳遞、作用域的時(shí)候很方便。global聲明全局變量(不一定要在全局作用域中有定義),nonlocal聲明由內(nèi)而外尋找(但非全局)的變量定義。這兩個(gè)聲明的區(qū)別還是非常大的。

跟C不一樣,python當(dāng)給變量賦值時(shí),系統(tǒng)會(huì)為這個(gè)值分配內(nèi)存空間,然后讓這個(gè)變量指向這個(gè)值;當(dāng)改變(不可變)變量的值時(shí),系統(tǒng)會(huì)為這個(gè)新的值分配另一個(gè)內(nèi)存空間,然后還是讓這個(gè)變量指向這個(gè)新值。C改變變量的值時(shí),改變的是內(nèi)存空間中的值,變量的地址是不改變的。

名字空間可以用dic()查看。

關(guān)于作用域的問題,搞清楚這個(gè)例子就理解地差不多了:

要注意這個(gè)建立局部名字空間的過程必須是每個(gè)變量都有唯一定義,如果既來自局部的賦值由來自向外找到的,會(huì)報(bào)錯(cuò)。這里面的幾個(gè)原則:1.賦值即定義(不能重復(fù)定義);2.全局和非局部聲明規(guī)則(可以建立“賦值即定義”的例外);3.定義唯一性規(guī)則;4.不同定義相互無關(guān)規(guī)則;5.作用域屏蔽規(guī)則。

上面這個(gè)例子的分析為:(畫一下namespace的圖更清楚。想象自己就是一個(gè)解釋器,一步步去解釋這個(gè)程序,碰到調(diào)用函數(shù)的時(shí)候先建立局部名字空間,依照定義[賦值,參數(shù),聲明]在局部函數(shù)空間里放進(jìn)新的名字,然后再去正式執(zhí)行函數(shù)的內(nèi)部過程

1.在全局名字空間放入x和y。

2.看了一下有f1和f2兩個(gè)函數(shù)。但是沒有進(jìn)去。

3.在全局名字空間放入w,然后調(diào)用f2。

4.來到f2的代碼。建立局部名字空間,有x(局部),z(局部),y則沒有再這個(gè)局部名字空間中定義(沒有賦值,沒有定義,不是參數(shù),也沒有全局或者非局部聲明)。然后調(diào)用f1。來到f1的代碼。

5.建立局部名字空間,放入x(局部),z(局部)。然后進(jìn)入g。

6.g的局部名字空間里放入u,v,y(全局),z(f1里的)。

7.這樣整個(gè)名字空間就搞清楚了(并沒有出現(xiàn)任何錯(cuò)誤)。然后再開始執(zhí)行。

8.最終結(jié)果為78。

關(guān)于Python的異常處理。所謂防御性程序設(shè)計(jì),就是盡可能讓每個(gè)代碼單元保護(hù)自己,對(duì)可能出現(xiàn)的異常做檢查和處理。一般用try配合except、else、finally完成。用raise拋出一個(gè)異常。with相當(dāng)于try...finally...的等價(jià)(不過表達(dá)式必須支持__enter__和__exit__操作,在with、快中自動(dòng)打開并在最后關(guān)閉)。

Python的list slices采取左閉右開的原則。

Python 手冊(cè)提倡的編程風(fēng)格要點(diǎn):?

  • 使用 4 個(gè)空格的縮進(jìn)(退格)形式,不用 tab 字符(更小的退格不夠清楚;如果用更大的退格,幾層嵌套后有效位置就會(huì)變得太少,不方便)。

  • 設(shè)法把每行安排在 79 個(gè)字符以內(nèi)(程序行不要太長,以方便閱讀)。?

  • 在不同的函數(shù)定義、類定義之間,在函數(shù)里大塊的代碼段上下加入空行。

  • 盡可能不把注釋與其他內(nèi)容寫在同一行(注釋獨(dú)立成行)。

  • 給函數(shù)寫文檔字符串(專門用于寫程序里說明的串,用一對(duì)包含三個(gè)雙引號(hào)的序列括起的文本)。

  • 在運(yùn)算符兩邊和逗號(hào)后面加一個(gè)空格。

  • 采用統(tǒng)一的名字寫法給函數(shù)和類取名。習(xí)慣上是類名采用 ClassName 的形式(分段的名字,每段用大寫字母作為第一個(gè)字符),函數(shù)名采用 function_name 的形式(分段的名字,用下劃線連接各段)。

  • 程序里的標(biāo)識(shí)符不要用非 ASCII 碼字符(雖然 Python 默認(rèn)采用 UTF-8 作為基礎(chǔ)字符集)。

關(guān)于類,也就是新定義的數(shù)據(jù)類型。類定義中,需要定義對(duì)象的構(gòu)造操作(__init__)、解析操作(各種實(shí)例方法)、變動(dòng)操作(各種實(shí)例方法,可變對(duì)象/不可變對(duì)象)。調(diào)用對(duì)象方法(即綁定到對(duì)象的函數(shù))用instance.method(arguments)或Class.method(instance, arguments),這里的方法是實(shí)例方法(針對(duì)實(shí)例的)。在類定義中還會(huì)用到靜態(tài)方法,用修飾符@staticmethod標(biāo)記,它不含self參數(shù),所以調(diào)用的時(shí)候只能用Class.method(arguments)。它只不過是一個(gè)定義在類里面的普通局部函數(shù)罷了。第三種method是類方法,@classmethod,顧名思義是針對(duì)class而不是instance的,定義的時(shí)候用def method(cls, arguments),調(diào)用的時(shí)候用Class.method(arguments),它直接讀取類里面的信息,而不是某一個(gè)實(shí)例對(duì)象的信息。這三個(gè)method其實(shí)看名字就非常直觀,很容易理解。

關(guān)于迭代器。所謂迭代器(iterator),簡(jiǎn)單來說就是能用next()迭代的對(duì)象。也可以用iter()去生成一個(gè)迭代器。從面向?qū)ο缶幊痰慕嵌热ダ斫?,迭代器就是這樣一個(gè)class的實(shí)例,這個(gè)class里面定義了兩個(gè)方法 __iter__() 與 __next__()?,并且可能通過raise一個(gè)StopIteration異常去結(jié)束迭代。而生成器函數(shù)就是用yield去產(chǎn)生一個(gè)迭代器的。需要區(qū)分的是可迭代對(duì)象(iterable),它并不是一個(gè)特殊的class類型,而是一類class,包括了list、set、dict和迭代器,只要能夠放在for后面做循環(huán)的,就叫做可迭代對(duì)象。

另外需要說明的是,我們經(jīng)常用的range()生成的不是一個(gè)迭代器,而是一個(gè)「range類型」的可迭代對(duì)象,和list之類是類似的。所以不要試圖用next()去處理一個(gè)range對(duì)象。

迭代器,可迭代對(duì)象,生成器三個(gè)概念要區(qū)分清楚。

關(guān)于Python的函數(shù)式編程:comprehension,匿名函數(shù),閉包,生成器。匿名函數(shù)比如lambda x, y: x**2 + y**2,這種只是為了方便。生成器包括tuple comprehension和generator function,它是一種特殊的迭代器(通過兩種特有的機(jī)制自動(dòng)實(shí)現(xiàn)了“迭代器協(xié)議”(即__iter__和next方法),不需要再手動(dòng)實(shí)現(xiàn)兩方法)。描述式(comprehension),顧名思義,是通過描述的方式構(gòu)建一個(gè)組合對(duì)象。比如n**2 for n in range(10),完全是和自然語言一樣的描述。但是這個(gè)表達(dá)式是不完整的,要加上修飾:如果用[]修飾,就變成list comprehension,結(jié)果是一個(gè)list;如果用()修飾,就變成tuple comprehension,結(jié)果是一個(gè)generator。類似的還有dictionary conprehension,比如{n : n**3 for n in range (10)}。生成器包括tuple comprehension和generator function。至于閉包(closure)這個(gè)東西,值得仔細(xì)說。這是一個(gè)比較特殊的東西,可以理解為生成器的擴(kuò)展版本。它就是在函數(shù)里定義了一個(gè)局部函數(shù)并返回它,這樣一來,我們調(diào)用大函數(shù)之后,局部名字空間并沒有被拋棄(這是一個(gè)反例),因?yàn)槊看沃笠{(diào)用里面的小函數(shù)的時(shí)候,必須在這個(gè)局部名字空間里干活。之后就可以在這個(gè)名字空間里邊多次調(diào)用小函數(shù),結(jié)果就像生成器一樣可以迭代。所以說,閉包其實(shí)就相當(dāng)于把一個(gè)函數(shù)局限在一個(gè)局部名字空間里反復(fù)調(diào)用。顧名思義,就是一個(gè)enclosure住的函數(shù)。








Python的一些整理的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
双牌县| 清远市| 临湘市| 南部县| 长岭县| 日喀则市| 贞丰县| 长宁县| 南阳市| 通榆县| 绥宁县| 永靖县| 内丘县| 读书| 武川县| 库伦旗| 广州市| 镇雄县| 沿河| 上思县| 庐江县| 江陵县| 都昌县| 晋州市| 光泽县| 东安县| 潮州市| 长春市| 张北县| 辉南县| 中牟县| 丹阳市| 湘西| 五河县| 桂林市| 永川市| 开原市| 榆树市| 萨嘎县| 弥渡县| 隆尧县|