Home  >  Article  >  Backend Development  >  Understanding references and class attributes in Python

Understanding references and class attributes in Python

大家讲道理
大家讲道理Original
2016-11-07 17:18:111016browse

Recently, I have done a little research on Python’s object reference mechanism and left notes for reference.

First of all, one thing is clear: "Everything in Python is an object."

So, what does this mean?

The following code:

#!/usr/bin/env python
a = [0, 1, 2] # 来个简单的list
# 最初,list 和其中各个元素的id 是这样的。
print 'origin'
print id(a),a
for x in a:
    print id(x), x
print '----------------------'
# 我们把第一个元素改改
print 'after change a[0]'
a[0] = 4
print id(a),a
for x in a:
    print id(x), x
print '----------------------'
# 我们再把第二个元素改改
print 'after change a[1]'
a[1] = 5
print id(a),a
for x in a:
    print id(x), x
print '----------------------'
# 回头看看直接写个0 ,id是多少
print 'how about const 0?'
print id(0), 0

The running results are as follows:

PastgiftMacbookPro:python pastgift$ ./refTest.py

Origin

4299760200 [0, 1, 2]

4298181328 0

4298181304 1

4298181280 2

----------------------

after change a[0]

4299760200 [4, 1, 2]

4298181232 4

4298181304 1

4298181280 2

----------------------

after change a[1]

4299760200 [4, 5, 2]

4298181232 4

4298181208 5

4298181280 2

-------------------------

how about const 0?

4298181328 0

Looking at the "Origin" part, the addresses of each element in the list are exactly 24 apart, pointing to their respective data in turn - this reminds me of an array.

After modifying the value of a[0], it was found that the address of a[0] has changed. In other words, the assignment statement actually just makes a[0] point to another object again. In addition, it is also noted that the address of a[0] and the address of a[2] differ by 48 (two 24s).

When a[1] is modified again, the address of a[1] also changes. Interestingly, this time the address of a[1] and the address of a[0] differ by 24, which is different from the original a[2] differs by 72 (three 24s).

Finally, after printing the address of the number 0 directly, we found that its address is exactly the same as the address of the original a[0].

At this point, it can be basically explained that even the elements in the list are actually references. Modifying the elements in the list is actually modifying the reference.

Regarding class attributes in Python, someone mentioned that "class attributes are shared between the same class and its subclasses, and modifying class attributes will affect all objects of the same class and its subclasses."

It sounds scary, but after careful study, it’s actually not a big deal.

The following code:

#!/usr/bin/env python
class Bird(object):
    name = 'bird'
    talent = ['fly']
class Chicken(Bird):
    pass
bird = Bird();
bird2 = Bird(); # 同类实例
chicken = Chicken(); # 子类实例
# 最开始是这样的
print 'Original attr'
print id(bird.name),      bird.name
print id(bird.talent),    bird.talent
print id(bird2.name),     bird2.name
print id(bird2.talent),   bird2.talent
print id(chicken.name),   chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------'
# 换个名字看看
bird.name = 'bird name changed!'
print 'after changing name'
print id(bird.name),      bird.name
print id(bird.talent),    bird.talent
print id(bird2.name),     bird2.name
print id(bird2.talent),   bird2.talent
print id(chicken.name),   chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------'
# 洗个天赋试试(修改类属性中的元素)
bird.talent[0] = 'walk'
print 'after changing talent(a list)'
print id(bird.name),      bird.name
print id(bird.talent),    bird.talent
print id(bird2.name),     bird2.name
print id(bird2.talent),   bird2.talent
print id(chicken.name),   chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------'
# 换个新天赋树(整个类属性全换掉)
bird.talent = ['swim']
print 'after reassign talent'
print id(bird.name),      bird.name
print id(bird.talent),    bird.talent
print id(bird2.name),     bird2.name
print id(bird2.talent),   bird2.talent
print id(chicken.name),   chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------'
# 洗掉新天赋树(对新来的类属性中的元素进行修改)
bird.talent[0] = 'dance'
print 'changing element after reassigning talent'
print id(bird.name),      bird.name
print id(bird.talent),    bird.talent
print id(bird2.name),     bird2.name
print id(bird2.talent),   bird2.talent
print id(chicken.name),   chicken.name
print id(chicken.talent), chicken.talent
print '----------------------------'

Running result:


PastgiftMacbookPro:python pastgift$ ./changeAttributeTest.py

Original att r

4301998000 bird

4301857352 ['fly']

4301998000 bird

4301857352 ['fly']

4301998000 bird

4301857352 ['fly']

--------------------- ----

after changing name

4301986984 bird name changed!

4301857352 ['fly']

4301998000 bird

4301857352 ['fly']

43019 98000 bird

4301857352 ['fly']

----------------------------

after changing talent(a list)

4301986984 bird name changed!

4301857352 ['walk ']

4301998000 bird

4301857352 ['walk']

4301998000 bird

4301857352 ['walk']

------------------------ ------

after reassign talent

4301986984 bird name changed!

4301859512 ['swim']

4301998000 bird

4301857352 ['walk']

4 301998000 bird

4301857352 ['walk']

----------------------------

changing element after reassigning talent

4301986984 bird name changed!

4301859512 ['dance ']

4301998000 bird

4301857352 ['walk']

4301998000 bird

4301857352 ['walk']

------------------------ ------

In "Origin", the addresses of the same class attributes of objects of the same type and subclass objects are the same - this is the so-called "sharing".

After modifying the name, only the name attribute of the modified object changes. This is because the assignment operation to name is actually changing a string and re-quoting it. The string itself has not changed. Therefore, there is no mutual influence between the same category and subcategories.

Next, modify the elements in talent. At this time, the situation has changed: the talent attributes of the same class and its subclasses have all changed together - this is easy to understand, because they all refer to the same memory address and refer to the same object.

Next, reassign the talent, that is, change it to reference another object. The result is that only the talent attribute of this instance changes. It can be seen from the memory address that the talent attributes of this instance and other instances no longer point to the same object. That is to say, "At this point, this example is already an outsider."

Then, after finally modifying the elements in talent again, it is easy to understand that it has no effect on other instances. Because I am already an "outsider", no matter how much I mess with it, it is all my own business.

所以,「类属性在同类及其子类之间互相影响」必须有一个前提条件:实例建立后,其类属性从来没有被重新赋值过,即类属性依然指向最初所指向的内存地址。

最后提一下对象属性

如下代码:


#!/usr/bin/env python
class Bird(object):
    def __init__(self):
        self.talent = ['fly']
bird = Bird()
bird2 = Bird()
# 刚开始的情形
print 'Origin'
print id(bird.talent), bird.talent
print id(bird2.talent), bird2.talent
print '--------------------'
# 修改其中一个对象的属性
bird.talent[0] = 'walk'
print 'after changing attribute'
print id(bird.talent), bird.talent
print id(bird2.talent), bird2.talent
print '--------------------'
# 作死:两个对象的属性指向同一个内存地址,再修改
bird.talent = bird2.talent
bird.talent[0] = 'swim'
print 'assign to another attribute and change it'
print id(bird.talent), bird.talent
print id(bird2.talent), bird2.talent
print '--------------------'

运行结果:

PastgiftMacbookPro:python pastgift$ ./changeAttributeTest2.py 

Origin

4299867632 ['fly']

4299760200 ['fly']

--------------------

after changing attribute

4299867632 ['walk']

4299760200 ['fly']

--------------------

assign to another attribute and change it

4299760200 ['swim']

4299760200 ['swim']

--------------------

   

由于对象属性就算内容完全一样(刚初始化后的属性内容一般都是一样的),也会分配到完全不同的内存地址上去。所以不存在「同类对象之间影响」的情况。

但如果让一个对象的属性和另一个对象的属性指向同一个地址,两者之间(但也仅限两者之间)便又互相牵连起来。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn