在classmethod

时间:2016-01-15 05:54:57

标签: python decorator class-method python-decorators

我来自java背景,所以我在这里有点困惑。

考虑下面的代码段

class A():
    def __init__(self, **kwargs):
        self.obj_var = "I am obj var"

    @classmethod
    def class_method(cls):
        print cls.obj_var   # this line is in question here
        cls.cls_obj = "I m class object"
        return cls.cls_obj

这会引发错误:

In [30]: a = A()

In [31]: a.obj_var
Out[31]: 'I am obj var'

In [32]: a.class_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-32-3dcd9d512548> in <module>()
----> 1 a.class_method()

<ipython-input-29-9c0d341ad75f> in class_method(cls)
      8     @classmethod
      9     def class_method(cls):
---> 10         print cls.obj_var
     11         cls.cls_obj = "I m class object"
     12         return cls.cls_obj

AttributeError: class A has no attribute 'obj_var'

如果我评论@classmethod,这将正常工作。

我的理解不正确,确定):

当我执行a = A()时,obj_var中创建的所有变量(__init__)在传递给任何其他a时都可通过此classmethod访问同一类。显然情况并非如此。

问题

  • 为什么我在__init__中无法访问var class_method时,方法中提到了decorater @classmethod,但在删除decorater时,它可以正常工作细

  • python如何在编译时内部处理这个特定的类?

  • 有什么办法可以用@classmethod__init__ vars用同样的方法吗?

2 个答案:

答案 0 :(得分:2)

让我们来谈谈Python的方法是如何运作的。

您可能已经注意到Python方法被声明为独立函数,但在类中。那是因为Python方法确实是碰巧在类中的独立函数。 self / cls参数并不特殊。它只是该函数的第一个参数。

在我们继续前进之前,我想指出您似乎并未明确继承object。如果你在Python 2.x中工作,除非你明确地从它继承,否则图的根部没有object这是一件坏事,您应该尽可能在新代码中直接或间接地从object继承。继承Python 3中的object是合法且无害的,但是没有必要。本讨论的其余部分假定您要么在3.x中工作,要么已修复此问题。

当您使用foo.bar访问变量,函数,方法或任何其他类型的对象时,某些钩子称为&#34;描述符协议&#34;被调用。您不必了解其中的详细信息,以了解函数的工作原理。所有你必须知道的是:

  1. 首先,如果直接附加到bar的实例变量foo(而foo不是类),我们只是直接返回它。(*)< / LI>
  2. 如果foo是一个类,bar@classmethod函数(**)在foo或其中一个超类中声明,则第一个参数是在我们返回之前设置为foo。否则,它将保持不变。(***)如果我们返回了某些内容,我们在这里停止
  3. 我们搜索&#34;方法解析顺序&#34; foo。这包括foo的类(称为type(foo)),该类的超类,依此类推,直到我们到达object。在多重继承的情况下,这会变得更加复杂,但同样,您不需要知道这一点。
  4. 从第一个有{1}的变量中取bar变量(称之为Baz)。
  5. 如果Baz.bar是常规的,未修饰的函数,请将其第一个参数设置为foo并将其返回。
  6. 否则,如果Baz.bar@classmethod函数,请将其第一个参数设置为type(foo)并将其返回。
  7. 否则,如果Baz.bar@staticmethod函数,或者根本不是函数(**),则保持不变。
  8. 正如您所看到的,如果方法声明为@classmethod,那么第一个参数始终是类,而不是实例,无论函数如何被调用。这意味着您无法访问foo的实例变量,因为您无法访问foo本身。 __init__()中设置的任何变量都是实例变量,因此在这里不可见。

    以下是我撒谎的所有事情:

    (*):Python实际上先完成剩下的工作然后再回到这一步。但这仅适用于@property之类的事情,它实际上可以覆盖本地实例变量。常规方法不能。

    (**):这是谎言。在这种情况下,Python还对@property函数以及实现某些特殊方法的任何其他函数进行了特殊处理。

    (***):我也忽略了Python 2.x中的未绑定方法,因为除了某些非常奇怪的情况(当你尝试将错误类型的对象作为第一个参数手动传递时),它们会使没有任何区别。它们在Python 3中不存在。

答案 1 :(得分:0)

如果要从类方法访问实例变量,则需要创建存在该实例变量的类的实例。 希望下面的代码能工作。

sal < 900