如果乙個類想被用於for … in迴圈,類似list或tuple那樣,就必須實現乙個__iter__()
方法,該方法返回乙個迭代物件,然後,python的for迴圈就會不斷呼叫該迭代物件的__next__()
方法拿到迴圈的下乙個值,直到遇到stopiteration
錯誤時退出迴圈。 比如以斐波那契數列為例,寫乙個fib類,可以作用於for迴圈:
class
fib(
object):
def__init__
(self)
: self.a, self.b =0,
1def
__iter__
(self)
:return self
def__next__
(self)
: self.a, self.b = self.b, self.a + self.b
if self.a >
10000
:raise stopiteration(
)return self. a
for n in fib():
print
(n)
fib例項雖然能作用於for迴圈,看起來和list有點像,但是,把它當成list來使用還是不行,它不能像list那樣按下標取出元素,要表現得像list那樣按照下標取出元素,需要實現__getitem__()
方法:
class
fib(
object):
def__getitem__
(self, n)
: a, b =1,
1for x in
range
(n):
a, b = b, a + b
return a
現在,就可以按下標訪問數列的任意一項了:
>>
> f = fib(
)>>
> f[0]
1>>
> f[1]
1>>
> f[2]
2>>
> f[3]
3>>
> f[10]
89>>
> f[
100]
573147844013817084101
__getitem__()
方法也可以實現list的切片操作,不過要加乙個判斷:
class
fib(
object):
def__getitem__
(self, n):if
isinstance
(n,int):
# n是索引
a, b =1,
1for x in
range
(n):
a, b = b, a + b
return a
ifisinstance
(n,slice):
# n是切片
start = n.start
stop = n.stop
if start is
none
: start =
0 a, b =1,
1 l =
for x in
range
(stop)
:if x >= start:
a, b = b, a + b
return l
>>
> f = fib(
)>>
> f[0:
5][1
,1,2
,3,5
]>>
> f[:10
][1,
1,2,
3,5,
8,13,
21,34,
55]
當我們需要定義常量時,乙個辦法是用大寫變數通過整數來定義,例如月份:
jan =
1feb =
2mar =3.
..nov =
11dec =
12
好處是簡單,缺點是型別是int,並且仍然是變數。更好的方法是為這樣的列舉型別定義乙個class型別,然後,每個常量都是class的乙個唯一例項。可以通過enum來實現:
from enum import enum
month = enum(
'month',(
'jan'
,'feb'
,'mar'
,'apr'
,'may'
,'jun'
,'jul'
,'aug'
,'sep'
,'oct'
,'nov'
,'dec'
))
列舉它的所有成員:
for name, member in month.__members__.items():
print
(name,
'=>'
, member,
',', member.value)
value的值預設從1開始,要自定義列舉型別,可以從enum派生出自定義類:
from enum import enum, unique
class
weekday
(enum)
: sun =
0# sun的value被設定為0
mon =
1 tue =
2 wed =
3 thu =
4 fri =
5 sat =
6
既可以用成員名稱引用列舉常量,又可以直接根據value的值獲得列舉常量。
動態語言和靜態語言最大的不同,就是函式和類的定義,不是編譯時定義的,而是執行時動態建立的。我們說class的定義是執行時動態建立的,而建立class的方法就是使用type()
函式。比如,我們可以通過type()
函式建立出hello類,而無需通過class hello(object)...
的定義:
>>
>
deffn
(self, name=
'world'):
# 先定義函式..
.print
('hello, %s.'
% name)..
.>>
> hello =
type
('hello',(
object,)
,dict
(hello=fn)
)# 建立hello class
>>
> h = hello(
)>>
> h.hello(
)hello, world.
>>
>
print
(type
(hello)
)<
class
'type'
>
>>
>
print
(type
(h))
<
class
'__main__.hello'
>
要建立乙個class物件,type()函式依次傳入3個引數:
class的名稱;
繼承的父類集合,注意python支援多重繼承,如果只有乙個父類,別忘了tuple的單元素寫法;
class的方法名稱與函式繫結,這裡是把函式fn繫結到方法名hello上。
除了使用type()
動態建立類以外,要控制類的建立行為,還可以使用metaclass。metaclass,直譯為元類,簡單的解釋就是:當我們定義了類以後,就可以根據這個類建立出例項,所以:先定義類,然後建立例項。但是如果我們想建立出類呢?那就必須根據metaclass建立出類,所以:先定義metaclass,然後建立類。
用metaclass給mylist類增加乙個add()
方法:
# metaclass是類的模板,所以必須從`type`型別派生:
class
listmetaclass
(type):
def__new__
(cls, name, bases, attrs)
: attrs[
'add']=
return
type
.__new__(cls, name, bases, attrs)
有了listmetaclass,我們在定義類的時候還要指示使用listmetaclass來定製類,傳入關鍵字引數metaclass:
class
mylist
(list
, metaclass=listmetaclass)
:pass
__new__()
方法接收到的引數依次是:
當前準備建立的類的物件;
類的名字;
類繼承的父類集合;
類的方法集合。
python高階用法 Python高階用法
python高階用法 三元表示式 x 10 y 20 print x if x y else y x 100 y 20 print x if x y else y 列表推導式和生成器 列表推導式 print i for i in range 10 print i 2 for i in range 1...
python高階用法
建立dict i for i in range 10 pandas給乙個dataframe的列沒有在另乙個dataframe的列中出現的列賦值為nan df a.loc df a.isin df b col name unique col name nan pandas做笛卡爾積 df a valu...
Python 函式的高階用法
python 中一切皆物件,我們定義的名稱僅僅是與這些物件繫結的識別符號。函式也不例外,它們也是物件,同樣可以被繫結到不同的名稱。def welcome info print info return welcome 輸出函式 welcome 的記憶體位址 f welcome 將 welcome 的記...