不管你是待業(yè)還是失業(yè),在這個被互聯(lián)網(wǎng)圍繞的時代里,選擇python元編程,就多了一項技能,還怕找不到工作?,還怕不好找工作?小編就來告訴你這個專業(yè)的優(yōu)勢到底體現(xiàn)在哪里:Python元編程:控制你想控制的一切,不要輕易使用元編程,學習python編程需要安裝哪些軟件???。
1.Python元編程:控制你想控制的一切
很多人不理解“元編程”是個什么東西,關于它也沒有一個十分準確的定義。這篇文章要說的是Python里的元編程,實際上也不一定就真的符合“元編程”的定義。只不過我無法找到一個更準確的名字來代表這篇文章的主題,所以就借了這么一個名號。副標題是控制你想控制的一切,實際上這篇文章講的都是一個東西,利用Python提供給我們的特性,盡可能的使代碼優(yōu)雅簡潔。具體而言,通過編程的方法,在更高的抽象層次上對一種層次的抽象的特性進行修改。首先說,Python中一切皆對象,老生常談。還有,Python提供了許多特殊方法、元類等等這樣的“元編程”機制。像給對象動態(tài)添加屬性方法之類的,在Python中根本談不上是“元編程”,但在某些靜態(tài)語言中卻是需要一定技巧的東西。我們來談些Python程序員也容易被搞糊涂的東西。我們先來把對象分分層次,通常我們知道一個對象有它的類型,老早以前Python就將類型也實現(xiàn)為對象。這樣我們就有了實例對象和類對象。這是兩個層次。稍有基礎的讀者就會知道還有元類這個東西的存在,簡言之,元類就是“類”的“類”,也就是比類更高層次的東西。這又有了一個層次。還有嗎? vs RunTime如果我們換個角度,不用非得和之前的三個層次使用同樣的標準。我們再來區(qū)分兩個東西:和RunTime,它們之間也并非界限分明,顧名思義,就是兩個時刻,導入時和運行時。當一個模塊被導入時,會發(fā)生什么?在全局作用域的語句(非定義性語句)被執(zhí)行。函數(shù)定義呢?一個函數(shù)對象被創(chuàng)建,但其中的代碼不會被執(zhí)行。類定義呢?一個類對象被創(chuàng)建,類定義域的代碼被執(zhí)行,類的方法中的代碼自然也不會被執(zhí)行。執(zhí)行時呢?函數(shù)和方法中的代碼會被執(zhí)行。當然你要先調(diào)用它們。元類所以我們可以說元類和類是屬于的,import一個模塊之后,它們就會被創(chuàng)建。實例對象屬于RunTime,單import是不會創(chuàng)建實例對象的。不過話不能說的太絕對,因為如果你要是在模塊作用域?qū)嵗?,實例對象也是會被?chuàng)建的。只不過我們通常把它們寫在函數(shù)里面,所以這樣劃分。如果你想控制產(chǎn)生的實例對象的特性該怎么做?太簡單了,在類定義中重寫__init__方法。那么我們要控制類的一些性質(zhì)呢?有這種需求嗎?當然有!經(jīng)典的單例模式,大家都知道有很多種實現(xiàn)方式。要求就是,一個類只能有一個實例。最簡單的實現(xiàn)方法是這樣的class _Spam: def __init__(self): print("Spam!!!") _spam_singleton =None def Spam(): global _spam_singleton if _spam_singleton is not None: return _spam_singleton else: _spam_singleton = _Spam() return _spam_singleton工廠模式,不太優(yōu)雅。我們再來審視一下需求,要一個類只能有一個實例。我們在類中定義的方法都是實例對象的行為,那么要想改變類的行為,就需要更高層次的東西。元類在這個時候登場在合適不過了。前面說過,元類是類的類。也就是說,元類的__init__方法就是類的初始化方法。 我們知道還有__call__這個東西,它能讓實例像函數(shù)那樣被調(diào)用,那么元類的這個方法就是類在被實例化時調(diào)用的方法。代碼就可以寫出來了:class Singleton(type): def __init__(self, *args, **kwargs): self._instance = None super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self._instance is None: self._instance = super().__call__(*args, **kwargs) return self._instance else: return self._instance class Spam(metaclass=Singleton): def __init__(self): print("Spam!!!")主要有兩個地方和一般的類定義不同,一是Singleton的基類是type,一是Spam定義的地方有一個metaclass=Singleton。type是什么?它是object的子類,object是它的實例。也就是說,type是所有類的類,也就是最基本的元類,它規(guī)定了一些所有類在產(chǎn)生時需要的一些操作。所以我們的自定義元類需要子類化type。同時type也是一個對象,所以它又是object的子類。有點不太好理解,大概知道就可以了。裝飾器我們再來說說裝飾器。大多數(shù)人認為裝飾器是Python里面最難理解的概念之一。其實它不過就是一個語法糖,理解了函數(shù)也是對象之后。就可以很輕易的寫出自己的裝飾器了。from functools import wraps def print_result(func): @wraps(func) def wrappper(*args, **kwargs): result = func(*args, **kwargs) print(result) return result return wrappper @print_result def add(x, y): return x + y #相當于: #add = print_result(add) add(1, 3)這里我們還用到了一個裝飾器@wraps,它是用來讓我們返回的內(nèi)部函數(shù)wrapper和原來的函數(shù)擁有相同的函數(shù)簽名的,基本上我們在寫裝飾器時都要加上它。我在注釋里寫了,@decorator這樣的形式等價于func=decorator(func),理解了這一點,我們就可以寫出更多種類的裝飾器。比如類裝飾器,以及將裝飾器寫成一個類。def attr_upper(cls): for attrname,value in cls.__dict__.items(): if (value,str): if not value.('__'): setattr(cls,attrname,bytes.decode(str.encode(value).upper())) return cls @attr_upper class Person: sex = 'man' print(Person.sex) # MAN注意普通的裝飾器和類裝飾器實現(xiàn)的不同點。對數(shù)據(jù)的抽象--描述符如果我們想讓某一些類擁有某些相同的特性,或者說可以實現(xiàn)在類定義對其的控制,我們可以自定義一個元類,然后讓它成為這些類的元類。如果我們想讓某一些函數(shù)擁有某些相同的功能,又不想把代碼復制粘貼一遍,我們可以定義一個裝飾器。那么,假如我們想讓實例的屬性擁有某些共同的特點呢?有人可能會說可以用property,當然可以。但是這些邏輯必須在每個類定義的時候都寫一遍。如果我們想讓這些類的實例的某些屬性都有相同的特點的話,就可以自定義一個描述符類。關于描述符,這篇文章 : def __init__(self, _type): self._type = _type def __get__(self, instance, cls): if instance is None: return self else: return getattr(instance, self.name) def __set_name__(self, cls, name): self.name = name def __set__(self, instance, value): if not (value, self._type): raise TypeError('Expected' + str(self._type)) instance.__dict__[self.name] = value class Person: age = (int) name = (str) def __init__(self, age, name): self.age = age self.name = name jack = Person(15, 'Jack') jack.age = '15' # 會報錯 在這里面有幾個角色,是一個描述符類,Person的屬性是描述符類的實例,看似描述符是作為Person,也就是類的屬性而不是實例屬性存在的。但實際上,一旦Person的實例訪問了同名的屬性,描述符就會起作用。需要注意的是,在Python3.5及之前的版本中,是沒有__set_name__這個特殊方法的,這意味著如果你想要知道在類定義中描述符被起了一個什么樣的名字,是需要在描述符實例化時顯式傳遞給它的,也就是需要多一個參數(shù)。不過在Python3.6中,這個問題得到了解決,只需要在描述符類定義中重寫__set_name__這個方法就好了。還需要注意的是__get__的寫法,基本上對instance的判斷是必需的,不然會報錯。原因也不難理解,就不細說了??刂谱宇惖膭?chuàng)建——代替元類的方法在Python3.6中,我們可以通過實現(xiàn)__init_subclass__特殊方法,來自定義子類的創(chuàng)建,這樣我們就可以在某些情況下擺脫元類這個討厭的東西。class : = [] def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) cls..append(cls) class Plugin1(): pass class Plugin2(): pass小結(jié)諸如元類等元編程對于大多數(shù)人來說有些晦澀難懂,大多數(shù)時候也無需用到它們。但是大多數(shù)框架背后的實現(xiàn)都使用到了這些技巧,這樣才能讓使用者寫出來的代碼簡潔易懂。如果你想更深入的了解這些技巧,可以參看一些書籍例如《Fluent Python》、《Python Cookbook》(這篇文章有的內(nèi)容就是參考了它們),或者看官方文檔中的某些章節(jié)例如上文說的描述符HowTo,還有Data Model一節(jié)等等?;蛘咧苯涌碢ython的源碼,包括用Python寫的以及CPython的源碼。記住,只有在充分理解了它們之后再去使用,也不要是個地方就想著使用這些技巧。
2.不要輕易使用元編程
本文轉(zhuǎn)載自: Common Lisp 里的 loop 宏就。一方面,它體現(xiàn)了宏的強大;另一方面,它展現(xiàn)了宏能給我們帶來的復雜。熟悉 C/Java 語言都知道循環(huán)是語言本身提供的關鍵字,一般是 for。但 Lisp 語言特別精簡,它認為循環(huán)只是遞歸的一個特殊形式,語言本身也不包含任何的循環(huán)關鍵字。于是有人用宏實現(xiàn)了 loop ,它讓我們能以近乎英語的方式在 Lisp 里寫循環(huán)語句,這里從 這里 摘抄一個例子:(loop for x in '(a b c d e) for y from 1 if (> y 1) do (format t ", ~A" x) else do (format t "~A" x) )你不需要了解這段代碼的含義,重要的是了解像 for .. in .., if ... do ... else ... do 這樣的語法并不是 Lisp 提供的,而是 loop 宏實現(xiàn)的,這些語法離開了 loop 也就不再合法。我們看到 loop 宏讓我們能在 Lisp 語言不支持的情況下享受到近乎現(xiàn)代語言中才包含的 for ... in ... 語法。要知道在 Java 中有兩種 for 語句:for (int i=0; i < array.length; i++) { System.out.println("Element: " + array[i]); } for (String element : array) { System.out.println("Element: " + element); }而第二種直到 JDK 1.5 才加入。在這之前,廣大的 Java 程序員即使已經(jīng)認識到了第二種寫法的優(yōu)越性,卻也只能無奈等到語言支持才行。而 Lisp 程序員很快就能通過宏來實現(xiàn)自己理想中的語法。然而光明與黑暗共生,宏給我們帶來極大自由的同時,也意味著分裂。每個程序員心中理想的語法各不相同,這就意味著一千個程序員會有一千種語法。在 Lisp 中宏是非常容易編寫的(不代表容易正確編寫),意味著真的會存在一千種語法,大家誰也不服誰,因此造成分裂;但在 C/Java 中,沒有宏的支持,雖然有一千種想法,但大家都寫不出編譯器,于是只能集中討論,統(tǒng)一語法了,再靠大牛們實現(xiàn)了。而現(xiàn)實就是如此,Common Lisp 嘗試標準化 Lisp,但依舊有人不認同這種理念,例如 Scheme,Common Lisp 標準化的 loop 宏在 Scheme 中就被拋棄了。照進現(xiàn)實前車之鑒,后事之師。Lisp 強大的功能,反面導致了語言的分裂,最終使 Lisp 也慢慢退出歷史舞臺(主流地位),這也被稱為 The Lisp Curse。而現(xiàn)實中我們也常常會被元編程的強大和便捷誘惑,我認為使用元編程之前*考慮會不會造成更多的分裂。最基本的就是不應該自己造語法(DSL)。當然,我的出發(fā)點是多人團隊,較大的項目,考慮的是整體的發(fā)展。如果是個人學習,或者小團隊等,元編程或許能成為你出眾的秘密武器。但大的項目講求的是合作,DSL 造成的分裂實在是得不償失,尤其是作者離開后,維護的工作經(jīng)常后繼無人。近兩年接觸到的 rust 也是提供了宏的支持,雖然不像 Lisp 宏一樣容易編寫,但從功能的角度上依舊特別強大,而且模板宏寫起來也很容易,于是有人想寫一個類似 Python 的 dict 語法:let x = dict!( "hello" => "world" ,"hello2" => "world2" );但我個人并不喜歡這種語法,我認為 Clojure 似的語法更簡潔 dict!("hello": "world")。那在團隊里引入這兩個宏就會引起代碼的分裂,后來人在看代碼時就會很困惑。不利于團隊的建設。*分享在 知乎 上看到的引用:Hygienic Macros and Compile-Time : A first-class macro system, or support for compile-time code execution in general, is something we may consider in future releases. We don’t want the existence of a macro system to be a that reduces the incentive for making the core language great. 表示不希望用宏來解決語言本身的缺陷。而我的理解是當我們希望用宏(或其它元編程手段)時,很可能是我們使用的語言缺少了某些特性,例如 Java 的 lombok 提供的 @Getter/@Setter 等注解,就是因為 Java 沒有相應的語言層面的支持,看看 Kotlin 的支持你就會明白的。但即便有了宏(或元編程)的支持,你有信心能做出讓整個團隊都信服的設計嗎?如果沒有,*還是慎重為之。寫在*雖然是吐糟,但這篇之間重寫了三次。想表達的內(nèi)容很多,最終還是把其它的東西刪去, Lisp curse 還是我想真正表達的東西吧,其它的基礎知識,有緣人自然會從其它地方學會。年輕人容易崇拜力量,我們也別忘了陽光還有影子。
3.學習python編程需要安裝哪些軟件?
你好,需要安裝Python平臺和一個順手的代碼編輯器,Python平臺2.6、2.7、3.0+的版本皆可,如果你在windows下代碼編輯器可以使用、PythonWin、自帶的IDLE也行,但智能感不夠強,在Linux下,可以考慮Vim,如果需要,請追問或私信留下郵箱,我將所需的工具和一些教材發(fā)給你。
就拿大數(shù)據(jù)說話,優(yōu)勢一目了然,從事IT行業(yè),打開IT行業(yè)的新大門,找到適合自己的培訓機構(gòu),進行專業(yè)和系統(tǒng)的學習。