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

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

问题描述

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

  class Complex:
a = 1

 类复杂:
def __init __(self):
self.a = 1

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



对于 __ init __() self 的更深入的回答,将不胜感激。

解决方案

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



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



通常将类属性与 static 变量(或方法)进行比较在Java,C#或C ++等语言中可以找到。但是,如果您想更深入地理解,我会避免将类属性视为与静态变量相同。尽管它们通常用于相同的目的,但基本概念却大不相同。



一个例子!

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

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

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



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

  instance = SomeClass()

发生这种情况时,将执行 SomeClass __ init __ 方法,并在其中接收新实例。其 self 参数。此方法创建两个实例属性: foo foo_list 。然后将此实例分配到 instance 变量中,因此将其绑定到具有以下两个实例属性的事物: foo foo_list



但是:

  print instance.bar 

给出:

 我是一个叫做bar 
的类属性

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



这也是方法调用的方式。例如,当您调用 mylist.append(5)时, mylist 没有名为<$ c的属性。 $ c>追加。但是 mylist class 可以,并且绑定到方法对象。该方法对象由 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)

打印sc1.foo_list
打印sc1.bar_list

打印sc2.foo_list
打印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 。这通常不是您想要的。






接下来是高级研究。 :)



要真正掌握Python,它来自传统的静态类型的OO语言(例如Java和C#),则必须学习重新考虑类。



在Java中,类本身并不是真正的事物。编写课程时,您要声明的是该课程的所有实例都具有的共同点。在运行时,只有实例(和静态方法/变量,但它们实际上只是与类关联的名称空间中的全局变量和函数,与OO无关)。类是您在源代码中写下实例在运行时的样子的方式。它们只存在于您的源代码中,而不存在于正在运行的程序中。



在Python中,类没什么特别的。就像其他物体一样因此,类属性实际上与实例属性完全相同;实际上,只有属性。产生区别的唯一原因是我们倾向于使用类的对象与非类对象不同。底层机制都是一样的。这就是为什么我说将类属性视为其他语言的静态变量是错误的。



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



在Python中,大多数类都是内置类的实例称为类型。正是这个类控制着类的通用行为,并使所有OO东西按其方式进行。具有类的实例的默认的OO方法是拥有自己的属性,并具有由类定义的通用方法/属性,这只是Python中的协议。您可以根据需要更改其大多数方面。如果您曾经听说过使用 metaclass ,那么所有定义的是一个与 type 不同的类的实例。 / p>

关于类的唯一真正特殊的东西(除了所有内置的机制,使它们按默认方式工作)是类块语法,您可以轻松创建类型的实例。这:

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

z = 28

大致等同于以下内容:

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

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

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

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



因此,看到您可以通过 Class.attribute 访问类属性就像<$一样简单c $ c> i = Class(); i.attribute 。 i Class 都是对象,并且对象具有属性。这也使您易于理解如何在创建类后修改它;



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



您甚至可以分配给 i .__ class __ 来更改其实例的类!如果执行此操作,则不会立即发生任何特别的事情。这不是惊天动地。它的全部意思是,当您查找实例中不存在的属性时,Python会查看 __ class __ 的新内容。由于该方法包含大多数方法,并且方法通常希望它们所操作的实例处于特定状态,因此,如果您随机执行操作,通常会导致错误,这非常令人困惑,但是可以做到。如果您非常小心,则存储在 __ class __ 中的东西甚至不必是类对象。 Python要做的所有事情就是在特定情况下查找属性,因此您所需要的只是具有正确类型的属性的对象(除了一些警告,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. :)

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

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