我有一个“工厂”,它使用参数元组创建类的实例:
def factory(cls, arg):
return cls(*arg)
class Foo(object):
def __init__(self, a, b):
pass
a = (1,2)
f = factory(Foo, a)
这很好用,所以我决定(由于各种原因超出了这个问题的范围)添加对不带任何参数作为回退的类的支持,以便可以在现有代码中更广泛地使用它。所以我需要检测2-arg vs 0-arg构造函数的可用性并适当地回退。鸭子打字似乎是“Pythonic”的答案并且工作得很漂亮:
def factory(cls, arg):
try:
return cls(*arg)
except TypeError:
print("Missing 2-arg, falling back to 0-arg ctor")
return cls()
class Foo(object):
def __init__(self,a,b):
pass
class Bar(object):
def __init__(self,a):
pass
a = (1,2)
f = factory(Foo, a)
b = factory(Bar, a)
但是当其中一个__init__
函数内部出现错误时,问题就出现了。当0-arg和2-arg __init__
都不存在时,我试图提供帮助并发出警告:
def factory(cls, arg):
try:
return cls(*arg)
except TypeError:
print("%s Missing 2-arg, falling back to 0-arg ctor" % str(cls))
return cls()
class Foo(object):
def __init__(self,a,b):
iter(a) # Oops, TypeError
a = (1,2)
try:
f = factory(Foo, a)
except TypeError: # 0-arg must be missing too
print("Neither 2-arg nor 0-arg ctor exist, that's all we support, sorry")
但是这里有一个致命的缺陷 - 我无法区分由于没有合适的TypeError
而引发的__init__
和因为问题较深而引发的TypeError
__init__
。
我不是在寻找修复Foo
或Bar
的方法,而是在“工厂”或其来电者层面更准确地理解失败的方法。
我如何以编程方式判断TypeError
是否是无过载匹配或其他地方失败的结果?我现在最好的想法是以编程方式走堆栈跟踪并查看行号,这最多是可怕的。
答案 0 :(得分:1)
测试__init__
方法所需的参数数量可以让您分离两种失败模式。
class Foo(object):
def __init__(self,a,b):
pass
class Bar(object):
def __init__(self,a):
pass
class Baz(object):
def __init__(self):
pass
def ctr_arg_count(cls):
fn = getattr(cls, '__init__')
return len(inspect.getargspec(fn).args) - 1
def factory(cls, *args):
if len(args) != ctr_arg_count(cls):
print("Can't initialize %s - wrong number of arguments" % cls)
return None
return cls(*args)
print factory(Foo, 1, 2)
print factory(Bar, 1)
print factory(Baz)
print factory(Foo, 1)
>>> <__main__.Foo object at 0x100483d10>
<__main__.Bar object at 0x100483d10>
<__main__.Baz object at 0x100483d10>
Can't initialize <class '__main__.Foo'> - wrong number of arguments
None