目录
1 类变量和实例变量
2 类对象和实例对象
2.1 类对象
2.2 实例对象
3 属性绑定
3.1 类属性绑定
3.2 实例属性绑定
4 属性引用
4.1 类属性引用
4.2 实例属性引用
4.2.1 数据属性引用
4.2.2 方法属性引用
5. **实践
1 类变量和实例变量
通常来说,实例变量是对于每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法。
其实我更愿意用类属性和实例属性来称呼它们,但是变量这个词已经成为程序语言的习惯称谓。一个正常的示例是:
class Dog: kind = 'canine' # class variable shared by all instances def __init__(self, name): self.name = name # instance variable unique to each instance
讯享网
类Dog中,类属性kind为所有实例所共享;实例属性name为每个Dog的实例独有。
2 类对象和实例对象
2.1 类对象
Python中一切皆对象;类定义完成后,会在当前作用域中定义一个以类名为名字,指向类对象的名字。如
讯享网class Dog: pass
会在当前作用域定义名字Dog,指向类对象Dog。
类对象支持的操作:
总的来说,类对象仅支持两个操作:
- 实例化;使用
instance_name = class_name()的方式实例化,实例化操作创建该类的实例。 - 属性引用;使用
class_name.attr_name的方式引用类属性。
2.2 实例对象
实例对象是类对象实例化的产物,实例对象仅支持一个操作:
- 属性引用;与类对象属性引用的方式相同,使用
instance_name.attr_name的方式。
按照严格的面向对象思想,所有属性都应该是实例的,类属性不应该存在。那么在Python中,由于类属性绑定就不应该存在,类定义中就只剩下函数定义了。
实践中,类定义中的语句通常是函数定义,但是其他语句也是允许的,有时也是有用的。
这里说的其他语句,就是指类属性的绑定语句。
3 属性绑定
在定义类时,通常我们说的定义属性,其实是分为两个方面的:
- 类属性绑定
- 实例属性绑定
用绑定这个词更加确切;不管是类对象还是实例对象,属性都是依托对象而存在的。
我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作,使用 objname.attr = attr_value 的方式,为对象objname绑定属性attr。
这分两种情况:
- 若属性
attr已经存在,绑定操作会将属性名指向新的对象; - 若不存在,则为该对象添加新的属性,后面就可以引用新增属性。
3.1 类属性绑定
Python作为动态语言,类对象和实例对象都可以在运行时绑定任意属性。因此,类属性的绑定发生在两个地方:
- 类定义时;
- 运行时任意阶段。
下面这个例子说明了类属性绑定发生的时期:

class Dog: kind = 'canine' Dog.country = 'China' print(Dog.kind, ' - ', Dog.country) # output: canine - China del Dog.kind print(Dog.kind, ' - ', Dog.country) # AttributeError: type object 'Dog' has no attribute 'kind'
在类定义中,类属性的绑定并没有使用 objname.attr = attr_value 的方式,这是一个特例,其实是等同于后面使用类名绑定属性的方式。因为是动态语言,所以可以在运行时增加属性,删除属性。
3.2 实例属性绑定
与类属性绑定相同,实例属性绑定也发生在两个地方:
- 类定义时;
- 运行时任意阶段。
讯享网class Dog: def __init__(self, name, age): self.name = name self.age = age dog = Dog('Lily', 3) dog.fur_color = 'red' print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.fur_color)) # Output: Lily is 3 years old, it has red fur
Python类实例有两个特殊之处:
__init__在实例化时执行Python实例调用方法时,会将实例对象作为第一个参数传递
因此,__init__方法中的self就是实例对象本身,这里是dog,语句
self.name = name self.age = age
以及后面的语句
讯享网dog.fur_color = 'red'
为实例dog增加三个属性name, age, fur_color。
4 属性引用
属性的引用与直接访问名字不同,不涉及到作用域。
4.1 类属性引用
类属性的引用,肯定是需要类对象的,属性分为两种:
- 数据属性
- 函数属性
(1)数据属性引用很简单,示例:
class Dog: kind = 'canine' Dog.country = 'China' print(Dog.kind, ' - ', Dog.country) # output: canine - China
(2)通常很少有引用类函数属性的需求,示例:
讯享网class Dog: kind = 'canine' def tell_kind(): print(Dog.kind) Dog.tell_kind() # Output: canine
函数 tell_kind 在引用kind需要使用Dog.kind而不是直接使用kind,涉及到作用域,这一点在我的另一篇文章中有介绍:Python进阶 - 命名空间与作用域
4.2 实例属性引用
使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:
- 总是先到实例对象中查找属性,再到类属性中查找属性;
- 属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象。
4.2.1 数据属性引用
示例1:
class Dog: kind = 'canine' country = 'China' def __init__(self, name, age, country): self.name = name self.age = age self.country = country dog = Dog('Lily', 3, 'Britain') print(dog.name, dog.age, dog.kind, dog.country) # output: Lily 3 canine Britain
类对象Dog与实例对象dog均有属性country,按照规则,dog.country会引用到实例对象的属性;但实例对象dog没有属性kind,按照规则会引用类对象的属性。
讯享网class Dog: kind = 'canine' country = 'China' def __init__(self, name, age, country): self.name = name self.age = age self.country = country dog = Dog('Lily', 3, 'Britain') print(dog.name, dog.age, dog.kind, dog.country) # Lily 3 canine Britain print(dog.__dict__) # {'name': 'Lily', 'age': 3, 'country': 'Britain'} 没有kind dog.kind = 'feline' print(dog.name, dog.age, dog.kind, dog.country) # Lily 3 feline Britain print(dog.__dict__) # {'name': 'Lily', 'age': 3, 'country': 'Britain', 'kind': 'feline'} print(Dog.kind) # canine 没有改变类属性的指向
使用属性绑定语句dog.kind = 'feline',按照规则,为实例对象dog增加了属性kind,后面使用dog.kind引用到实例对象的属性。
这里不要以为会改变类属性Dog.kind的指向,实则是为实例对象新增属性,可以使用查看__dict__的方式证明这一点。
示例3,可变类属性引用:
class Dog: tricks = [] def __init__(self, name): self.name = name def add_trick(self, trick): self.tricks.append(trick) d = Dog('Fido') e = Dog('Buddy') d.add_trick('roll over') e.add_trick('play dead') print(d.tricks) # ['roll over', 'play dead'] print(Dog.tricks) # ['roll over', 'play dead']
语句self.tricks.append(trick)并不是属性绑定语句,因此还是在类属性上修改可变对象。
4.2.2 方法属性引用
与数据成员不同,类函数属性在实例对象中会变成方法属性。
先看一个示例:
讯享网class MethodTest: def inner_test(self): print('in class') def outer_test(): print('out of class') mt = MethodTest() mt.outer_test = outer_test print(type(MethodTest.inner_test)) # <class 'function'> print(type(mt.inner_test)) #<class 'method'> print(type(mt.outer_test)) #<class 'function'> print(type(outer_test)) #<class 'function'>
可以看到,类函数属性在实例对象中变成了方法属性,但是并不是实例对象中所有的函数都是方法。
引用非数据属性的实例属性时,会搜索它对应的类。如果名字是一个有效的函数对象,Python会将实例对象连同函数对象打包到一个抽象的对象中并且依据这个对象创建方法对象:这就是被调用的方法对象。当使用参数列表调用方法对象时,会使用实例对象以及原有参数列表构建新的参数列表,并且使用新的参数列表调用函数对象。
mt.inner_test() mt.outer_test()
除了方法与函数的区别,其引用与数据属性都是一样的
5. **实践
虽然Python作为动态语言,支持在运行时绑定属性,但是从面向对象的角度来看,还是在定义类的时候将属性确定下来。
Python基础-类变量和实例变量:https://www.cnblogs.com/crazyrunning/p/6945183.html
Python动态语言的特性:https://blog.csdn.net/weixin_/article/details/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/27739.html