1.屬性訪問class Rectangle:<br /> def __init__(self):<br /> self.width = 0<br /> self.height = 0<br /> def setSize(self, size):<br /> self.width, self.height = size #我的理解是自動組成Tuple<br /> def getSize(self):<br /> return self.width, self.height #同上<br />
這種技術文法上不錯,但它將程式與一種accessor緊耦合了。
函數property能夠解決這個問題:class Rectangle(object):<br /> def __init__(self):<br /> self.width = 0<br /> self.height = 0<br /> def setSize(self, size):<br /> self.width, self.height = size<br /> def getSize(self):<br /> return self.width, self.height<br /> size = property(getSize, setSize) # getter在前,setter在後<br />
原理:其實property是個滿足descriptor協議的類(這樣的類實現了__get__, __set__和__delete__方法)
下面測試accessor:
r = Rectangle()
r.width = 10
r.height = 5
r.size ---> (10, 5)
r.size = 150, 100
r.width ---> 150
實際上property函數也可以使用0個、1個、3個、4個參數。
0個 —— resulting property 既不可讀也不可寫
1個 —— resulting property 僅僅可讀
3個 —— 第3個參數是用來刪除某個屬性的方法(此方法無參數)
4個 —— 第4個參數是documentation string
以上4個參數的名稱為 fget, fset, fdel以及doc。
property(fget, fset, fdel, doc)
作者最後說,The moral is this: With new-style classes, you should use property rather than accessors.
2. 靜態方法和類方法
靜態方法是沒有self參數的方法,而且可以由類直接調用。
類方法是使用了一個類似於self的參數cls。
以下是一個小例子:
__metaclass__ = type #申明使用new-style類<br />class MyClass:<br /> def smeth():<br /> print 'This is a static method'<br /> smeth = staticmethod(smeth)<br /> def cmeth(cls):<br /> print 'This is a class method of', cls<br /> cmeth = classmethod(cmeth)<br />
在Python 2.4中, 引入了一個新的文法:decorators
__metaclass__ = type<br />class MyClass:<br /> @staticmethod<br /> def smeth():<br /> print 'This is a static method'<br /> @classmethod<br /> def cmeth(cls):<br /> print 'This is a class method of', cls<br />
以下為調用:
MyClass.smeth()
---> This is a static method
MyClass.cmeth()
---> This is a class method of <class '__main__.MyClass'>
靜態方法和類方法之所以在Python中不太重要,是因為它未能在早期版本中實現。但在像factory函數中,它還是非常有用的。
3.__getattr__, __setattr__, and Friends
__getattribute__(self, name): 當屬性name被訪問時,被自動調用(Works correctly on new-style classes only.) #Note:TODO
__getattr__(self, name):當屬性name被訪問時,被自動調用
__setattr__(self, name, value):當屬性name要被賦值value時,被自動調用
__delattr__(self, name): 當屬性name要被刪除時,被自動調用
這些magic方法在處理多個屬性的時候是很有用的,但是If you have a choice, though, stick with property.
一個使用例子:
class Rectangle:<br /> def __init__(self):<br /> self.width = 0<br /> self.height = 0<br /> def __setattr__(self, name, value):<br /> if name == 'size':<br /> self.width, self.height = value<br /> else:<br />#將成員變數映射為Dictionary中的一個Pair,也是magic attribute,避免了無限調用__setattr__<br /> self.__dict__[name] = value<br /> def __getattr__(self, name):<br /> if name == 'size':<br /> return self.width, self.height<br /> else:<br /> raise AttributeError #如果想使你的類能夠與內建函數hasattr和getattr配合使用正確,則這裡很重要<br />
4.迭代器Iterators
實現了__iter__方法的對象就可以和Sequences和Dictionaries一樣在for迴圈中迭代。
__iter__方法返回一個迭代器,這是一個擁有next方法的任意對象,可調用但無參數。如果調用迭代器時已經沒有了傳回值,但會引發一個StopIteration異常。
!下面是一個可迭代的類樣本:
class Fibs:<br /> def __init__(self):<br /> self.a = 0<br /> self.b = 1<br /> def next(self):<br /> self.a, self.b = self.b, self.a+self.b<br /> return self.a<br /> def __iter__(self):<br /> return self<br />
下面在for迴圈中使用這個迭代:
fibs = Fibs()<br />for f in fibs:<br /> if f > 1000:<br /> print f<br /> break<br />#內建函數iter可以從一個可迭代對象中獲得迭代器iter(obj) Extracts an iterator from an iterable object.
除了使用迭代器遍曆對象,還可以將其轉換成Sequence:
class TestIterator:<br /> value = 0<br /> def next(self):<br /> self.value += 1<br /> if self.value > 10: raise StopIteration<br /> return self.value<br /> def __iter__(self):<br /> return self<br />...
ti = TestIterator()
list(ti) ---> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
5.Generators(本質也是一種迭代)
#書中後面給出了定義:A generator is a function that contains the keyword yield. When called, the generator function returns a generator, which is a special type of iterator.
Making a Generator:
nested = [[1, 2], [3, 4], [5]] #一個嵌套List<br />def flatten(nested):<br /> for sublist in nested:<br /> for element in sublist:<br /> yield element #凡是包含yield的函數都稱為generator,意味著你一次可以“收穫”多個變數,而非普通函數一次只能返回一個變數<br />
或者
list(flatten(nested))
---> [1, 2, 3, 4, 5]
遞迴Generator:(可以用來表示某種樹結構)
def flatten(nested):<br /> try:<br /> for sublist in nested:<br /> for element in flatten(sublist):<br /> yield element<br /> except TypeError: #已經不可迭代,通常是已經到達樹葉<br /> yield nested<br />
更簡潔的調用方式:
list(flatten([[[1],2],3,4,[5,[6,7]],8]))
---> [1, 2, 3, 4, 5, 6, 7, 8]
以上遞迴方式有一個隱患,當迭代string-like對象時,因為它是一個sequence,所以不會引起TypeError異常。(不過不應該迭代String-like對象),下面是一種更為安全的定義方式:
def flatten(nested):<br /> try:<br /> # Don't iterate over string-like objects:<br /> try: nested + '' #通過看是否能夠與一個string合并,看是否是一個String-like對象<br /> except TypeError: pass #是string-like對象,跳過餘下程式<br /> else: raise TypeError #不是string-like對象,則拋出一個TypeError讓外層來捕獲並yield<br /> for sublist in nested:<br /> for element in flatten(sublist):<br /> yield element<br /> except TypeError:<br /> yield nested<br />
使用樣本:
list(flatten(['foo', ['bar', ['baz']]]))
---> ['foo', 'bar', 'baz']
generators包含兩總分:generator函數和generator迭代器。generator函數是包含yield的函數; generator迭代器是generator函數的傳回值,和其它迭代器一樣使用。
def simple_generator():
yield 1
...
simple_generator
---> <function simple_generator at 153b44> #這裡被看成一個函數
simple_generator()
---> <generator object at 1510b0> #加括弧則看成一個generator