在 Python 中,当实现一个序列类型时,我经常(相对而言)发现自己写的代码是这样的:
class FooSequence(collections.abc.Sequence):
# Snip other methods
def __getitem__(self, key):
if isinstance(key, int):
# Get a single item
elif isinstance(key, slice):
# Get a whole slice
else:
raise TypeError('Index must be int, not {}'.format(type(key).__name__))
该代码使用 isinstance()
明确检查其参数的类型。这在 Python 社区中 被视为一种反模式。我该如何避免呢?
- 我不能使用
functools.singledispatch
,因为它 故意 与方法不兼容(它将尝试在self
上调度,这完全没用,因为我们已经在self
通过 OOP 多态性)。它适用于@staticmethod
,但是如果我需要从self
中取出东西怎么办? - 转换为
int()
然后捕获TypeError
,检查切片,并可能重新加注仍然很难看,尽管可能稍微不那么难看。 - 将整数转换为单元素切片并使用相同的代码处理这两种情况可能更清晰,但这有其自身的问题(返回
0
或[0]
?)。
原文由 Kevin 发布,翻译遵循 CC BY-SA 4.0 许可协议
尽管看起来很奇怪,但我怀疑您拥有它的方式是处理事情的最佳方式。模式通常存在以涵盖常见的用例,但这并不意味着当遵循它们会使生活变得更加困难时,它们应该被视为福音。 PEP 443 拒绝显式类型检查的主要原因是它“脆弱且无法扩展”。但是,这主要适用于随时采用多种不同类型的自定义函数。来自
__getitem__
上的 Python 文档:Python 文档明确说明了应该接受的两种类型,以及如果提供的项目不属于这两种类型,该怎么办。鉴于类型是由文档本身提供的,它不太可能改变(这样做会破坏比你自己的更多的实现),所以不值得费心去针对 Python 本身可能发生变化的代码进行编码。
如果您打算避免显式类型检查,我会向您指出 这个 SO answer 。它包含一个
@methdispatch
装饰器(不是我的名字,但我会用它滚动)的简洁实现,它允许@singledispatch
通过强制检查args[1]
来使用方法---
(arg) 而不是args[0]
(self)。使用它应该允许您将自定义单一调度与您的__getitem__
方法一起使用。您是否认为这些“pythonic”中的任何一个取决于您,但请记住,虽然 Python 之禅指出“特殊情况不足以打破规则”,但它立即指出“实用性胜过纯粹性” .在这种情况下,仅检查文档明确指出的两种类型是唯一的东西
__getitem__
应该支持对我来说似乎是实用的方法。