Python類的高階用法

2021-09-08 07:21:39 字數 4758 閱讀 2044

如果乙個類想被用於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 的記...