类和实例变量有什么区别?

Chr*_*eta 59 python variables class self

Python中的类和实例变量有什么区别?

class Complex:
    a = 1
Run Code Online (Sandbox Code Playgroud)

class Complex:
    def __init__(self):
        self.a = 1
Run Code Online (Sandbox Code Playgroud)

使用呼叫:x = Complex().a在两种情况下都将x分配给1.

一个更深入的答案__init__(),self将受到赞赏.

Ben*_*Ben 105

编写类块时,可以创建类属性(或类变量).您在类块中指定的所有名称,包括您定义的方法都将def成为类属性.

创建类实例后,任何引用该实例的内容都可以在其上创建实例属性.在内部方法中,"当前"实例几乎总是绑定到名称self,这就是为什么您将这些视为"自变量"的原因.通常在面向对象的设计中,附加到类的代码应该控制该类的实例的属性,因此几乎所有实例属性赋值都在方法内部完成,使用对self参数中接收的实例的引用.方法.

类属性通常与Java,C#或C++等语言中的静态变量(或方法)进行比较.但是,如果你想要更深入的理解,我会避免将类属性视为与静态变量"相同".虽然它们通常用于相同的目的,但基本概念却截然不同.更多关于这一点在线下面的"高级"部分.

一个例子!

class SomeClass:
    def __init__(self):
        self.foo = 'I am an instance attribute called foo'
        self.foo_list = []

    bar = 'I am a class attribute called bar'
    bar_list = []
Run Code Online (Sandbox Code Playgroud)

执行该块之后,有一类SomeClass,3类属性:__init__,bar,和bar_list.

然后我们将创建一个实例:

instance = SomeClass()
Run Code Online (Sandbox Code Playgroud)

当发生这种情况,SomeClass__init__方法被执行时,在其接收到新的实例self参数.此方法创建两个实例属性:foofoo_list.然后将此实例分配给instance变量,因此它绑定到具有这两个实例属性的东西:foofoo_list.

但:

print instance.bar
Run Code Online (Sandbox Code Playgroud)

得到:

I am a class attribute called bar
Run Code Online (Sandbox Code Playgroud)

这怎么发生的?当我们尝试通过点语法检索属性,并且该属性不存在时,Python会通过一系列步骤来尝试完成您的请求.它将尝试的下一件事是查看实例类的类属性.在这种情况下,它发现一个属性barSomeClass,所以它返回.

这也是方法调用的方式.mylist.append(5)例如,当您调用时,mylist没有名为的属性append.但mylist事情,它绑定到一个方法的对象.该方法对象由该mylist.append位返回,然后该(5)位使用参数调用该方法5.

这有用的方式是所有实例SomeClass都可以访问相同的bar属性.我们可以创建一百万个实例,但我们只需要将一个字符串存储在内存中,因为它们都可以找到它.

但你必须要小心一点.看看以下操作:

sc1 = SomeClass()
sc1.foo_list.append(1)
sc1.bar_list.append(2)

sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append(20)

print sc1.foo_list
print sc1.bar_list

print sc2.foo_list
print sc2.bar_list
Run Code Online (Sandbox Code Playgroud)

你认为这印刷什么?

[1]
[2, 20]
[10]
[2, 20]
Run Code Online (Sandbox Code Playgroud)

这是因为每个实例都有自己的副本foo_list,所以它们是分别附加的.但是所有实例都共享访问权限bar_list.所以当我们sc1.bar_list.append(2)受影响时sc2,即使它sc2还不存在!同样sc2.bar_list.append(20)影响了bar_list检索通过sc1.这通常不是你想要的.


高级研究如下.:)

要真正理解Python,来自传统的静态类型的OO语言,如Java和C#,你必须学会​​重新思考类.

在Java中,一个类本身并不是一个真正的东西.当你编写一个类时,你会更多地声明该类的所有实例都有共同点.在运行时,只有实例(和静态方法/变量,但这些实际上只是与类关联的命名空间中的全局变量和函数,与OO无关).类是您在源代码中记下实例在运行时将会是什么样的方式; 它们只在源代码中"存在",而不是在正在运行的程序中.

在Python中,类没什么特别的.它就像其他任何东西一样.所以"类属性"实际上与"实例属性"完全相同; 实际上只有"属性".绘制区别的唯一原因是我们倾向于使用与不是类的对象不同的类的对象.底层机器都是一样的.这就是为什么我说将类属性视为来自其他语言的静态变量是错误的.

但真正使Python类与Java风格类不同的是,就像任何其他对象一样,每个类都是某个类的实例!

在Python中,大多数类都是内置类的实例type.正是这个类控制着类的常见行为,并以它的方式完成所有OO的操作.具有自己的属性的类的实例以及由其类定义的公共方法/属性的默认OO方式只是Python中的协议.如果需要,您可以更改它的大多数方面.如果你听说过使用元类,那就是定义一个类,它是一个不同类的实例type.

关于类的唯一真正"特殊"的事情(除了所有内置机制使它们以默认方式工作),是类块语法,以便您更容易创建实例type.这个:

class Foo(BaseFoo):
    def __init__(self, foo):
        self.foo = foo

    z = 28
Run Code Online (Sandbox Code Playgroud)

大致相当于以下内容:

def __init__(self, foo):
    self.foo = foo

classdict = {'__init__': __init__, 'z': 28 }

Foo = type('Foo', (BaseFoo,) classdict)
Run Code Online (Sandbox Code Playgroud)

它将安排所有内容classdict成为创建对象的属性.

因此,看到您可以像访问类Class.attribute一样轻松地访问类属性变得非常简单i = Class(); i.attribute.这两个iClass的对象,对象也有属性.这也使您很容易理解如何在创建类之后修改它; 只需像对待任何其他对象一样分配其属性!

实际上,实例与用于创建它们的类没有特别的特殊关系.Python知道哪个类搜索实例中未找到的__class__属性的方式是隐藏属性.您可以阅读以找出这是一个实例的类,就像使用任何其他属性一样:c = some_instance.__class__.现在你有一个c绑定到类的变量,即使它可能与类没有相同的名称.您可以使用它来访问类属性,甚至可以调用它来创建更多的实例(即使您不知道它是什么类!).

你甚至可以指定i.__class__改变它是一个实例的类!如果你这样做,没有特别的事情立即发生.这不是惊天动地.所有这一切意味着当你查找实例中不存在的属性时,Python将会查看新的内容__class__.由于这包括大多数方法,并且方法通常期望它们正在操作的实例处于某些状态,如果你随机执行它通常会导致错误,并且它非常令人困惑,但它可以完成.如果你非常小心,你存储的东西__class__甚至不必是一个类对象; 所有Python都会在某些情况下查找属性,所以你需要的只是一个具有正确类型属性的对象(除了Python在某些类或特定类的实例中变得挑剔之外,还有一些注意事项).

这可能就足够了.希望(如果你甚至读过这篇文章)我并没有太多困惑你.当你了解它的工作原理时,Python很简洁.:)

  • 我的评论(我花了太长时间写的)在你的帖子的第二部分得到了忍者!干得好.:) (2认同)

voi*_*hos 10

你所谓的"实例"变量实际上并不是一个实例变量; 它是一个类变量.请参阅有关类语言参考.

在您的示例中,a似乎是一个实例变量,因为它是不可变的.在分配可变对象时,可以看到它作为变量的性质:

>>> class Complex:
>>>    a = []
>>>
>>> b = Complex()
>>> c = Complex()
>>> 
>>> # What do they look like?
>>> b.a
[]
>>> c.a
[]
>>> 
>>> # Change b...
>>> b.a.append('Hello')
>>> b.a
['Hello']
>>> # What does c look like?
>>> c.a
['Hello']
Run Code Online (Sandbox Code Playgroud)

如果你使用过self,那么它将是一个真正的实例变量,因此每个实例都有它自己的唯一a.创建新实例时__init__调用对象的函数,并且self该函数是对该实例的引用.

  • 那么基本上类变量就像其他语言中的静态变量那么? (5认同)