使用属性装饰器时Python中的行为不一致

时间:2017-06-28 22:52:59

标签: python python-3.x oop

这是一个简单的文件,描述了一些不一致的Python(3.6)行为。为什么Case 1Case 2可能会运行但Case 3失败,即使Case 3只是前两种情况的合并?

我提供了前两种情况的dis输出。

import dis # Python bytecode disassembler

class A(object):
  def __init__(self):
    self.x # In case 2, getting x results in a function call.

  # CASE 1: Legal
  def x(self):
    y
    pass

  '''
  # CASE 2: Legal
  @property
  def x(self):
    pass
  '''

  '''
  # CASE 3: Illegal:
  @property
  def x(self):
    y
    pass
  '''

if __name__ == '__main__':
  a = A()
  dis.dis(A)

案例1字节码:

Disassembly of __init__:
  5           0 LOAD_FAST                0 (self)
              2 LOAD_ATTR                0 (x)
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE

Disassembly of x:
  9           0 LOAD_GLOBAL              0 (y)
              2 POP_TOP

 10           4 LOAD_CONST               0 (None)
              6 RETURN_VALUE

案例2字节码:

Disassembly of __init__:
  5           0 LOAD_FAST                0 (self)
              2 LOAD_ATTR                0 (x)
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE

2 个答案:

答案 0 :(得分:1)

这里没有矛盾。

当您实例化a = A()时,会调用__init__,调用self.x,它将执行x的正文。那时,没有y内窥镜,所以你得到一个例外。

答案 1 :(得分:1)

感谢@ chepner的评论:

  

在案例1中,你没有打电话; self.x是一个函数引用   那是没用过的。在案例3中,self.x实际上调用了已定义的getter   for x,大概是试图访问未定义的全局   名。

案例3中由行self.x引起的行为与案例1根本不同,因为案例1不会调用任何内容 - 它只是评估对函数的引用。

另一方面,案例3中的self.x执行x方法的正文,导致未定义的y错误。

为了确认@Chepner的评论,我用案例1运行了a.x()并得到了与案例3相同的错误。