Python Class Members

有些话、适合烂在心里 提交于 2019-11-26 10:28:52

问题


I am just learning Python and I come from a C background so please let me know if I have any confusion / mix up between both.

Assume I have the following class:

class Node(object):
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

    @classmethod
    def tree(cls, element, left, right):
        node = cls(element)
        node.left = left
        node.right = right
        return node

This is a class named Node, that overloads the constructor, to be able to handle different arguments if needed.

What is the difference between defining self.element in __init__ only (as shown above) as opposed to doing the following:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

Isn\'t self.element in __init__ the same as the class\'s element variable defined? Wouldn\'t that just overwrite element from None to the element value passed into __init__?


回答1:


One is a class attribute, while the other is an instance attribute. They are different, but they are closely related to one another in ways that make them look the same at times.

It has to do with the way python looks up attributes. There's a hierarchy. In simple cases it might look like this:

instance -> Subclass -> Superclass -> object (built-in type)

When you look for an attribute on instance like this...

`instance.val`

...what actually happens is that first, Python looks for val in the instance itself. Then, if it doesn't find val, it looks in its class, Subclass. Then, if it doesn't find val there, it looks in the parent of Subclass, Superclass. This means that when you do this...

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

...all instances of Foo share foovar, but have their own distinct selfvars. Here's a simple, concrete example of how that works:

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

If we don't touch foovar, it's the same for both f and Foo. But if we change f.foovar...

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

...we add an instance attribute that effectively masks the value of Foo.foovar. Now if we change Foo.foovar directly, it doesn't affect our foo instance:

>>> Foo.foovar = 7
>>> f.foovar
5

But it does affect a new foo instance:

>>> Foo(5).foovar
7

Also keep in mind that mutable objects add another layer of indirection (as mgilson reminded me). Here, f.foovar refers to the same object as Foo.foovar, so when you alter the object, the changes are propagated up the hierarchy:

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]



回答2:


In python it is possible to have class variables and instance variables of the same name. They are located separately in memory, and are accessed quite differently.

In your code:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

The first set of variables (outside the __init__ function) are called class variables. These can be subsequently accessed using Node.element, etc. These are equivalent to static member variables in C++, and they are shared by all instances of the class.

The second set of variables (inside the __init__ function) are called instance variables. These are accessed via the self object, e.g. self.element, or by the instance name e.g. myNode.element outside of the class.

It is important to note that you have to use either the self.variable or Node.variable form to access either of these from within a member function. Just accessing variable will try to access a local variable called variable.




回答3:


self.element inside the constructor is an instance variable (if a node object modifies its value it only changes for this object) where the one in the second version is a class variable (so if one node object modifies its value it will change for all node objects).

The analogy in C++ would be non-static versus static member variables in your class.




回答4:


self.element in the init is an instance variable, you can get/set it in any other member function by typing self.element. element declared in the class is the class variable, you can get/set it by typing Node.element.




回答5:


The important part is the self argument to __init__. In fact, in any instance method, this will be the first argument. This is done by design; in Python, the only time you actually have access to the instance is during method calls, and it is shown explicitly with the self argument.

When you're inside of a class definition, you don't have any instances yet, so what you're really modifying is the class itself. Thus, if you define attributes at class-level, then they really become class attributes, and not instance.

Comparing it to a C(++), you could probably say that "classes" in those languages are basically blueprints for the objects that they represent. "These objects shall have foo and bar attributes, and, in addition, the following methods." In Python, however, classes are objects themselves, and their main strength is that they can create copies (instances) of themselves, which also happen to use the class's methods. So, it's more like "Thou shall have foo and bar as class attributes, and, in addition, the following method which thou shall use to create instances."

So, instead of a blueprint, it's more of a step-by-step how-to.




回答6:


when you try to access the variable with a class it look into only

cls.__dict__

but when you try to access the variable with instance it looks first

self.__dict__ 

if find then return or if can't find then it also looks in

cls.__dict__

here cls is the class

class Test:
    temp_1=10
    temp_2=20

    def __init__(self):
        self.test_1=10
        self.test_2=20

    @classmethod
    def c_test(cls):
        pass

    def t_method(self):
        pass


print Test.__dict__
print Test().__dict__

Output:

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}

{'test_2': 20, 'test_1': 10}

For detail class special attribute



来源:https://stackoverflow.com/questions/12409714/python-class-members

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