在装饰器中自动分配初始化参数

Assign init arguments automatically in decorator

我正在尝试将传递给 init 的所有参数分配给 class。我无法获得参数,也无法获得 class selfinit 作为第一个参数传递的 self):

class unpack_arguments(object):

    def __init__(self, f):
        self.f = f

    def __call__(self, *args, **kwargs):
        import ipdb; ipdb.set_trace()



class SomeObject(object):

    @unpack_arguments
    def __init__(self, one=1, two=2, three=3, four=4):
        pass


# At this point, you can do
#
# obj = SomeObject()
# obj.one # 1
# obj.two # 2
# obj.three # 3
# obj.four # 4


obj = SomeObject()

我尝试查找内容,但找不到 SomeObject 的 class 实例或 onetwo 等键名:

ipdb> kwargs
{}
ipdb> args
self = <__main__.unpack_arguments object at 0x1077a3f60>
args = ()
kwargs = {}
ipdb> self.f
<function SomeObject.__init__ at 0x1077a06a8>
ipdb> dir(self.f)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
ipdb> self.f.__defaults__
(1, 2, 3, 4)
ipdb> self.f.__kwdefaults__
ipdb> self.f.__kwdefaults__
ipdb> 

Python 的方法是使用 **kwargs:

class SomeObject(object):
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)


obj = SomeObject(a=1, b=2, c=3)

print(obj.__dict__)

如您所见,对象的表示是:

{'a': 1, 'b': 2, 'c': 3}

因为你需要基础class: 这是 "dummy" 实现:

class SomeObject_with_init(object):
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def my_name_is(self):
        return (self.__class__)


class SomeObject1(SomeObject_with_init):
    pass


class SomeObject2(SomeObject_with_init):
    pass


obj = SomeObject1(a=1, b=2)

obj2 = SomeObject2(test='1', test2='2')

print(obj.__dict__, obj.my_name_is())
print(obj2.__dict__, obj2.my_name_is())

这里的输出将是:

{'a': 1, 'b': 2} <class '__main__.SomeObject1'>
{'test': '1', 'test2': '2'} <class '__main__.SomeObject2'>

你可以尝试这样的事情,虽然我更喜欢 Arseniy's 解决方案或使用元类而不是装饰 __init__

def unpack_arguments(func):
    def wrapper(*args, **kwargs):
        cls = args[0]
        cls.__dict__.update(kwargs)
        func(*args, **kwargs)
    return wrapper


class SomeObject(object):
    @unpack_arguments
    def __init__(self, *args, **kwargs):
        self.object = 'SomeObject'


s = SomeObject(a=1, b=2, c=3)
print (s.a)
print (s.b)
print (s.c)
print (s.object)

Returns:

1
2
3
SomeObject