W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
你想在類被定義的時(shí)候就初始化一部分類的成員,而不是要等到實(shí)例被創(chuàng)建后。
在類定義時(shí)就執(zhí)行初始化或設(shè)置操作是元類的一個(gè)典型應(yīng)用場(chǎng)景。本質(zhì)上講,一個(gè)元類會(huì)在定義時(shí)被觸發(fā),這時(shí)候你可以執(zhí)行一些額外的操作。
下面是一個(gè)例子,利用這個(gè)思路來(lái)創(chuàng)建類似于 collections
模塊中的命名元組的類:
import operator
class StructTupleMeta(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
for n, name in enumerate(cls._fields):
setattr(cls, name, property(operator.itemgetter(n)))
class StructTuple(tuple, metaclass=StructTupleMeta):
_fields = []
def __new__(cls, *args):
if len(args) != len(cls._fields):
raise ValueError('{} arguments required'.format(len(cls._fields)))
return super().__new__(cls,args)
這段代碼可以用來(lái)定義簡(jiǎn)單的基于元組的數(shù)據(jù)結(jié)構(gòu),如下所示:
class Stock(StructTuple):
_fields = ['name', 'shares', 'price']
class Point(StructTuple):
_fields = ['x', 'y']
下面演示它如何工作:
>>> s = Stock('ACME', 50, 91.1)
>>> s
('ACME', 50, 91.1)
>>> s[0]
'ACME'
>>> s.name
'ACME'
>>> s.shares * s.price
4555.0
>>> s.shares = 23
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>
這一小節(jié)中,類 StructTupleMeta
獲取到類屬性 _fields
中的屬性名字列表,然后將它們轉(zhuǎn)換成相應(yīng)的可訪問(wèn)特定元組槽的方法。函數(shù) operator.itemgetter()
創(chuàng)建一個(gè)訪問(wèn)器函數(shù),然后 property()
函數(shù)將其轉(zhuǎn)換成一個(gè)屬性。
本節(jié)最難懂的部分是知道不同的初始化步驟是什么時(shí)候發(fā)生的。StructTupleMeta
中的 __init__()
方法只在每個(gè)類被定義時(shí)被調(diào)用一次。cls
參數(shù)就是那個(gè)被定義的類。實(shí)際上,上述代碼使用了 _fields
類變量來(lái)保存新的被定義的類,然后給它再添加一點(diǎn)新的東西。
StructTuple
類作為一個(gè)普通的基類,供其他使用者來(lái)繼承。這個(gè)類中的 __new__()
方法用來(lái)構(gòu)造新的實(shí)例。這里使用 __new__()
并不是很常見(jiàn),主要是因?yàn)槲覀円薷脑M的調(diào)用簽名,使得我們可以像普通的實(shí)例調(diào)用那樣創(chuàng)建實(shí)例。就像下面這樣:
s = Stock('ACME', 50, 91.1) # OK
s = Stock(('ACME', 50, 91.1)) # Error
跟 __init__()
不同的是,__new__()
方法在實(shí)例被創(chuàng)建之前被觸發(fā)。由于元組是不可修改的,所以一旦它們被創(chuàng)建了就不可能對(duì)它做任何改變。而 __init__()
會(huì)在實(shí)例創(chuàng)建的最后被觸發(fā),這樣的話我們就可以做我們想做的了。這也是為什么 __new__()
方法已經(jīng)被定義了。
盡管本節(jié)很短,還是需要你能仔細(xì)研讀,深入思考Python類是如何被定義的,實(shí)例是如何被創(chuàng)建的,還有就是元類和類的各個(gè)不同的方法究竟在什么時(shí)候被調(diào)用。
PEP 422 提供了一個(gè)解決本節(jié)問(wèn)題的另外一種方法。但是,截止到我寫(xiě)這本書(shū)的時(shí)候,它還沒(méi)被采納和接受。盡管如此,如果你使用的是Python 3.3或更高的版本,那么還是值得去看一下的。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: