【发布时间】:2019-03-29 00:43:26
【问题描述】:
我有一个带有非常通用的初始化器的类,它接受args 和kwargs 的任意组合。我想实现另一种构建实例的方法,它将使用 3 个列表:一个用于args,两个用于kwargs(Key 和values,长度相同)。显然,我不能用我的普通 __init()__ 方法做到这一点,因为传递 3 个列表是一个完全有效的案例。
class MyVeryGenericClass:
__init__(self, *args, **kwargs):
pass #Do something really nice with args and kwargs, any case is valid.
出于这个原因,我想,我将不得不使用另一个函数来环绕我的 __init__ 函数,如下所示:
def mvgc_wrapper(lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return MyVeryGenericClass(*lll, **dict(zip(keys, vals)))
问题是:我的包装函数是否应该是我的类的方法,出于什么原因,如果是,那么如何?
- 一方面,除了
__new__和__init__等特殊方法外,类实例应该已经存在,但事实并非如此。 - 另一方面,让我的包装器成为我的类的一部分以使其成为整体会更合乎逻辑。
- 否则,我是否应该以与
__new__相同的方式定义它,使用 cls 参数而不是 self。我试着写成这样,但它似乎不起作用。
代码:
#!/usr/bin/python3
# coding: UTF-8
import traceback
class MyVeryGenericClass:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __repr__(self):
return repr(self.args)+repr(self.kwargs)
def wrapper(cls, lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return MyVeryGenericClass(*lll, **dict(zip(keys, vals)))
def wrapper2(cls, lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return cls(*lll, **dict(zip(keys, vals)))
def wrapper3(cls, lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return cls.MyVeryGenericClass(*lll, **dict(zip(keys, vals)))
genlist = [1, 2, 3]
genkeys = ["spam", "eggs"]
genvals = ["foo", "bar"]
try:
cmd="instance1 = MyVeryGenericClass(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("instance1 = {}".format(repr(instance1)))
except TypeError: traceback.print_exc()
print()
try:
cmd="instance2 = instance1.wrapper(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("instance2 = {}".format(repr(instance2)))
except TypeError: traceback.print_exc()
print()
try:
cmd="failed_instance = MyVeryGenericClass.wrapper(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("failed_instance = {}".format(repr(failed_instance)))
except TypeError: traceback.print_exc()
print()
try:
cmd="failed_instance = MyVeryGenericClass.wrapper2(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("failed_instance = {}".format(repr(failed_instance)))
except TypeError: traceback.print_exc()
print()
try:
cmd="failed_instance = MyVeryGenericClass.wrapper3(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("failed_instance = {}".format(repr(failed_instance)))
except TypeError: traceback.print_exc()
生产:
RESTART: /media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py
> instance1 = MyVeryGenericClass(genlist, genkeys, genvals)
instance1 = ([1, 2, 3], ['spam', 'eggs'], ['foo', 'bar']){}
> instance2 = instance1.wrapper(genlist, genkeys, genvals)
instance2 = (1, 2, 3){'eggs': 'bar', 'spam': 'foo'}
> failed_instance = MyVeryGenericClass.wrapper(genlist, genkeys, genvals)
Traceback (most recent call last):
File "/media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py", line 51, in <module>
exec(cmd)
File "<string>", line 1, in <module>
TypeError: wrapper() missing 1 required positional argument: 'vals'
> failed_instance = MyVeryGenericClass.wrapper2(genlist, genkeys, genvals)
Traceback (most recent call last):
File "/media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py", line 58, in <module>
exec(cmd)
File "<string>", line 1, in <module>
TypeError: wrapper2() missing 1 required positional argument: 'vals'
> failed_instance = MyVeryGenericClass.wrapper3(genlist, genkeys, genvals)
Traceback (most recent call last):
File "/media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py", line 65, in <module>
exec(cmd)
File "<string>", line 1, in <module>
TypeError: wrapper3() missing 1 required positional argument: 'vals'
编辑:
感谢@kindall,解决方案是在备用构造函数上方添加#classmethod。但现在的问题是:如何区分备用构造函数和备用初始化器?
【问题讨论】:
-
备用构造函数通常使用
@classmethod。 -
这不是一个接口顺便说一句,我不明白你为什么不将 3 个列表传递给构造函数而不是这样做
-
因为,我的 init 方法无法检测到两个输入之间的差异,并且会产生错误的结果(请参阅我的实例 1 和实例 2 的内容之间的差异最后一个例子)(关于接口,这就是我引用它的原因。)
-
所以你无法控制类的代码,你需要在两者之间添加一些东西来动态修改参数?
-
我可以控制类的代码,但我不想失去我的正常初始化程序。
标签: python python-3.x class constructor