定义包含哪个类

时间:2016-01-23 10:38:30

标签: python

好吧,这可能是一个非常愚蠢的问题而且可能不可能,或者我正在以一种扭曲的方式思考。所以,请考虑一下:

class MyClass:
    def __init__(self, x):
        self.x = x
        self.y = self.x ** 2


class MyList:
    def __init__(self, list):
        self.list = list

    def __iter__(self):
        return iter(self.list)

foo = [MyClass(x=1), MyClass(x=2)]
bar = MyList(list=foo)

for i in bar:
    print(i.x, i.y)

好的,这里我们有两个类:MyClass只是非常普通的东西而且没什么特别的。它有两个实例属性:xy。 另一方面,MyList应该是一个定义迭代器的类,该迭代器只应包含第一个类MyClass中的元素!

然后我创建了MyClass的两个实例,将它们放在列表foo中,并使用此列表创建MyListbar)的实例。

现在,传递给MyList的列表应该只包含MyClass元素!我想要的是Python要意识到这个事实!当我编写一个迭代bar内容的循环时,我希望Python知道bar中的元素是MyClass个对象。

我的程序目前的一个主要不便之处是Python没有意识到这一点,并且自动完成功能不起作用。换句话说:在循环中,当我写i.时,我希望弹出所有可能的参数(在本例中为xy)。我可以在Python中为MyList定义一些魔术方法,使Python知道这个列表的内容吗?

3 个答案:

答案 0 :(得分:3)

如果您使用的是PyCharm IDE,那么您可以这样做:

for i in bar:
    assert isinstance(i, MyClass)

或者这个:

for i in bar: # type: MyClass

答案 1 :(得分:2)

PEP 484

在Python≥3.0中,您可以使用函数注释(PEP 3107)和PEP 0484的类型提示语义。虽然后一个提议仅在Python 3.5和will be provisional until the release of 3.6中被接受,但它在语法上向后兼容所有支持PEP 3107的Python版本,因此在任何3.x版本的Python中使用类型提示注释应at least not hurt。< SUP> [1]

是否帮助您的IDE或交互式解释器(REPL)做更好的自动完成取决于IDE或解释器,可能是它的设置,即使对于Python≥3.5也是如此

对于Python 2,alternative notation using comments可用,支持PEP 0484的工具可能会或可能不会尊重。

添加您关心的类型提示

让我们看一下基于注释的提示(Python 3.x)如何查找代码。 (基于注释,Python-2.x兼容的提示留给读者练习。)

为了表示迭代MyList个实例会产生MyClass个对象,我们通过附加__iter__()(由减号和更大值组成的箭头)提示返回类型-> -than sign)在函数定义的冒号后面,后跟返回值的类型。 __iter__()本身不返回MyClass,它返回一个迭代器。为了表明它应该是MyClass以上的迭代器,我们使用generic [2] 中的Iterator abstract base class typing module

from typing import Iterator

class MyClass:
    # ...

class MyList:
    # ...

    def __iter__(self): -> Iterator[MyClass]
        return iter(self.list)

为了能够履行此承诺,self.list必须仅包含MyClass个实例。因此,请通过类型提示__init__()参数,让我们的调用者提供这样的信息:

from typing import Iterator, Iterable

# ...

class MyList:
    def __init__(self, list: Iterable[MyClass]):
        self.list = list

    def __iter__(self): -> Iterator[MyClass]
        return iter(self.list)

请注意,我选择了Iterable通用抽象基类,而不是更具体的List generic abstract base class(也不是MappingSequenceAbstractSet),您的实施仅依赖于iter(...)

[1] 除了过度使用时的可读性。所以as Mark writes,“如果您使用它们,请”负责任地使用类型提示“。

Python中包含的

[2] ≥3.5。对于较低版本,请使用backport可安装pip install typing

答案 2 :(得分:1)

在您实际运行代码之前,Python不知道任何类型。即,检查类型并发生基于类型的操作。

在开发代码时,您正在寻找的是IDE / REPL功能。在默认的Python REPL中,这种查找可能不可用。在更复杂的环境中,这确实发生了,您可以看到给定类的属性。

例如,在我经常使用的IPython REPL中,当在循环内部时:

for i in bar:

我按i.并点击tab两个元素i.x i.y都会显示。这是因为REPL已经开发出来,可以在开发代码时进行更好的内省。

我非常确定大多数知名的IDE都提供此功能; Pythons默认REPL相当简单(3.5有一些自动完成,但是!:D)并没有太多提供。