[TOC] >[success] # 自定义生成属性的init方法 * 了解setattr 工作原理 ~~~ def setattr(x, y, v): # real signature unknown; restored from __doc__ """ Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v'' """ pass ~~~ * 定义思路 ~~~ 1.创建一个接受属性的列表 2.判断列表和传入属性参数是否一致,不一致报错,一致利用zip 将列表和元组整合 3.使用setattr 整合成该类的属性 ~~~ >[danger] ##### 代码实现 ~~~ class Structure1: _fields = [] def __init__(self, *args): if len(args) != len(self._fields): raise TypeError('Expected {} arguments'.format(len(self._fields))) # Set the arguments print(self._fields, args) for name, value in zip(self._fields, args): setattr(self, name, value) ~~~ * 使用方法,继承后享有父类init方法 ~~~ # 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 ~~~ * 调用,传入的参数被*args 接受 ~~~ s = Stock('ACME', 50, 91.1) ~~~ >[danger] ##### 代码升级,接受定义传参数 ~~~ 1.了解几个小知识点 a = ['a', 'b', 'c'] print(a[2:]) b = {'a': 1,'b': 2} print(b.pop('b')) 打印结果: ['c'] 2 ~~~ ~~~ 1.思路 获取传入的元祖数量,做切片剩下的就是得到定义传入的参数 2.利用字典的pop 删除k获取value ~~~ ~~~ 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 print(self._fields[len(args):],args) 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) ~~~ >[danger] ##### 在升级你还能将不在 _fields 中的名称加入到属性中去 ~~~ 1.kwargs.keys() - self._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 print(extra_args) 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') ~~~ >[danger] ##### 不推荐直接使用字典方式 ~~~ 1.把字典之前更新到类中,这样的弊端遇到当一个子类定义了 __slots__ 或者通过property(或描述器)来包装某个属性,那么直接访问实例字典就不起作用了 ~~~ ~~~ 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)) ~~~