8.11 简化数据结构的初始化

    可以在一个基类中写一个公用的 init() 函数:

    然后使你的类继承自这个基类:

    1. # Example class definitions
    2. class Stock(Structure1):
    3. _fields = ['name', 'shares', 'price']
    4.  
    5. class Point(Structure1):
    6. _fields = ['x', 'y']
    7.  
    8. class Circle(Structure1):
    9. _fields = ['radius']
    10.  
    11. def area(self):
    12. return math.pi * self.radius ** 2

    使用这些类的示例:

    1. class Structure2:
    2.  
    3. def __init__(self, *args, **kwargs):
    4. if len(args) > len(self._fields):
    5. raise TypeError('Expected {} arguments'.format(len(self._fields)))
    6.  
    7. # Set all of the positional arguments
    8. for name, value in zip(self._fields, args):
    9. setattr(self, name, value)
    10.  
    11. # Set the remaining keyword arguments
    12. for name in self._fields[len(args):]:
    13. setattr(self, name, kwargs.pop(name))
    14.  
    15. # Check for any remaining unknown arguments
    16. if kwargs:
    17. raise TypeError('Invalid argument(s): {}'.format(','.join(kwargs)))
    18. if __name__ == '__main__':
    19. class Stock(Structure2):
    20. _fields = ['name', 'shares', 'price']
    21.  
    22. s1 = Stock('ACME', 50, 91.1)
    23. s2 = Stock('ACME', 50, price=91.1)
    24. s3 = Stock('ACME', shares=50, price=91.1)
    25. # s3 = Stock('ACME', shares=50, price=91.1, aa=1)

    你还能将不在 中的名称加入到属性中去:

    当你需要使用大量很小的数据结构类的时候,相比手工一个个定义 init() 方法而已,使用这种方式可以大大简化代码。

    在上面的实现中我们使用了 函数类设置属性值,你可能不想用这种方式,而是想直接更新实例字典,就像下面这样:

    1. class Structure:
    2. # Class variable that specifies expected fields
    3. _fields= []
    4. def __init__(self, *args):
    5. if len(args) != len(self._fields):
    6. raise TypeError('Expected {} arguments'.format(len(self._fields)))
    7.  
    8. # Set the arguments (alternate)

    这种方法唯一不好的地方就是对某些IDE而言,在显示帮助函数时可能不太友好。比如:

    可以参考9.16小节来强制在 init() 方法中指定参数的类型签名。

    原文: