Python:递归的isinstance检查

4
如何检查嵌套抽象类的完整类型签名?在这个例子中。
In [4]: from typing import Sequence

In [5]: IntSeq = Sequence[int]

In [6]: isinstance([1], IntSeq)
Out[6]: True

In [7]: isinstance([1.0], IntSeq)
Out[7]: True

我希望最后一个isinstance调用实际上返回False,而它只检查参数是否为Sequence。我考虑过递归地检查类型,但是IntSeq没有公共属性来存储嵌套的类型:

In [8]: dir(IntSeq)
Out[8]: 
['__abstractmethods__',
 '__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__extra__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__le__',
 '__len__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__origin__',
 '__parameters__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__slots__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 '_abc_cache',
 '_abc_negative_cache',
 '_abc_negative_cache_version',
 '_abc_registry']

因此,获取嵌套类型似乎并不直接。我在文档中找不到相关信息。
附言:我需要这个实现来进行多重分派。
更新
感谢Alexander Huszagh和Blender的反馈,我们现在知道Python 3.5中的抽象类(可能)有两个属性来存储嵌套类型:__parameters____args__。前者在Linux(Ubuntu)和Darwin(OS X)下都存在,尽管在Linux下为空。后者仅在Linux下可用,并且像__parameters__一样存储类型在OS X下。这些实现细节增加了混淆。

3
我希望关于投票关闭的人能够解释他选择此项的原因:“答案可能有太多种,或者好的答案会太长超出了这个格式。请添加细节来缩小答案集或隔离一个可在几段中回答的问题。” - Eli Korvigo
@DmitryTorba 我正在尝试在Python中实现真正的多重分派,因此我需要调度程序能够检查完整的类型签名。 - Eli Korvigo
@EliKorvigo 很有趣。让我在其他安装中测试一下。也许就没有好的答案了...只是提醒一下,这适用于Python 3.5.2、Ubuntu、GCC 5.4.0。 - Alex Huszagh
@AlexanderHuszagh,您是指这两个属性的可用性取决于Python版本还是特定的抽象类型实现?在我的系统(Darwin)上,Python 3.5.1中的“Sequence”没有“__args__”属性。 - Eli Korvigo
1
你可能会发现这个模块很有用:https://github.com/fabiommendes/pygeneric - Blender
显示剩余4条评论
1个回答

2
我看到你想使用一个仍然是临时的模块来实现一些东西;如果你这样做,你就可能会遇到一个变化中的接口。
Blender注意到__parameters__参数保存了类型的参数;我认为这在3.5.1之前是正确的。在我对最新版Python(3.6.0a4+)进行的git克隆中,__parameters__再次保存了一个空元组,__args__保存了参数,而__origin__是其__bases__属性的第一个条目。
>>> intSeq = typing.Sequence[int]
>>> intSeq.__args__
(<class 'int'>,)
>>> intSeq.__parameters__
()
>>> intSeq.__origin__
typing.Sequence<+T_co>

根据PEP 411的理解,从版本3.6开始,输入将从临时状态进入稳定状态,因此您应该使用此版本来实现您的功能。


谢谢您的澄清。我在PEP 411中没有找到关于“typing”的参考资料。您知道+T_co__origin__属性中是什么意思吗? - Eli Korvigo
是的,PEP 411不会讨论哪些模块是临时的,这在介绍该模块的PEP 0484中已经提到了 :-). +T_co表示参数是协变的,您可以在同一PEP中阅读更多信息(covariance and contravariance部分)。 - Dimitris Fasarakis Hilliard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接