Python中的类和实例变量之间有什么区别? [英] What is the difference between class and instance variables in Python?

查看:163
本文介绍了Python中的类和实例变量之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python中的类变量和实例变量之间的区别是什么?

  class Complex:
a = 1

  class Complex:
def __init __(self):
self.a = 1

使用调用: x = Complex()。a 在这两种情况下将x分配给1。



将对 __ init __() self 更深入的回答。

解决方案

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



类实例被创建,对实例的引用的任何东西都可以在其上创建实例属性。在内部方法中,当前实例几乎总是绑定到名称 self ,这就是为什么你认为这些作为自变量。通常在面向对象设计中,附加到类的代码应该具有对该类的实例的属性的控制,因此几乎所有的实例属性赋值都在方法中完成,使用对<$ cc中接收的实例的引用$ c> self 方法的参数。



类属性通常与静态变量如在Java,C#或C ++语言中找到的。然而,如果你想要更深入的理解,我会避免把类属性看作是相同作为静态变量。虽然它们经常用于相同的目的,但基本概念是完全不同的。



例子!

 

code> class SomeClass:
def __init __(self):
self.foo ='我是一个实例属性称为foo'
self.foo_list = []

bar ='我是一个类属性称为bar'
bar_list = []

执行此块后,有一个类 SomeClass ,有3个类属性: __ init __ bar bar_list



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

  instance = SomeClass()

当发生这种情况时,执行 SomeClass __ init __ 它的 self 参数。此方法创建两个实例属性: foo foo_list 。然后这个实例被分配到实例变量中,因此它绑定到一个带有两个实例属性的事物: foo foo_list



但:

  print instance.bar 

提供:

 我是一个类属性bar 

这是如何发生的?当我们尝试通过点语法检索属性时,该属性不存在,Python通过一系列步骤尝试并满足您的请求。接下来要做的是查看实例类的类属性。在这种情况下,它在 SomeClass 中找到一个属性 bar ,因此它返回了



这也是方法调用如何工作的方式。当调用 mylist.append(5)时,例如 mylist 没有名为 append 。但是 mylist 会绑定到方法对象。该方法对象由 mylist.append 位返回,然后(5)位调用该方法 5 。



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



但是你必须要小心。请查看以下操作:

  sc1 = SomeClass()
sc1.foo_list.append b $ b sc1.bar_list.append(2)

sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append
$ b print sc1.foo_list
print sc1.bar_list

print sc2.foo_list
print sc2.bar_list

您认为这是什么打印?

  [1 ] 
[2,20]
[10]
[2,20]

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






高级研究如下。 :)



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

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



在Python中,一个类没什么特别的。它是一个对象就像任何其他。所以类属性事实上与实例属性完全相同;在现实中只有属性。区分的唯一原因是我们倾向于使用对象,这些对象不同于不是类的对象。底层的机械是一样的。这就是为什么我说将类属性看作来自其他语言的静态变量是错误的。



但是真正让Python类与Java风格不同的东西类是任何其他对象每个类都是一些类

的实例!



在Python中,大多数类都是内置类的实例调用 type 。它是控制类的常见行为的类,并使所有的OO东西的方式。默认的OO方式拥有具有自己的属性的类的实例,并且具有由它们的类定义的通用方法/属性,只是Python中的协议。如果你愿意,你可以改变它的大部分。如果你曾听说过使用元类,所有这一切都是定义一个类是类型的不同类的实例。 / p>

类的唯一真正特殊的东西(除了所有的内置机制,使他们按照他们默认的方式工作),是类块语法,更容易创建类型的实例。这个:

  class Foo(BaseFoo):
def __init __(self,foo):
self。 foo = foo

z = 28

大致相当于以下内容: / p>

  def __init __(self,foo):
self.foo = foo

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

Foo = type('Foo',(BaseFoo,)classdict)

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



因此,看起来您可以通过 Class.attribute 访问类属性变得非常简单,就像 i = Class(); i.attribute i 是对象,对象具有属性。这也使得很容易理解如何在类创建后修改它;只需按照与任何其他对象相同的方式分配其属性!



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



你甚至可以分配 i .__ class __ 来改变它是一个实例的类。如果你这样做,什么都不会立即发生。这不是毁灭性的。这意味着当你查找实例中不存在的属性时,Python将会查看 __ class __ 的新内容。由于这包括大多数方法,并且方法通常期望他们正在操作的实例处于某些状态,这通常导致错误,如果你做随机,它是非常混乱,但它可以做到。如果你很小心,你存储在 __ class __ 的东西甚至不必是一个类对象;所有Python的做法是在某些情况下查找属性,所以你需要的是一个具有正确类型的属性的对象(一些注意事项,Python确实挑选了某些特定类的实例或类)。



这可能足够了。希望(如果你甚至读了这么远)我没有混淆你太多。 Python是整洁的,当你学习它是如何工作的。 :)


What is the difference between class and instance variables in Python?

class Complex:
    a = 1

and

class Complex:
    def __init__(self):
        self.a = 1

Using the call: x = Complex().a in both cases assigns x to 1.

A more in-depth answer about __init__() and self will be appreciated.

解决方案

When you write a class block, you create class attributes (or class variables). All the names you assign in the class block, including methods you define with def become class attributes.

After a class instance is created, anything with a reference to the instance can create instance attributes on it. Inside methods, the "current" instance is almost always bound to the name self, which is why you are thinking of these as "self variables". Usually in object-oriented design, the code attached to a class is supposed to have control over the attributes of instances of that class, so almost all instance attribute assignment is done inside methods, using the reference to the instance received in the self parameter of the method.

Class attributes are often compared to static variables (or methods) as found in languages like Java, C#, or C++. However, if you want to aim for deeper understanding I would avoid thinking of class attributes as "the same" as static variables. While they are often used for the same purposes, the underlying concept is quite different. More on this in the "advanced" section below the line.

An example!

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 = []

After executing this block, there is a class SomeClass, with 3 class attributes: __init__, bar, and bar_list.

Then we'll create an instance:

instance = SomeClass()

When this happens, SomeClass's __init__ method is executed, receiving the new instance in its self parameter. This method creates two instance attributes: foo and foo_list. Then this instance is assigned into the instance variable, so it's bound to a thing with those two instance attributes: foo and foo_list.

But:

print instance.bar

gives:

I am a class attribute called bar

How did this happen? When we try to retrieve an attribute through the dot syntax, and the attribute doesn't exist, Python goes through a bunch of steps to try and fulfill your request anyway. The next thing it will try is to look at the class attributes of the class of your instance. In this case, it found an attribute bar in SomeClass, so it returned that.

That's also how method calls work by the way. When you call mylist.append(5), for example, mylist doesn't have an attribute named append. But the class of mylist does, and it's bound to a method object. That method object is returned by the mylist.append bit, and then the (5) bit calls the method with the argument 5.

The way this is useful is that all instances of SomeClass will have access to the same bar attribute. We could create a million instances, but we only need to store that one string in memory, because they can all find it.

But you have to be a bit careful. Have a look at the following operations:

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

What do you think this prints?

[1]
[2, 20]
[10]
[2, 20]

This is because each instance has its own copy of foo_list, so they were appended to separately. But all instances share access to the same bar_list. So when we did sc1.bar_list.append(2) it affected sc2, even though sc2 didn't exist yet! And likewise sc2.bar_list.append(20) affected the bar_list retrieved through sc1. This is often not what you want.


Advanced study follows. :)

To really grok Python, coming from traditional statically typed OO-languages like Java and C#, you have to learn to rethink classes a little bit.

In Java, a class isn't really a thing in its own right. When you write a class you're more declaring a bunch of things that all instances of that class have in common. At runtime, there's only instances (and static methods/variables, but those are really just global variables and functions in a namespace associated with a class, nothing to do with OO really). Classes are the way you write down in your source code what the instances will be like at runtime; they only "exist" in your source code, not in the running program.

In Python, a class is nothing special. It's an object just like anything else. So "class attributes" are in fact exactly the same thing as "instance attributes"; in reality there's just "attributes". The only reason for drawing a distinction is that we tend to use objects which are classes differently from objects which are not classes. The underlying machinery is all the same. This is why I say it would be a mistake to think of class attributes as static variables from other languages.

But the thing that really makes Python classes different from Java-style classes is that just like any other object each class is an instance of some class!

In Python, most classes are instances of a builtin class called type. It is this class that controls the common behaviour of classes, and makes all the OO stuff the way it does. The default OO way of having instances of classes that have their own attributes, and have common methods/attributes defined by their class, is just a protocol in Python. You can change most aspects of it if you want. If you've ever heard of using a metaclass, all that is is defining a class that is an instance of a different class than type.

The only really "special" thing about classes (aside from all the builtin machinery to make them work they way they do by default), is the class block syntax, to make it easier for you to create instances of type. This:

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

    z = 28

is roughly equivalent to the following:

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

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

Foo = type('Foo', (BaseFoo,) classdict)

And it will arrange for all the contents of classdict to become attributes of the object that gets created.

So then it becomes almost trivial to see that you can access a class attribute by Class.attribute just as easily as i = Class(); i.attribute. Both i and Class are objects, and objects have attributes. This also makes it easy to understand how you can modify a class after it's been created; just assign its attributes the same way you would with any other object!

In fact, instances have no particular special relationship with the class used to create them. The way Python knows which class to search for attributes that aren't found in the instance is by the hidden __class__ attribute. Which you can read to find out what class this is an instance of, just as with any other attribute: c = some_instance.__class__. Now you have a variable c bound to a class, even though it probably doesn't have the same name as the class. You can use this to access class attributes, or even call it to create more instances of it (even though you don't know what class it is!).

And you can even assign to i.__class__ to change what class it is an instance of! If you do this, nothing in particular happens immediately. It's not earth-shattering. All that it means is that when you look up attributes that don't exist in the instance, Python will go look at the new contents of __class__. Since that includes most methods, and methods usually expect the instance they're operating on to be in certain states, this usually results in errors if you do it at random, and it's very confusing, but it can be done. If you're very careful, the thing you store in __class__ doesn't even have to be a class object; all Python's going to do with it is look up attributes under certain circumstances, so all you need is an object that has the right kind of attributes (some caveats aside where Python does get picky about things being classes or instances of a particular class).

That's probably enough for now. Hopefully (if you've even read this far) I haven't confused you too much. Python is neat when you learn how it works. :)

这篇关于Python中的类和实例变量之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆