赞
踩
在Python的类中,有着类属性、实例属性,静态方法、类方法、实例方法的区别。到底有什么不一样呢?接下来我们就一探究竟。
来看下简单的 Student
类的例子
class Student(object):
# 类属性
school = '井冈山大学'
def __init__(self, name):
# 实例属性
self.name = name
其中 school
是 Student
类的类属性,name
则是实例属性。
在 ipython
中测试一下如何访问其属性
In [5]: stu1 = Student('hui') In [6]: stu2 = Student('wang') In [7]: stu3 = Student('zack') In [8]: stu1.name, Student.school Out[8]: ('hui', '井冈山大学') In [9]: stu2.name, Student.school Out[9]: ('wang', '井冈山大学') In [10]: stu3.name, Student.school Out[10]: ('zack', '井冈山大学') # 看看实例对象能不能访问类属性,类对象能不能访问实例属性 In [11]: stu1.name, stu1.school Out[11]: ('hui', '井冈山大学') In [12]: Student.name, stu1.school --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-12-b897e001b174> in <module> ----> 1 Student.name, stu1.school AttributeError: type object 'Student' has no attribute 'name'
经过测试可以发现 实例属性需要通过实例对象来访问,类属性通过类来访问,但在测验中 stu1.school
实例对象也能访问类属性,为什么呢?
其实,实例对象也是间接的通过类对象进行访问的,在每一个实例对象中都有一个 __class__
的属性,其指向的就是创建实例对象的类对象。stu1.__class__
的指向就是 Student
类对象。然后实例对象访问属性的规则是先访问实例属性,然后再根据实例对象的 __class__
来访问类属性。如果都没有找到则报错。
In [15]: dir(stu1) Out[15]: ['__class__', '__delattr__', '__dict__', '__dir__', .... 'name', 'school'] In [16]: stu1.__class__ Out[16]: __main__.Student In [17]: stu1.__class__.school Out[17]: '井冈山大学' In [18]: id(Student) Out[18]: 2011692023944 In [19]: id(stu1.__class__) Out[19]: 2011692023944
可以看出 Student
,stu1.__class__
的 id()
都一样,说明其内存地址都一样。因此实例属性可以通过 __class__
访问类属性。
存储方式如下图
由上图可以看出:
还是以上面的例子在 ipython
中对类属性的修改进行测验
In [24]: class Student(object): ...: ...: # 类属性 ...: school = '井冈山大学' ...: ...: def __init__(self, name): ...: ...: # 实例属性 ...: self.name = name ...: In [25]: stu1 = Student('hui') In [26]: stu2 = Student('jack') In [27]: stu1.name, stu1.school Out[27]: ('hui', '井冈山大学') In [28]: stu2.name, stu2.school Out[28]: ('jack', '井冈山大学') # 通过类对象进行修改 In [29]: Student.school = '清华大学' In [30]: stu2.name, stu2.school Out[30]: ('jack', '清华大学') In [31]: stu1.name, stu1.school Out[31]: ('hui', '清华大学') # 通过实例对象进行修改 IIn [33]: stu1.school = '北京大学' In [34]: stu1.name, stu1.school Out[34]: ('hui', '北京大学') In [35]: stu2.name, stu2.school Out[35]: ('jack', '清华大学') In [36]: Student.school Out[36]: '清华大学' In [37]: stu1.__class__.school Out[37]: '清华大学' In [39]: id(stu2.school) Out[39]: 2011720409808 In [40]: id(Student.school) Out[40]: 2011720409808 In [41]: id(stu1.school) Out[41]: 2011720494992 # 通过实例对象的__class__属性修改 IIn [42]: stu2.__class__.school = '井冈山大学' In [43]: stu1.name, stu1.school Out[43]: ('hui', '北京大学') In [44]: stu2.name, stu2.school Out[44]: ('jack', '井冈山大学') In [45]: Student.school Out[45]: '井冈山大学'
说明: 实例对象.类属性 = xxx 并没有修改到其类属性,而是在实例对象中创建了一个与类属性同名的实例属性。因此修改类属性,应该使用类对象进行修改。再外界最好不要使用 实例对象.新属性 = xxx,动态创建实例属性。
到底是用类属性,还是实例属性?
如果每个实例对象需要具有相同值的属性,那么就使用类属性,用一份既可。
class Province(object):
# 类属性
country = '中国'
def __init__(self, name):
# 实例属性
self.name = name
p1 = Province('江西省')
p2 = Province('四川省')
类中方法包括:实例方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
self
参数;执行实例方法时,自动将调用该方法的对象赋值给 self
。cls
参数;执行类方法时,自动将调用该方法的类赋值给 cls
。class Foo(object): foo = 'Foo' def __init__(self, name): self.name = name def instance_func(self): print(self.name) print(self.foo) print('实例方法') @classmethod def class_func1(cls): print(cls.foo) print('类方法1') @classmethod def class_func2(cls): print(cls.name) print('类方法二') @staticmethod def static_func(): print('静态方法')
其中 @classmethod
是装饰器,说明这是类方法,@staticmethod
则说明是静态方法。关于装饰器的内容这里就不在赘述了。
在 ipython
中测验一下各方法
# 实例对象调用 In [71]: f = Foo('hui') In [72]: f.instance_func() hui Foo 实例方法 In [73]: f.class_func1() Foo 类方法1 In [74]: f.class_func2() --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-74-7d161e9e60ec> in <module> ----> 1 f.class_func2() <ipython-input-60-7fc48649a96a> in class_func2(cls) 18 @classmethod 19 def class_func2(cls): ---> 20 print(cls.name) 21 print('类方法二') 22 AttributeError: type object 'Foo' has no attribute 'name' In [75]: f.static_func() 静态方法 # 类对象自身调用 In [76]: Foo.instance_func() --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-76-883efcb56130> in <module> ----> 1 Foo.instance_func() TypeError: instance_func() missing 1 required positional argument: 'self' In [77]: Foo.class_func1() Foo 类方法1 In [78]: Foo.static_func() 静态方法
可以发现实例对象三种方法都可以调用,但 cls
类对象不能访问实例属性。类对象不能直接调用实例方法,类、静态方法可以。
self
指的是类实例对象本身(注意:不是类本身)。cls
指的是类对象本身self
可以访问到类属性、实例属性,cls
只能访问类属性。其中 self, cls
只是代指实例对象和类对象,因此换成其他变量也可以,但是约定成俗(为了和其他编程语言统一,减少理解难度),不要搞另类,大家会不明白的。
需要操作类属性的定义成类方法。
需要操作实例属性的定义成实例方法。
既不需要操作类属性,也不需要操作实例属性就定义成静态方法。
新建文件夹X
大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。