classmethod属性TypeError:'property'对象不可迭代

Nar*_*ann 8 python

运行此代码:

import weakref

class A(object):
    _instances = []
    def __init__(self):
        self._instances.append(weakref.ref(self))

    @property
    @classmethod
    def instances(cls):
        for inst_ref in cls._instances:
            inst = inst_ref()
            if inst is not None:
                yield inst

foo = A()
bar = A()
for inst in A.instances:
    print inst
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

Traceback (most recent call last):
  File "test.py", line 18, in <module>
    for inst in A.instances:
TypeError: 'property' object is not iterable
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚类方法的行为如何像属性(没有括号).

  • 谁能解释我为什么会收到此错误?
  • 任何人都可以解释我如何让一个类方法表现得像一个属性?

Rob*_*obᵩ 8

以下是使用描述符和类的一种方法:

import weakref

class classproperty(object):
    def __init__(self, fget):
        self.fget = fget
    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class A(object):
    _instances = []
    def __init__(self):
        self._instances.append(weakref.ref(self))

    @classproperty
    def instances(cls):
        for inst_ref in cls._instances:
            inst = inst_ref()
            if inst is not None:
                yield inst

foo = A()
bar = A()
for inst in A.instances:
    print inst
Run Code Online (Sandbox Code Playgroud)

参考文献:

  • 我会用它,因为它对我来说看起来最优雅。非常感谢!(PS 我不能投票,因为我还不到 15 岁,对此感到抱歉......)。 (2认同)

Dan*_*man 5

属性始终适用于实例,而不适用于类。

这样做的方法是定义一个元类,该元类通过自己的实例方法定义属性,因为一个类是其元类的实例:

class AMeta(type):
    def __init__(self,name,bases,dict):
        self._instances = []

    @property
    def instances(self):
        for inst_ref in self._instances:
             inst = inst_ref()
             if inst is not None:
                 yield inst

class A(object):
     __metaclass__ = AMeta

     def __init__(self):
         self._instances.append(weakref.ref(self))
Run Code Online (Sandbox Code Playgroud)

现在可以正常工作了:

>>> foo=A()
>>> bar = A()

>>> for inst in A.instances:
...     print inst
<__main__.A object at 0x1065d7290>
<__main__.A object at 0x1065d7990>
Run Code Online (Sandbox Code Playgroud)