类变量是实例方法或类方法的范围吗?

时间:2014-02-13 14:20:38

标签: python class methods scope

  • 类变量是否属于为Python类定义的方法的范围?
  • 如何在方法(类方法或实例方法或静态方法)中访问类变量并可能更改它?
  • 最好的方法是什么?例如,我可能想要计算已经创建了多少个类的实例。

我读here表示类变量在方法参数列表的范围内。要在那里使用类变量,我应该将其称为counter而不是MyClass.counter,因为该类正处于定义的中间,但是我可以在MyClass.counter中将其作为__init__方法。这是否意味着在__init__方法内部完全定义了类?

编辑:我还想知道为什么counter在方法的参数列表范围内而不在方法体中?

class MyClass(object):
    counter = 0

    def __init__(self): # counter is in scope here. can be used as default argument
        counter += 1  # Counter not in scope. Throws UnboundLocalError

    def printCount(self):
        print counter  # Counter not in scope. Throws UnboundLocalError

2 个答案:

答案 0 :(得分:8)

在方法中,您可以通过两种不同的方式访问类属性:

  1. 通过引用该类,然后是属性:

    MyClass.counter
    
  2. 通过访问实例上的属性self

    self.counter
    

    仅当没有实例属性屏蔽counter时才有效。

  3. 问题是,当您设置实例上的属性时,self上无法再访问类属性:

    self.counter += 1
    

    首次运行时会设置一个实例属性,不再访问class属性。

    如果你想设置一个类属性,你将不得不使用第一种方法来解决它:

    class MyClass(object):
        counter = 0
    
        def __init__(self): 
            MyClass.counter += 1
    
        def printCount(self):
            # these both work:
            print self.counter
            print MyClass.counter
    

    您无法在方法中将counter称为本地。在类定义主体之外,它们不是本地或全局名称。只有在class body内才可以这样做:

      

    然后使用新创建的本地命名空间和原始全局命名空间,在新的执行框架 [...] 中执行类的套件。 (通常,套件仅包含函数定义。)当类的套件完成执行时,其执行帧将被丢弃,但其本地名称空间将被保存。 [...]然后使用基类的继承列表和属性字典的已保存本地名称空间创建类对象。

    换句话说,当Python执行class主体时,counter__init__printCount是本地名称,并且在执行期间您可以将这些名称称为当地人。因此,您可以使用counter为方法参数定义默认值,或者对其进行基础计算。但是一旦构造了类,那个名称空间就会消失,你将不得不引用MyClass.<name>

答案 1 :(得分:1)

这是另一个简单的解释:

<强> 1。类变量是否在为Python类定义的方法的范围内?

以下是类变量说明:

  • 由类的所有实例共享的变量。
  • 它在类中定义,但在类的任何方法之外。
  • 可以使用类名称变量名称来访问类变量。

注意:类变量存储在class_name.__dict__中,即共享给所有实例。

注意:实例变量存储在instance.__dict__中,即仅存储在当前实例中。

注意:使用类名访问类变量总是一个好主意,以减少混淆,而不是用实例变量重写。

以下是摘录:

class ClassA(object):
    _counter = 0
    def __init__(self, val):
       self._counter = val

    def show_me(self):
        print 'Class variable: %d' % ClassA._counter
        print 'Instance variable: %d' % self._counter

obj = ClassA(1000)

obj.show_me()
print ClassA.__dict__['_counter']
print obj.__dict__['_counter']

输出:

Class variable: 0
Instance variable: 1000
0
1000

<强> 2。如何在方法(类方法或实例方法或静态方法)中访问类变量并可能更改它?

您可以使用class_name点变量名称访问类变量,即

ClassA._counter

第3。什么是最好的方式?例如,我可能想要计算已经创建了多少个类的实例。

到目前为止,我知道覆盖__new__方法会更好,因为__new__正在调用每个对象创建和更新类变量_counter,如下面的代码段所示:

#!/usr/bin/python

class ClassA(object):
    # this _counter is in the class.__dict__ which shared across all instance
    _counter = 0
    def __new__(cls, *args, **kw):
        ob = super(ClassA, cls).__new__(cls, *args, **kw)
        ClassA._counter += 1
        return ob

    def __init__(self, val):
        # this _counter is in the instance dictionary which is not shared
        self._counter = val*val

    def total_instance(self):
        return ClassA._counter

# Lets create three instance
for i in range(1,4):
    obj = ClassA(i)
    print 'class variable _counter : %d' % obj.total_instance()
    print 'instance variable _counter : %d' % obj._counter

输出:

class variable _counter : 1
instance variable _counter : 1
class variable _counter : 2
instance variable _counter : 4
class variable _counter : 3
instance variable _counter : 9

注意:在上面的示例中,我试图向您展示实例变量_counter和类变量_counter的区别。

如果有帮助,请告诉我。