当我创建一个python类并在init方法中,我只写:
self.name1 = name1
self.name2 = name2
....
对于所有参数。
SO,如何为不同的__init__
和*args
优雅地编写**kwargs
?
我想编写一个元类以自动设置*args
和**kwargs
的属性:
#the metaclass to be used
class LazyInit():
# code here
然后,当我为其创建子类时,子类将自动为它们自己的__init__
和*args
使用**kwargs
。
class Hospital(metaclass = LazyInit):
def __init__(self, *args,**kwargs): pass
class Basketball(metaclass = LazyInit):
def __init__(self, *args, **kwargs): pass
a = 1
b = 2
c = 3
a_hospital = Hospital(a, b, kw1 =1, kw2 =2)
a_circle = Basketball(a, c, kw3 = 10, kw4 = 20)
我只知道我们只能将setattr
用于**kwargs
:
class LazyInit():
def __init__(self,**kwargs):
for k,v in kwargs.items():
setattr(self,k,v)
LazyInit(a=1).a
1
但是,这不是可以在子类中使用的元类。我应该在每个子类中编写此代码段...
首先,使装饰器进行绑定。
from functools import wraps
from inspect import signature
def binds(f):
@wraps(f)
def __init__(self, *args, **kwargs):
# Update self attributes with inspected binding of arg names to values.
vars(self).update(signature(f).bind(None, *args, **kwargs).arguments)
# `self` is also an arg, but we didn't really want to save this one.
del self.self
return __init__
这里是使用方法。
class Foo:
@binds
def __init__(self, foo, bar, *args, baz, **kwargs):
pass
和演示:
>>> vars(Foo(1,2,3,4,baz=5,quux=10))
{'foo': 1, 'bar': 2, 'args': (3, 4), 'baz': 5, 'kwargs': {'quux': 10}}
现在剩下的就是让一个元类自动应用此装饰器。
class AutoInit(type):
def __new__(cls, name, bases, namespace):
namespace['__init__'] = store_args(namespace['__init__'])
return type.__new__(cls, name, bases, namespace)
AutoInit
是默认元类type
的子类。在构造过程中,它会找到init方法并将其替换为包装的版本。 type
处理其余部分。
现在您可以像使用其他任何元类一样使用它:
class Bar(metaclass=AutoInit):
def __init__(self, spam, eggs, *, bacon):
pass
演示:
>>> vars(Bar(1,2,bacon=3))
{'spam': 1, 'eggs': 2, 'bacon': 3}
并且此行为也将被继承。
class Baz(Bar):
def __init__(self, spam, eggs, sausage, *, bacon):
super().__init__(spam, eggs, bacon=bacon)
演示(请注意'sausage'
):
>>> vars(Baz(1,2,3,bacon=4))
{'spam': 1, 'eggs': 2, 'sausage': 3, 'bacon': 4}
元类是deep magic。功能强大,但晦涩难懂。您几乎永远不需要它们(如果不确定,假设您不需要)。过多使用元类的代码可能变得很难理解和维护。
在这种情况下,您可能应该在装饰器处停下来。它几乎可以完成您想要的所有事情,而不会造成混乱。显式胜于隐式。读取的代码多于编写的代码。可读性计数。