簡(jiǎn)單的全局?jǐn)?shù)據(jù)結(jié)構(gòu)的初始化

問題

你寫了很多僅僅用作數(shù)據(jù)結(jié)構(gòu)的類,不想寫太多煩人的 init() 函數(shù)

解決方案

可以在一個(gè)基類中寫一個(gè)公用的 init() 函數(shù):

import math
class Structurel:
# Class variable that specifies expected fields
        -fields = []
        def __init__(self, *args):
                if len(args) != len(self._fields):
                        raise TypeError("Expected {} arguments".format(len(self._fields)))
# Set the arguments
                for name, value in zip(self._fields, args):
                        setattr(self, name, value)

然后使你的類繼承自這個(gè)基類:

# Example class definitions
class Stock(Structure1):
        _fields = ['name', 'shares', 'price']
class Point(Structure1):
        _fields = ['x', 'y']
class Circle(Structure1):
        _fields = ['radius']

        def area(self):
                return math.pi * self.radius ** 2

使用這些類的示例:

>>> s = Stock('ACME', 50, 91.1)
>>> p = Point(2, 3)
>>> c = Circle(4.5)
>>> s2 = Stock('ACME', 50)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "structure.py", line 6, in __init__
raise TypeError('Expected {} arguments'.format(len(self._fields)))
TypeError: Expected 3 arguments

如果還想支持關(guān)鍵字參數(shù),可以將關(guān)鍵字參數(shù)設(shè)置為實(shí)例屬性:

class Structure2:
_fields = []
def __init__(self, *args, **kwargs):
if len(args) > len(self._fields):
raise TypeError('Expected {} arguments'.format(len(self._fields)))
# Set all of the positional arguments
for name, value in zip(self._fields, args):
setattr(self, name, value)
# Set the remaining keyword arguments
for name in self._fields[len(args):]:
setattr(self, name, kwargs.pop(name))
# Check for any remaining unknown arguments
if kwargs:
raise TypeError('Invalid argument(s): {}'.format(','.
,→ join(kwargs)))
# Example use
if __name__ == '__main__':
class Stock(Structure2):
_fields = ['name', 'shares', 'price']
s1 = Stock('ACME', 50, 91.1)
s2 = Stock('ACME', 50, price=91.1)
s3 = Stock('ACME', shares=50, price=91.1)
# s3 = Stock('ACME', shares=50, price=91.1, aa=1)

你還能將不在 _fields 中的名稱加入到屬性中去:

class Structure3:
# Class variable that specifies expected fields
_fields = []
def __init__(self, *args, **kwargs):
if len(args) != len(self._fields):
raise TypeError('Expected {} arguments'.format(len(self._fields)))
# Set the arguments
for name, value in zip(self._fields, args):
setattr(self, name, value)
# Set the additional arguments (if any)
extra_args = kwargs.keys() - self._fields
for name in extra_args:
setattr(self, name, kwargs.pop(name))
if kwargs:
raise TypeError('Duplicate values for {}'.format(','.
,→ join(kwargs)))
# Example use
if __name__ == '__main__':
class Stock(Structure3):
_fields = ['name', 'shares', 'price']
s1 = Stock('ACME', 50, 91.1)
s2 = Stock('ACME', 50, 91.1, date='8/2/2012')

討論
當(dāng)你需要使用大量很小的數(shù)據(jù)結(jié)構(gòu)類的時(shí)候,相比手工一個(gè)個(gè)定義 init() 方
法而已,使用這種方式可以大大簡(jiǎn)化代碼。
在上面的實(shí)現(xiàn)中我們使用了 setattr() 函數(shù)類設(shè)置屬性值,你可能不想用這種方
式,而是想直接更新實(shí)例字典,就像下面這樣:

class Structure:
# Class variable that specifies expected fields
_fields= []
def __init__(self, *args):
if len(args) != len(self._fields):
raise TypeError('Expected {} arguments'.format(len(self._fields)))
# Set the arguments (alternate)
self.__dict__.update(zip(self._fields,args))

盡管這也可以正常工作,但是當(dāng)定義子類的時(shí)候問題就來(lái)了。當(dāng)一個(gè)子類定義了
slots 或者通過 property(或描述器) 來(lái)包裝某個(gè)屬性,那么直接訪問實(shí)例字典就
不起作用了。我們上面使用 setattr() 會(huì)顯得更通用些,因?yàn)樗策m用于子類情況。
這種方法唯一不好的地方就是對(duì)某些 IDE 而言,在顯示幫助函數(shù)時(shí)可能不太友好。
比如:

>>> help(Stock)
Help on class Stock in module __main__:
class Stock(Structure)
...
| Methods inherited from Structure:
|
| __init__(self, *args, **kwargs)
|
...
>>>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容