Initializing field outside __init__

淺唱寂寞╮ 提交于 2021-02-10 03:18:34

问题


I need a bit of help to understand how python initialising works. I have a class (Bar) with another class (Foo) as a field/variable. When I try to initialise this variable directly in Bar (not in the class __init__) all instances of Bar will point to the same Foo. But if I have an __init__ method, as in Bar2, each Bar2 instance will have a unique Foo instance. What is happening here?

class Foo():
    number = 0

class Bar():
    foo = Foo()

class Bar2():
    foo = None

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

first = Bar()
second = Bar()

print "Bar"
print first
print second
print first.foo
print second.foo

first = Bar2()
second = Bar2()

print "\nBar2"
print first
print second
print first.foo
print second.foo

The output will for example be:

Bar
<\__main__.Bar instance at 0x025B2AF8>
<\__main__.Bar instance at 0x025B2B20>
<\__main__.Foo instance at 0x004A3AA8>
<\__main__.Foo instance at 0x004A3AA8>

Bar2
<\__main__.Bar2 instance at 0x025B2B48>
<\__main__.Bar2 instance at 0x025B2AF8>
<\__main__.Foo instance at 0x025B2B70>
<\__main__.Foo instance at 0x025B2B98>

Using Bar both instances will refer to the same Foo instance. Why?

Edit: Corrected the error with printing first.foo twice for Bar. The resulting behaviour is still as seen in the output.


回答1:


Python is a dynamic language. In static languages like Java, the compiler reads the code, finds the class definitions, figures out if they are proper and generates some code accordingly. In python, a class definition (or a function definition) is just a statement as any other, like an assignment to a variable. The syntax is just a bit different.

When defining a class, the interpreter runs the class definition, i.e., it runs all the code after the class line. If it finds function definitions, it runs them as well, that is defines the functions and binds them to the function name. Since class and function definitions are statements as any other assignment, you can also have them in many places. For example like following:

def foo():
  class A: pass
  a = A()
  a.msg = "Hello"
  return a

Because python is duck typed (if it quacks like a duck and looks like one, it is one), users of the function foo don't even have to know what the class is called, they simply need to know that foo returns an object with a member msg. You would use it like this:

a = foo()
print a.msg

So in your example, when the definition of Bar is executed, the classes statements are run including the creation of the Foo object. When the definition of Bar2 is executed, the classes statements are run among them the definition of a function called init. Python uses this as the name of the function to call, when an object is created (after calling another function __new__, but that's besides the point).

So again, the class definition (code that is inside the class, where Bar creates the Foo object) is run only once when the class is introduced. __init__ is called again and again every time a new object is made, so in Bar2 the creation of a Foo is done again and again as well.

The "foo = None" thing as far as I can tell is superfluous, it's not really needed. In python you can add instance variables from anywhere, even from outside the class and definitely from inside __init__.




回答2:


Bar.foo is a class variable. It is initialised once when the class is created.

(Note that your code als print first.foo twice, so no wonder the output is the same.)




回答3:


Classes are objects too, and they have their own set of variables. Not only that, but when Python can't find a variable in the object, it looks within the class to see if it can find it there, and that's what it uses. Since the class is shared between all the objects of that class, so are the variables within that class.




回答4:


first = Bar()
second = Bar()

print "Bar"
print first
print second
print first.foo
print first.foo

Here, you are printing first.foo twice, that's why the same foo object is printed.

first = Bar2()
second = Bar2()

print "\nBar2"
print first
print second
print first.foo
print second.foo

Here, foo is a static variable in class Bar2, that's why both objects point to the same foo object, constructed with the construction of second.

class Bar2():
 foo = None

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

class Bar():
 def __init__(self):
   self.foo = Foo()

In Bar2, all objects of Bar2, will have the foo object pointing to the same object constructed at the construction of the last constructed object of Bar2.

In Bar, all foo objects will be unique for every object of Bar, unless otherwise stated.



来源:https://stackoverflow.com/questions/12449107/initializing-field-outside-init

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!