此博客参考了部分资料,具体链接在下方。
# 首先我们要知道变量分为 immutable 和 mutable
# imutable types : numbers, strings, tuples..
# mutable types : lists, dictionaries...
# 其中在Pytion中使用 mutable types 可能会引起 aliasing
class Dog:
# 类变量
kind = 'canine' # immutable
tricks = [] # mutable
def __init__(self, name):
# 实例变量
self.name = name
a = Dog('a')
b = Dog('b')
c = Dog('c')
# 通过一个对象a访问一个变量x,变量的查找过程是这样的:
# 先在对象自身的__dict__中查找是否有x,如果有则返回,否则
# 进入对象a所属的类A的__dict__中进行查找
# 例如:
a.kind # 结果返回 'canine'
# 对象a试图修改一个属于类的immutable的变量,则python会在内存中为对象a
# 新建一个kind变量,此时a就具有了属于自己的kind变量
a.kind = 'unknown'
a.__dict__ # {'kind': 'unknow', 'name': 'a'}
b.__dict__ # {'name': 'b'}
Dog.__dict__ # 'kind': 'canine','tricks': []
# 对象b试图修改一个mutable的变量tricks,
# 但是直接用一个列表lis(在内存中有自己的地址)赋值,并不会去访问类变量中的tricks,
# python会直接为对象b新建一个tricks变量并和lis指向同一个地址
lis = ['run','sit']
id(lis) # 内存地址:1527988934728
b.tricks = lis
id(b.tricks) # 内存地址:1527988934728
b.__dict__ # {'name': 'b', 'tricks': ['run', 'sit']}
a.__dict__ # {'kind': 'unknow', 'name': 'a'}
Dog.__dict__ # 'kind': 'canine','tricks': []
# 对象c也试图修改一个mutable的变量,但在c中找不到该变量,
# 则python找到类Dog的__dict__中的变量tricks,
# 类Dog以及它的实例(__dict__中没有变量tricks的)都公用一个tricks
c.tricks.append('run')
c.__dict__ # {'name': 'c'}
a.__dict__ # {'kind': 'unknow', 'name': 'a'}
Dog.__dict__ # 'kind': 'canine','tricks': [run]
# 在编写程序的时候,实例变量和类变量请不要使用相同的名字
# 相同名称的实例变量将屏蔽掉类变量
# 使用类变量的时候也要注意 aliasing
参考资料:
Python中的aliasing
Python:Immutable vs Mutable types
官方教程 - python3.5 Docs
廖雪峰 - 实例属性和类属性
python的类变量与实例变量以及__dict__
属性