__init__()内外变量的区别(类属性和实例属性)

322 投票
12 回答
204940 浏览
提问于 2025-04-15 14:54

这些类之间除了名字以外,真的有区别吗?

class WithClass ():
    def __init__(self):
        self.value = "Bob"
    def my_func(self):
        print(self.value)

class WithoutClass ():
    value = "Bob"

    def my_func(self):
        print(self.value)

如果我在声明变量 value 时使用或不使用 __init__ 方法,会有什么不同吗?

我最担心的是,我可能会用一种方式,但这样会在以后给我带来更多麻烦。

12 个回答

53

我想在这里补充一些我在这个讨论串和这个讨论串中看到的内容。

声明: 这些观点来自我自己的实验。

__init__ 外的变量:

这些实际上是 静态类变量,因此可以被这个类的所有实例访问。

__init__ 内的变量:

这些 实例变量 的值只能被当前的实例访问(通过 self 引用)。

我的补充:

程序员在使用 静态类变量 时需要考虑的一点是,它们可能会被 实例变量 盖掉(如果你通过 self 引用来访问 静态类变量)。

解释:

之前我以为这两种声明变量的方式是完全一样的(真是傻),部分原因是我可以通过 self 引用访问这两种变量。直到我遇到问题,才开始研究这个话题并弄清楚了。

通过 self 引用访问 静态类变量 的问题在于,只有当没有同名的 实例变量 时,它才会引用 静态类变量。更糟糕的是,试图通过 self 引用重新定义一个 静态类变量 是不行的,因为这会创建一个 实例变量,然后把之前可以访问的 静态类变量 盖掉。

为了解决这个问题,你应该始终通过类的名称来引用 静态类变量

示例:

#!/usr/bin/env python

class Foo:
    static_var = 'every instance has access'

    def __init__(self,name):
        self.instance_var = 'I am %s' % name

    def printAll(self):
        print 'self.instance_var = %s' % self.instance_var
        print 'self.static_var = %s' % self.static_var
        print 'Foo.static_var = %s' % Foo.static_var

f1 = Foo('f1')

f1.printAll()

f1.static_var = 'Shadowing static_var'

f1.printAll()

f2 = Foo('f2')

f2.printAll()

Foo.static_var = 'modified class'

f1.printAll()
f2.printAll()

输出:

self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class

希望这些对某些人有帮助。

136

没有 Self

先创建一些对象:

class foo(object):
    x = 'original class'

c1, c2 = foo(), foo()

我可以改变 c1 这个实例,但这不会影响到 c2 这个实例:

c1.x = 'changed instance'
c2.x
>>> 'original class'

但是如果我改变了 foo 这个类,所有这个类的实例都会受到影响:

foo.x = 'changed class'
c2.x
>>> 'changed class'

请注意这里 Python 的作用域是怎么工作的:

c1.x
>>> 'changed instance'

有了 Self

改变类并不会影响到实例:

class foo(object):
    def __init__(self):
        self.x = 'original self'

c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'
359

在类的外面定义的变量属于这个类,所有的实例都会共享这些变量。

__init__(还有其他方法)里面创建的变量,如果前面有self.,那么这些变量就属于这个对象的实例。

撰写回答