python - 试图消除python代码中的类型模块
问题描述
正在说:
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 模块。
解决方案
不,它们不一样。
callable(output.write)
只是检查是否output.write
是可调用的。可调用的内容包括:
- 绑定方法对象(其类型为
types.MethodType
)。 - 普通函数(其类型为
types.FunctionType
) partial
包装绑定方法对象的实例(其类型为functools.partial
)- 您拥有自定义可调用类的实例,其
__call__
方法设计为与绑定方法对象(其类型是您的类)无法区分。 - 绑定方法类型(其类型是该子类)的子类的实例。
- …</li>
type(output.write) == types.MethodType
只接受其中的第一个。没有其他任何东西,甚至 的子类都MethodType
不会通过。(如果您想允许子类,请使用isinstance(output.write, types.MethodType)
.)
前者几乎可以肯定是你想要的。如果我对一个对象进行了猴子修补,以在调用时将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。ABC 仅内置支持检查抽象方法是否作为属性存在;它不检查它们是否可以调用,或者是否可以使用正确的签名调用。但扩展这种支持并不难。(或者,也许更好,只是从 PyPI 中获取一个接口/协议模块。)而且我认为类似的东西会比涉及or 、类型检查和grubbingisinstance(output, StringWriteable)
的一堆行更好地表明你的意图。getattr
hasattr
inspect
推荐阅读
- docker - 使用 Ansible 根据使用 docker_prune 的标签删除图像
- c++ - 如何检查每个头文件是否包含所需的包含文件?
- java - 如何在 HttpDecompressor 之前添加 GlobalTrafficShapingHandler
- sap-gui - 是否有可能在用户级别关闭日期扩展?
- python-3.x - python with lightgbm,预测类标签(0或1)而不是概率
- javascript - 希望根据某些条件检查将值保持在切换按钮的一种状态
- node.js - 在 Multer 中上传图像后移动和重命名图像
- django - curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN (0x80090308) - 提供给函数的令牌无效
- ios - 像在 Safari 中一样将 UIProgressView 添加到 UISearchBar
- jenkins - 使用带有 config.xml 的 curl 创建作业将在单行的 Execute shell/Pipeline 部分下的代码没有缩进