1、Python的函數傳參
Python中所有的變量都可以理解為內存中一個對象的“引用”,或者,也可以看似C中的void *的感覺。這里記住的是類型是屬於對象的,而不是變量。對象分為兩種:
可更改的:list,dict;
不可更改的:strings,tuples,numbers;
當向函數傳遞一個參數,即引用的時候:
1)如果該參數是函數外一個不可變的對象的引用,則函數執行完之后,在函數外打印的是原來的值,與函數對該引用做什么事情無關。
2)如果該函數是函數外一個可變的對象的引用,則函數執行完之后,在函數外打印的是該函數多該引用所執行的內存空間改變的結果。
2、普通方法、實例方法、類方法和靜態方法
普通方法:在一個Python環境中,獨立於類或者對象的函數,可直接導入文件中的方法直接使用。
實例方法:實例定義來類中,使用之前先通過類實例化一個對象,然后在通過對象調用實例方法。與c++類似。實例方法的第一個參數默認傳入一個self,這個self會與實例綁定。
類方法:與實例方法的調用方式類似,不同的是類方法第一個參數默認傳入一個類cls,而不是對象。
靜態方法:對於靜態方法其實和普通的方法一樣,不需要對誰進行綁定,唯一的區別是調用的時候需要使用a.static_foo(x)或者A.static_foo(x)來調用.

靜態方法修飾:@staticmethod
類方法修飾:@classmethod
1 #普通方法 2 def foo(x): 3 pass 4 5 class A(object): 6 #實例方法 7 def foo(self,x): 8 pass 9 10 #類方法 11 @classmethod 12 def class_foo(cls,x): 13 pass 14 15 #靜態方法 16 @staticmethod 17 def static_foo(x): 18 pass
3、類屬性和實例屬性
類屬性就是供類使用的屬性,實例屬性就是供實例使用的屬性。
由於Python是動態語言,根據類創建的實例可以任意綁定屬性。
給實例綁定屬性的方法是通過實例變量,或者通過self變量:
1 class Student(object): 2 def __init__(self, name): 3 self.name = name 4 5 s = Student('Bob') 6 s.score = 90
但是,如果Student類本身需要綁定一個屬性呢?可以直接在class中定義屬性,這種屬性是類屬性,歸Student類所有
1 class Student(object): 2 name = 'Student'
當我們定義了一個類屬性后,這個屬性雖然歸類所有,但類的所有實例都可以訪問到。來測試一下:
>>> class Student(object): ... name = 'Student' ... >>> s = Student() # 創建實例s >>> print(s.name) # 打印name屬性,因為實例並沒有name屬性,所以會繼續查找class的name屬性 Student >>> print(Student.name) # 打印類的name屬性 Student >>> s.name = 'Michael' # 給實例綁定name屬性 >>> print(s.name) # 由於實例屬性優先級比類屬性高,因此,它會屏蔽掉類的name屬性 Michael >>> print(Student.name) # 但是類屬性並未消失,用Student.name仍然可以訪問 Student >>> del s.name # 如果刪除實例的name屬性 >>> print(s.name) # 再次調用s.name,由於實例的name屬性沒有找到,類的name屬性就顯示出來了 Student
從上面的例子可以看出,在編寫程序的時候,千萬不要對實例屬性和類屬性使用相同的名字,因為相同名稱的實例屬性將屏蔽掉類屬性,但是當你刪除實例屬性后,再使用相同的名稱,訪問到的將是類屬性
4、Python自省
自省就是面向對象的語言所寫的程序在運行時,所能知道對象的類型.簡單一句就是運行時能夠獲得對象的類型.比如type(),dir(),getattr(),hasattr(),isinstance()
5、python的各種推導式(列表推導式、字典推導式、集合推導式)
推導式comprehensions(又稱解析式),是Python的一種獨有特性。推導式是可以從一個數據序列構建另一個新的數據序列的結構體。 共有三種推導,在Python2和3中都有支持:
- 列表(list)推導式
- 字典(dict)推導式
- 集合(set)推導式
使用[]生成list
基本格式
variable = [out_exp_res for out_exp in input_list if out_exp == 2] out_exp_res: 列表生成元素表達式,可以是有返回值的函數。 for out_exp in input_list: 迭代input_list將out_exp傳入out_exp_res表達式中。 if out_exp == 2: 根據條件過濾哪些值可以。
注意:表達式是用方括號擴起來,說明生成的是一個列表。
實例一: multiples = [i for i in range(30) if i % 3 is 0] print(multiples) # Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
實例二: def squared(x): return x*x multiples = [squared(i) for i in range(30) if i % 3 is 0] print multiples # Output: [0, 9, 36, 81, 144, 225, 324, 441, 576, 729]
使用()生成generator
將列表推導式的 [] 改成 () 即可得到生成器。以下會介紹生成器。
multiples = (i for i in range(30) if i % 3 is 0) print(type(multiples)) # Output: <type 'generator'>
字典推導式
字典推導和列表推導的使用方法是類似的,只不中括號該改成大括號。
基本格式
variable = {out_exp_res for out_exp in input_list if out_exp == 2}
out_exp_res: 列表生成元素表達式,可以是有返回值的函數。
for out_exp in input_list: 可迭代的input_list將out_exp傳入out_exp_res表達式中。
if out_exp == 2: 根據條件過濾哪些值可以。
例子一:大小寫key合並
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {
k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)
for k in mcase.keys()
if k.lower() in ['a','b']
}
print mcase_frequency
# Output: {'a': 17, 'b': 34}
例子二:快速更換key和value
mcase = {'a': 10, 'b': 34}
mcase_frequency = {v: k for k, v in mcase.items()}
print mcase_frequency
# Output: {10: 'a', 34: 'b'}
集合推導式
它們跟列表推導式也是類似的。 唯一的區別在於它使用大括號{}。
squared = {x**2 for x in [1, 1, 2]}
print(squared)
# Output: set([1, 4])
6、生成器generator
通過列表生成式,我們可以直接創建一個列表。但是,受到內存限制,列表容量肯定是有限的。而且,創建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數元素占用的空間都白白浪費了。
所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出后續的元素呢?這樣就不必創建完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱為生成器:generator。
要創建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]改成(),就創建了一個generator:在第五點中有陳述。
如果要一個一個打印出來,可以通過next()函數獲得generator的下一個返回值:
>>> next(g) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) 9 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
不斷調用next(g)實在是太變態了,正確的方法是使用for循環,因為generator也是可迭代對象:
>>> g = (x * x for x in range(10)) >>> for n in g: ... print(n) ... 0 1 4 9
第二種generator的獲取方法:
比如,著名的斐波拉契數列(Fibonacci),除第一個和第二個數外,任意一個數都可由前兩個數相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契數列用列表生成式寫不出來,但是,用函數把它打印出來卻很容易:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done'
仔細觀察,可以看出,fib函數實際上是定義了斐波拉契數列的推算規則,可以從第一個元素開始,推算出后續任意的元素,這種邏輯其實非常類似generator。
也就是說,上面的函數和generator僅一步之遙。要把fib函數變成generator,只需要把print(b)改為yield b就可以了:
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return 'done'
如果一個函數定義中包含yield關鍵字,那么這個函數就不再是一個普通函數,而是一個generator。
這里,最難理解的就是generator和函數的執行流程不一樣。函數是順序執行,遇到return語句或者最后一行函數語句就返回。而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。
同樣的,把函數改成generator后,我們基本上從來不會用next()來獲取下一個返回值,而是直接使用for循環來迭代:
>>> for n in fib(6): ... print(n)
但是用for循環調用generator時,發現拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中:
>>> g = fib(6) >>> while True: ... try: ... x = next(g) ... print('g:', x) ... except StopIteration as e: ... print('Generator return value:', e.value) ... break ... g: 1 g: 1 g: 2 g: 3 g: 5 g: 8 Generator return value: done
7、Python中單下划線和雙下划線
__foo__:一種約定,Python內部的名字,用來區別其他用戶自定義的命名,以防沖突.
_foo:一種約定,用來指定變量私有.程序員用來指定私有變量的一種方式.
__foo:這個有真正的意義:解析器用_classname__foo來代替這個名字,以區別和其他類相同的命名.
8、字符串格式化:%和format函數格式化的用法
.format在許多方面看起來更便利.對於%最煩人的是它無法同時傳遞一個變量和元組.你可能會想下面的代碼不會有什么問題:

但是,如果name恰好是(1,2,3),它將會拋出一個TypeError異常.為了保證它總是正確的,你必須這樣做:

但是有點丑..format就沒有這些問題.你給的第二個問題也是這樣,.format好看多了.
自python2.6開始,新增了一種格式化字符串的函數str.format(),可謂威力十足。那么,他跟之前的%型格式化字符串相比,有什么優越的存在呢?讓我們來揭開它羞答答的面紗。
詳見如下文章:http://www.jb51.net/article/63672.htm
9、迭代器和生成器
看廖雪峰的Python教程:
凡是可作用於for循環的對象都是Iterable類型;
凡是可作用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;
集合數據類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。
Python的for循環本質上就是通過不斷調用next()函數實現的,例如:
generator是非常強大的工具,在Python中,可以簡單地把列表生成式改成generator,也可以通過函數實現復雜邏輯的generator。
要理解generator的工作原理,它是在for循環的過程中不斷計算出下一個元素,並在適當的條件結束for循環。對於函數改成的generator來說,遇到return語句或者執行到函數體最后一行語句,就是結束generator的指令,for循環隨之結束。
請注意區分普通函數和generator函數,普通函數調用直接返回結果:
>>> r = abs(6) >>> r 6
generator函數的“調用”實際返回一個generator對象:
>>> g = fib(6) >>> g <generator object fib at 0x1022ef948>
10、*args and **kwargs(可變參數)
用*args和**kwargs只是為了方便並沒有強制使用它們.
當你不確定你的函數里將要傳遞多少參數時你可以用*args.例如,它可以傳遞任意數量的參數:
def print_everything(*args): for count,thing int enumerate(args): print '{0},{1}'.format(count,thing); print_everything('apple','banana','cabbage'); output: 0,apple 1,banana 2,cabbage
相似的,**kwargs允許你使用沒有事先定義的參數名:
