【问题标题】:python: What happens when class attribute, instance attribute, and method all have the same name?python:当类属性、实例属性和方法都同名时会发生什么?
【发布时间】:2012-10-08 13:57:14
【问题描述】:

名称相同的类属性、实例属性和方法,python如何区分?

class Exam(object):

    test = "class var"

    def __init__(self, n):
        self.test = n

    def test(self):
        print "method : ",self.test

test_o = Exam("Fine")

print dir(test_o)

print Exam.test
print test_o.test
test_o.test()

输出:

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',    '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'test']
<unbound method load.test>
Fine
Traceback (most recent call last):
  File "example.py", line 32, in <module>
    test_o.test()
TypeError: 'str' object is not callable

如何调用

  1. 类属性,Exam.test --> &lt;unbound method load.test&gt; 输出显示方法
  2. 实例属性test_o.test --> "Fine"
  3. 方法test_o.test() --> TypeError: 'str' object is not callable

【问题讨论】:

    标签: python methods instance-variables class-attributes


    【解决方案1】:

    类属性可以通过类访问:

    YourClass.clsattribute
    

    或者通过实例(如果实例没有覆盖类属性):

    instance.clsattribute
    

    方法,如by ecatmur in his answer 所述,是描述符,被设置为类属性。

    如果您通过实例访问方法,则实例将作为self 参数传递给描述符。 如果要从类中调用方法,则必须显式传递一个实例作为第一个参数。所以这些是等价的:

    instance.method()
    MyClass.method(instance)
    

    对实例属性和方法使用相同的名称会使该方法通过实例隐藏,但该方法仍然可以通过类使用:

    #python3
    >>> class C:
    ...     def __init__(self):
    ...         self.a = 1
    ...     def a(self):
    ...         print('hello')
    ... 
    >>> C.a
    <function a at 0x7f2c46ce3c88>
    >>> instance = C()
    >>> instance.a
    1
    >>> C.a(instance)
    hello
    

    结论:不要给实例属性和方法起相同的名字。 我通过给出有意义的名称来避免这种情况。方法就是动作,所以我通常使用动词或句子来表示它们。属性是数据,所以我对它们使用名词/形容词,这样可以避免方法和属性使用相同的名称。

    请注意,您根本不能拥有与方法同名的类属性,因为该方法会完全覆盖它(最后,方法只是可调用的类属性,并且会自动接收类的实例作为第一个属性)。

    【讨论】:

      【解决方案2】:

      你可以写

      Exam.test(test_o)
      

      Exam.test.__get__(test_o)()
      

      在后一种情况下,您使用方法是 descriptors 的事实将 &lt;unbound method load.test&gt; 转换为绑定方法,因此您可以使用单括号调用它。

      当你写test_o.test() 时,Python 并不知道你在尝试调用一个方法;您可能正在尝试调用已作为实例数据成员安装在对象上的函数或可调用对象。相反,它查找属性test,首先在对象上,然后在其类上,但由于该属性存在于对象上,它隐藏了类上的方法。

      班级成员

      test = "class var"
      

      不可访问(实际上它在任何地方都不存在),因为它被方法test 覆盖;当 class statement 被执行时,它的命名空间在被传递给它的元类之前被收集到一个字典中,后面的名字会覆盖前面的名字。

      【讨论】:

      • @naren 您正在尝试调用实例成员;见上文。
      【解决方案3】:

      如何拨打电话
      类属性,Exam.test

      你不能,因为在执行 def test(self) 时,名称 test 绑定到类中的方法并且对 "class var" 的引用丢失了。

      实例属性test_o.test --> "很好"

      你已经这样做了。

      方法test_o.test()

      您不能这样调用它,因为在执行 self.test = n 时,名称 test 绑定到实例中引用的任何对象 n,并且对实例中方法的引用丢失了。

      但正如其他答案中所指出的,您可以调用类中的方法并将实例传递给它:Exam.test(test_o)

      【讨论】:

      • 这正是我要寻找的。如此简单,如此富有表现力谢谢你
      【解决方案4】:

      您可以将方法称为类方法并将您的实例传递给它:

      Exam.test(test_o)
      

      或者,如果你不想使用Exam

      type(test_o).test(test_o)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-24
        • 2021-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-03
        相关资源
        最近更新 更多