python學習筆記(方法、屬性、迭代器)

來源:互聯網
上載者:User

標籤:

準備工作

為了確保類是新型類,應該把 _metaclass_=type 入到你的模組的最開始

class NewStyle(object):
more_code_here
class OldStyle:
more_code_here

在這個兩個類中NewType是新類,OldType是屬於舊類,如果前面加上 _metaclass_=type ,那麼兩個類都屬於新類。

構造方法

 構造方法與其的方法不一樣,當一個對象被建立會立即調用構造方法。建立一個python的構造方法很簡答,只要把init方法,從簡單的init方法,轉換成魔法版本的_init_方法就可以了。

class FooBar:

def __init__(self):

self.somevar = 42

>>> f =FooBar()

>>> f.somevar

42

重寫一個一般方法和特殊的構造方法

每一個類都可能擁有一個或多個超類(父類),它們從超類那裡繼承行為方法。

class A:

def hello(self):

print ‘hello . I am A.‘

class B(A): 

pass>>> a = A()

>>> b = B()

>>>a.hello()

hello . I am A.

因為B類沒有hello方法,B類繼承了A類,所以會調用A 類的hello方法。 

在子類中增加功能功能的最基本的方式就是增加方法。但是也可以重寫一些超類的方法來自訂繼承的行為。如下:

class A:
def hello(self):
print "Hello,I‘m A."
class B(A):
def hello(self):
print ‘Hello,I\‘m B.‘

>>> b=B()
>>> b.hello()
Hello,I‘m B.
>>>

 重寫是繼承機制中的一個重要內容,對一於構造方法尤其重要。看下面的例子:

class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

----------------------

>>> b=Bird()
>>> b.eat()
Aaaah...
>>> b.eat()
No,thanks!
>>>

這個類中定義了鳥有吃的能力, 當它吃過一次後再次就會不餓了,通過上面的執行結果可以清晰的看到。

那麼用SongBird類來繼承Bird 類,並且給它添加歌唱的方法:

class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

class SongBird(Bird):
def __init__(self):
self.sound=‘Squawk!‘
def sing(self):
print self.sound

-----------

>>> sb=SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()

Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
sb.eat()
File "F:/python/myDemo/_init_.py", line 5, in eat
if self.hungry:
AttributeError: SongBird instance has no attribute ‘hungry‘
>>>

異常很清楚地說明了錯誤:SongBird沒有hungry特性。原因是這樣的:在SongBird中,構造方法被重寫,但新的構造方法沒有任何關於初始化hungry特性的代碼。為了達到預期的效果,SongBird的構造方法必須調用其超類Bird的構造方法來確保進行基本的初始化。

兩種方法實現:

調用未綁定的超類構造方法

class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

class SongBird(Bird):
def __init__(self):
Bird.__init__(self)
self.sound=‘Squawk!‘
def sing(self):
print self.sound

--------------------------

>>> sb=SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaaah...
>>> sb.eat()
No,thanks!
>>>

在SongBird類中添加了一行代碼Bird.__init__(self) 。 在調用一個執行個體的方法時,該方法的self參數會被自動綁定到執行個體上(這稱為Binder 方法)。但如果直接調用類的方法,那麼就沒有執行個體會被綁定。這樣就可以自由地提供需要的self參數(這樣的方法稱為未Binder 方法)。

通過將當前的執行個體作為self參數提供給未Binder 方法,SongBird就能夠使用其超類構造方法的所有實現,也就是說屬性hungry能被設定。

使用super函數

__metaclass__=type
class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

class SongBird(Bird):
def __init__(self):
super(SongBird,self).__init__()
self.sound=‘Squawk!‘
def sing(self):
print self.sound

----------

>>> sb=SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaaah...
>>> sb.eat()
No,thanks!
>>>

基本的映射和序列規則

序列和映射是對象的集合。

__len(self)__:

返回集合中所含項目的數量。對序列來說,這就是元素的個數,對映射來說,這就是鍵~值對的數量

__getitem__(self,key):

返回與所給鍵對應的值

__setitem__(self,key,value):

按一定方法儲存與key相關的value

__delitem__(self,key):

對一部分對象使用del語句時被調用,同時必須刪除和元素相關的鍵

def checkIndex(key):
‘‘‘
所給的鍵是能接受的索引嗎?
為了能被接受,鍵應該是一個非負的整數,如果它不是一個整數,會引發TypeError,如果它是負數,
則會引發IndexError(因為序列是無限長的)
‘‘‘
if not isinstance(key,(int,long)):
raise TypeError
if key <0:
raise IndexError

class ArithmeticSequence:
def __init__(self,start=0,step=1):
‘‘‘
初始化算術序列
‘‘‘
self.start=start #儲存開始值
self.step=step #儲存步長值
self.changed={} #沒有項被修改
def __getitem__(self,key):
checkIndex(key)
try:
return self.changed[key]
except KeyError:
return self.start+key*self.step

def __setitem__(self,key,value):
checkIndex(key)
self.changed[key]=value

------------------------------

>>> s=ArithmeticSequence(1,2)
>>> s[4]
9
>>> s[4]=2
>>> s[4]
2
>>> s[5]
11
>>> s[6]
13
>>> s[‘four‘]

Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
s[‘four‘]
File "F:/python/myDemo/_init_.py", line 21, in __getitem__
checkIndex(key)
File "F:/python/myDemo/_init_.py", line 8, in checkIndex
raise TypeError
TypeError
>>> s[-42]

Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
s[-42]
File "F:/python/myDemo/_init_.py", line 21, in __getitem__
checkIndex(key)
File "F:/python/myDemo/_init_.py", line 10, in checkIndex
raise IndexError
IndexError
>>>

子類化列表,字典和字串

class CounterList(list):
def __init__(self,*args):
super(CounterList,self).__init__(*args)
self.counter=0
def __getitem__(self,index):
self.counter+=1
return super(CounterList,self).__getitem__(index)

-------------------------

>>> cl=CounterList(range(10))
>>> cl
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> cl.reverse()
>>> cl
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del cl[3:6]
>>> cl
[9, 8, 7, 3, 2, 1, 0]
>>> cl.counter
0
>>> cl[4]+cl[2]
9
>>> cl[4]
2
>>> cl[2]
7
>>> cl.counter
4
>>>

屬性

訪問器是一個簡單的方法,它能夠使用getHeight 、setHeight 之樣的名字來得到或者重綁定一些特性。如果在訪問給定的特性時必須要採取一些行動,那麼像這樣的封裝狀態變數就很重要。如下:

class Rectangle:
def __init__(self):
self.width=0
self.height=0
def setSize(self,size):
self.width,self.height=size
def getSize(self):
return self.width,self.height

----------------

>>> r=Rectangle()
>>> r.width=10
>>> r.height=5
>>> r.getSize()
(10, 5)
>>> r.setSize((150,100))

>>> r.width
150

在上面的例子中,getSize和setSize方法一個名為size的假想特性的訪問器方法,size是由width 和height構成的元組。

property函數

__metaclass__=type
class Rectangle:
def __init__(self):
self.width=0
self.height=0
def setSize(self,size):
self.width,self.height=size
def getSize(self):
return self.width,self.height
size=property(getSize,setSize)

----------------------

>>> r=Rectangle()
>>> r.width=10
>>> r.height=5
>>> r.size
(10, 5)
>>> r.size=150,100
>>> r.width
150
>>>

在這個新版的Retangle 中,property 函數建立了一個屬性,其中訪問器函數被用作參數(先取值,然後是賦值),這個屬性命為size 。這樣一來就不再需要擔心是怎麼實現的了,可以用同樣的方式處理width、height 和size。

靜態方法和類成員方法

靜態方法定義沒有self參數,且能夠被類本身直接調用

類方法在定義時需要名為cls的類似於self的參數,類成員方法可以被類的具體對象調用。但cls參數是自動綁定到類的

__metaclass__=type
class MyClass:
def smeth():
print ‘This is a static method‘
smeth=staticmethod(smeth)

def cmeth(cls):
print ‘This is a class method of‘,cls
cmeth=classmethod(cmeth)

手動封裝和替換方法的技術看起來有些單調,為此引入了一個叫裝飾器的新文法,使用@操作符

__metaclass__=type
class MyClass:
@staticmethod
def smeth():
print ‘This is a static method‘

@classmethod
def cmeth(cls):
print ‘This is a class method of‘,cls

-------------------

>>> MyClass.smeth()
This is a static method
>>> MyClass.cmeth()
This is a class method of <class ‘__main__.MyClass‘>
>>>

__getattr__、__setattr__和它的朋友們

__getattr__(self,name):

當特性name被訪問且對象沒有相應的特性時被自動調用

__setattr__(self,name,value):

當試圖給特性name賦值時被自動調用

__delattr__(self,name):

當試圖刪除特性name時被自動調用

class Rectangle:
def __init__(self):
self.width=0
self.height=0
def __setattr_(self,name,value):
if name==‘size‘:
self.width,self.height=value
else:
self.__dict__[name]=value
def __getattr__(self,name):
if name==‘size‘:
return self.width,self.height
else:
raise AttributeError

 

迭代器

本節進行迭代器的討論。只討論一個特殊方法---- __iter__  ,這個方法是迭代器規則的基礎

迭代器規則

迭代的意思是重複做一些事很多次---就像在迴圈中做的那樣。__iter__ 方法返回一個迭代器,所謂迭代器就是具有next方法的對象,在調用next方法時,迭代器會返回它的下一個值。如果next方法被調用,但迭代器沒有值可以返回,就會引發一個StopIteration異常。

 

這裡是一個婓波那契數例,使用迭代器如下:

class Fibs:
def __init__(self):
self.a=0
self.b=1
def next(self):
self.a,self.b=self.b,self.a+self.b
return self.a
def __iter__(self):
return self

----------------

fibs=Fibs()

>>> for f in fibs:
if f>1000:
print f
break


1597
>>>

從迭代器得到序列

 除了在迭代器和可迭代對象上進行迭代外,還能把它們轉換為序列。在大部分能使用序列的情況下,能使用迭代器替換。

>>> class TestIterator:
value=0
def next(self):
self.value +=1
if self.value >10: raise StopIteration
return self.value
def __iter__(self):
return self


>>> ti=TestIterator()
>>> list(ti)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>

產生器建立產生器

def flatten(nested):
for sublist in nested:
for element in sublist:
yield element

>>> nested=[[1,2],[3,4],[5]]
>>> for num in flatten(nested):
print num


1
2
3
4
5
>>> list(flatten(nested))
[1, 2, 3, 4, 5]
>>>

遞迴產生器

上面建立的產生器只能處理兩層嵌套,為了處理嵌套使用了兩個for迴圈,如果要處理任意層的嵌套呢?例如,可以每層嵌套需要增加一個for迴圈,但不知道有幾層嵌套,所以必須把解決方案變得更靈活,現在可以用遞迴來解決

def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

-------------------

>>> list(flatten([[[1],2],3,4,[5,[6,7]],8]))
[1, 2, 3, 4, 5, 6, 7, 8]
>>>

當flatten被調用時有兩種情況:基本情況和需要遞迴的情況

在基本的情況中,函數被告知展開一個元素,這種情部下,for迴圈會引發一個TypeError 異常,產生會產生一個元素。

如果展開的是一個列表,那麼就需要特殊情況處理。程式必須遍曆所有的子列表,並對它們調用flatten。

上面的做法有一個問題:如果aa 是一個類似於字串的對象(字串、Unicode、UserString等),那麼它就是一個序列,不會引發TypeError,但是你不想對這樣的對象進行迭代。

為了處理這種情況,則必須在產生器的開始處添加一個檢查語句。試著將傳入的對象和一個字串拼接,看看會不會出現TypeError,這是檢查一個對象是不是類似於字串最簡單快速的方法。

def flatten(nested):
try:
try:nested+‘‘
except TypeError:pass
else: raise TypeError
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

--------------------

>>> list(flatten([‘foo‘,[‘bar‘,[‘baz‘]]]))
[‘foo‘, ‘bar‘, ‘baz‘]
>>>

如果nested+’’ 引發了一個TypError ,它就會被忽略。如果沒有引發TypeError,那麼內層try語句就會引發一個它自己的TypeError異常。

產生器方法

def repeater(value):
while True:
new=(yield value)
if new is not None: value=new

---------------------

>>> r=repeater(42)
>>> r.next()
42
>>> r.send(‘Hello,world!‘)
‘Hello,world!‘
>>>

產生器的另兩個方法:

throw方法(使用異常類型調用,還有可選的值以及回溯對象)用於在產生器內引發一個異常(在yield運算式中)

close 方法(調用時不用參數)用於停止產生器。

 

python學習筆記(方法、屬性、迭代器)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.