【问题标题】:AttributeError: 'property' object has no attributeAttributeError:“属性”对象没有属性
【发布时间】:2012-12-01 18:36:25
【问题描述】:

Python (2.6) 似乎是无缘无故的,有人能看出这段代码有问题吗?

class DB ():
    def doSomething (self, str):
        print str

class A ():
    __db = DB()

    @staticmethod
    def getDB ():
        return A.__db

    db = property(getDB)


A.db.doSomething("blah")

异常失败:

AttributeError: 'property' 对象没有属性 'doSomething'

我的理解是,一个属性在访问时会自动运行它的 getter,那么为什么它会抱怨一个属性对象,为什么它没有找到我明确可用的方法?

【问题讨论】:

  • 什么 Python 版本?如果使用 Python 2.x,则需要构建继承自 object...的类...
  • @JonClements -- 好眼力!看来 OP 正在使用 python2.x 因为 OP 使用 print str
  • 2.6,类工作正常,无需从对象继承。我需要这样做才能使属性正常工作吗?
  • @ben 除非你有充分的理由——你所有的对象都应该继承自 object
  • 对不起,乔恩,我忘了在我的示例中添加 staticmethod 装饰器。我不会实例化这个类,所以从对象继承将没有效果。无论如何,从对象继承有什么好处?

标签: python class exception object properties


【解决方案1】:

您没有正确使用类。一个类(通常)是两件事:

  1. 用于创建一系列相关对象的工厂
  2. 这些对象的共同行为的定义

这些相关对象是类的实例。普通方法在类的instances 上调用,而不是在类本身上。如果您想要可以从类中调用的方法,而不需要实例,则需要使用@classmethod(或@staticmethod)标记这些方法。

但是,我实际上并不知道从类对象中检索属性时是否有效。我现在不能检查,但我不这么认为。您得到的错误是A.db 正在检索定义属性本身的属性对象,而不是“评估”属性以获取A.__db。属性对象没有 doSomething 属性。属性旨在在类中创建,作为这些类的实例如何工作的描述。

如果您确实打算使用 A 的实例,那么您需要创建一个:

my_a = A()
my_a.db.doSomething("blah")

但是,这也会失败。您没有正确地将getDB 写成任何一种方法。普通方法需要一个参数来表示它被调用的实例(传统上称为self):

def getDB(self):
    ...

静态方法不需要,但需要一个装饰器将它们标记为静态:

@staticmethod
def getDB():
    ...

类方法既需要一个参数来接收调用它们的类,还需要一个装饰器:

@classmethod
def getDB(cls):
    ...

【讨论】:

  • 它确实有一个静态方法装饰器。除了您建议的两种方法之外,还有更多使用类的方法。您在这里并没有真正回答问题,只是陈述了一些明显的事实。我认为该物业没有被正确评估,这构成了我的问题的基础......
  • @我写答案时它不存在。您似乎不知道该属性没有被评估,因为您在问“为什么它没有找到我明确可用的方法?”而不是“为什么 python 不调用 getDB?”。它看起来很像这个问题源于对 python 中的类的一些非常基本的误解。很高兴得知事实并非如此。 :)
  • 很抱歉给您带来了困惑。我想既然你在其他人看到编辑之后回答的时间要长得多,对此感到抱歉。无论哪种方式,您的答案都可以帮助其他偶然发现它的人,所以不用担心!但是,我仍然不确定为什么要评估属性需要类的实例?
  • @Ben 要获得明确的答案,您必须询问原始设计师。我的猜测是,他们认为该用例是切线的,因为大多数属性 需要 一个实例,如果您尝试在没有实例的情况下评估它们将会失败。而且,如果您无法从类中检索底层属性对象,则根本无法获得它,因为您永远无法保证它返回的任何内容都会具有 __property__ 特殊属性(或其他属性)。
  • @Ben 慢是因为我在用手机。
【解决方案2】:

Python 中不需要 getter:

class B(object):
    def do_something(self, str):
        print str

class A(object):
    db = B()

A.db.do_something("blah")

(我也 PEP8:ed 代码)

【讨论】:

  • 这不是同一个代码。 db 不再是私有的。 A 不再是静态的。你说得对,我不需要 吸气剂,但我想要它们。
  • @Ben:A 仍然是静态的,它还没有被实例化。 B 从来不是私有的,Python 中没有“私有”对象之类的东西。你所做的只是命名空间重整。
  • 是的,但是现在由于继承和缺少静态方法而变得不那么明显了,但我很欣赏这只是理论。是的,再次正确,但它是 Python 的等价物,我认为这里的差异可以忽略不计。
  • @Ben:你并不需要 getter,但你想要它们……你考虑过你想要它们用于什么吗?您希望通过使用它们来实现什么?如果你没有实例化或子类化它,你似乎也不需要一个类根本,因为你只是将它用作一个美化的模块。
  • 本例中的代码是基于我原来的问题的简单提取。我的许多成员变量都有需要额外处理的空间,因此是吸气剂。虽然这不适用于所有成员变量,但我的类在 API 中形成模块,我希望它们保持一致。
【解决方案3】:

除了需要从object 继承之外,属性仅适用于实例。

a = A()
a.db.doSomething("blah")

要使属性在类上起作用,您可以定义一个元类。 (类是元类的一个实例,因此在元类上定义的属性适用于类,就像在类上定义的属性适用于该类的实例一样。)

【讨论】:

  • 这是一个静态类,我不会创建任何实例。我认为这也使得从对象继承毫无意义?
  • 最简单的解决方案,假设您不需要能够对这个“静态”类进行子类化,只需在类定义之后执行A = A()。然后,您有一个可以调用方法的类的实例。 (当然,可以使用type() 创建新实例,但这应该足以警告不要这样做。或者使用元类。)
  • 谢谢。我想让它保持静态,而且我认为仅仅为了大部分多余的属性而实现元类是不值得的,所以我将完全抛弃它们。很遗憾,因为从表面上看,它们看起来很整洁,如果不是很有用的话。
  • 不过,您不需要属性。
  • 如果您只是将类用作命名空间,这似乎就是您所说的“静态”,那么容器是否实际上是一个类并不重要......跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 2021-04-19
  • 1970-01-01
  • 2013-10-23
相关资源
最近更新 更多