简化数据结构的初始化

有时候,我们会厌倦为无数的class编写__init__函数,而__init__函数的作用仅是为了初始化一些属性。
我们可以编写一个父类来约定子类的__init__方式,根据类属性列表来一一初始化。

class Structure:
    _fields = []
    def __init__(self, *args):
        if len(args) != len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))
        
        # Set the arguments
        for key, value in zip(self._fields, args):
            setattr(self, key, value)


class Stock(Structure):
    _fields = ['name', 'shares', 'price']


class Point(Structure):
    _fields = ['x', 'y']


class Circle(Structure):
    _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

如果要支持关键字参数的初始化形式,则需要做如下更改:

class Structure:
    _fields = []
    def __init__(self, *args, **kwargs):
        if len(args) > len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))
        
        # Set the arguments
        for key, value in zip(self._fields, args):
            setattr(self, key, 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)))


class Stock(Structure):
    _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)
posted @ 2019-12-29 20:59  Jeffrey_Yang  阅读(255)  评论(0编辑  收藏  举报