说:
if not callable(output.write):
raise ValueError("Output class must have a write() method")
与说法相同:
if type(output.write) != types.MethodType:
raise exceptions.ValueError("Output class must have a write() method")
如果可以避免,我宁愿不使用types模块。
答案 0 :(得分:5)
不,他们不一样。
callable(output.write)
只检查output.write
是否可调用。可以调用的东西包括:
types.MethodType
)。types.FunctionType
)partial
个实例包装绑定的方法对象(类型为functools.partial
)__call__
方法设计为与绑定方法对象(其类型为您的类)无法区分。 type(output.write) == types.MethodType
只接受其中的第一个。除了MethodType
的子类之外,没有别的东西会通过。 (如果要允许子类,请使用isinstance(output.write, types.MethodType)
。)
前者几乎可以肯定你想要的。如果我使用monkeypatched对象将write
方法替换为在调用时就像write
方法一样的方法,但是没有实现为绑定方法,为什么你的代码想拒绝我的对象?
关于你在评论中提出的问题:
我想知道是否有必要使用exceptions.ValueError
不,不是。
在Python 2.7中,exceptions
模块中也提供了内置异常:
>>> ValueError is exceptions.ValueError
True
在Python 3中,它们与所有其他内置函数一起移动到builtins
:
>>> ValueError is builtins.ValueError
True
但无论如何,您需要引用其模块的唯一原因是,如果您在自己的模块中隐藏ValueError
具有相同名称的全局。
最后一件事:
正如user2357112在评论中指出的那样,您的解决方案并不能确保任何有用的内容。
最常见的问题几乎肯定是output.write
根本不存在。在这种情况下,您将获得AttributeError
而不是您想要的ValueError
。 (如果这是可以接受的,您不需要检查任何内容 - 只需调用该方法,如果它不存在,您将获得AttributeError
,如果有,则TypeError
但不可调用。)您可以使用getattr(output, 'write', None)
代替output.write
解决此问题,因为None
无法调用。
下一个最常见的问题可能是output.write
已存在,并且可以调用,但签名错误。这意味着当您尝试调用时,您仍然会尝试避免使用相同的TypeError
。您可以通过例如使用inspect
模块来解决这个问题。
但如果你真的想要做所有这些,你应该把它全部考虑到ABC。 ABCs只有内置支持来检查抽象方法是否作为属性存在;它不会检查它们是否可以调用,或者使用正确的签名进行调用。但是,扩展这种支持并不难。 (或者,也许更好,只需从PyPI中获取一个接口/协议模块。)我认为像isinstance(output, StringWriteable)
之类的东西会比涉及getattr
或{{的一堆行更好地宣告你的意图1}},键入检查,hasattr
grubbing。