【Python学习】python学习手册--第三十一章 类的高级主题
2018-03-30 17:45
405 查看
新式类
在Python3.0中,所有类都是新式类(new-style),所有的类都继承自object对象,不管是显式的还是隐式的,并且所有对象都是object的实例。在Python2.6和以前的版本,类必须显式继承object才会是新式类,并且获得所有新式类的特性
在Python3.0中,所有的类都自动继承自新式类,所以新式类的特征只是常规的特性。而在Python2.6版本及以前的都必须继承自object类或者继承自Python内置类才会成为新式类。
实际上,新式类在语法和行为上几乎与经典类完全向后兼容;它们主要只是添加了一些高级的新特性。
新式类的变化有以下几点:
类就是类型,类型也是类,同时一个实例的类型也是该实例的类,它们之间的区别已经完全消失,
>>> type([1,2,3]) #类型就是类 <class 'list'> >>> type(list) #类也是类型 <class 'type'> >>> list.__class__ <class 'type'> >>>
所有的类都是派生自object类
新式类在多重继承的类树中搜索是先从同一个深度中的类开始搜索,所有同深度的类都搜索完成之后,然后再开始搜索更深类(而2.6是优先将一个树枝搜索完后,再开始搜索下一个树枝,新式类是广度优先而不是深度优先)。如果要避免这种搜索顺序的混淆,最好将变量命名得更加有特效,类的设计更加合理。
新式类还有一些更高级的扩展:
slots属性
在新式类中,__slots__是比较特殊的类属性,可以将字符串列表赋值给该属性,这样就可以限制类实例的合法属性集,那些不合法的属性将无法赋值,这又能优化内存和速度性能。>>> class c: ... __slots__=['a','b','c'] ... >>> lxm=c() >>> lxm.d=1 #赋值不会成功 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'c' object has no attribute 'd' >>> lxm.a=1 >>> lxm.b=2 >>> lxm.c=3 >>> lxm.z=2222 Traceback (most recent call last): File "& c0fa lt;stdin>", line 1, in <module> AttributeError: 'c' object has no attribute 'z' >>>
如果类的属性只有确定的几个时,创建实例并分配命名空间时很费内存的办法,__slots__属性可以顺序存储,而不是用传统的字典形式来存储属性,这样提高了执行速度,也节省空间。
当有多个超类的时候,__slots__属性可以看做是所有超类该属性的集合。与超裂相关slots属性有以下几点需要注意:
如果一个子类继承自一个没有__slots__的超类,那么超类的dict属性总是可以访问,这让子类中的slots属性失去意义。
如果一个子类和超类相同的slots名称,超类的slots属性只有通过超类标识符获取其属性
由于一个slots声明的含义受到类的限制,所以子类将有一个__dict__,除非它们也定义了一个slots
property机制
这个property是一个对象,赋值给类属性名称。它会产生三种方法(get,set,del)如果任何参数是None,那么该运算就不能支持。特性赋值一般都是在类的顶层处使用。>>> class c(): ... def Cget(self): ... print("Cget called,value:") ... return 999 ... def Cset(self,value): ... print("Cset called,value:",value) ... return 888 ... def Cdel(self): ... print("Cdel called") ... del self ... test=property(Cget,Cset,Cdel,None) ... >>> lxm=c() >>> lxm.test Cget called,value: 999 >>> lxm.test=123 Cset called,value: 123
这种效果就很像重载运算符中的__getattr__和__setattr__方法。
静态方法
有些时候我们需要对类的属性进行操作,而不是类的实例。我们就需要定义一个不需要传入实例(self)的“静态”方法。在Python2.6中,无论是否在定义方法是写没写self参数,在调用方法是都会需要一个实例。而在Python3.0中就不一样,如果不需要实例,是完全可以不传入实例对象,调用时需要通过类名调用,如果使用实例调用,会默认传入实例对象,导致接受参数出错。使用静态方法最好的方法是将静态方法写入到类方法中,使得每一个实例都可以调用,调用的结果就是可以改变类属性。
内置函数staticmethod和classmethod可以把类中的方法标记成为特殊的方法(标记成为静态方法和类方法。)标记之后,就会将Python默认传递第一个参数的机制给屏蔽掉
>>> class c(): ... def func(): ... print("func called") ... func2=staticmethod(func) ... >>> lxm=c() >>> lxm.func() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: func() takes 0 positional arguments but 1 was given #默认情况下还是传入了实例 >>> lxm.func2() #通过内置staticmethod就不会传入实例对象了 func called >>>
类似的,用classmethod函数时,就将方法标记为类方法,默认情况下,就将该实例的类传入成为第一个参数。
从技术上讲,Python现在支持三种类相关方法:实例,静态和类。
实例方法就是必须用实例来调用的方法,Python会把实例对象当作方法的第一个参数传入方法内。
静态方法调用时不需要实例参数,其变量属于类,是在类的范围内,属于局部变量。
类方法与实例方法类似,但是第一个参数传入的应该是类,而不是实例。
装饰器和元类
staticmethod和classmethod这类函数属于Python中的函数装饰器,它们就像是在函数外包裹了一层,替函数明确了特定的运算模式,返回了一个新的函数对象。函数装饰器类似于委托设计模式,但是其设计是为了增强特定的函数或方法调用,而不是整个对象接口。staticmethod装饰器编写还可以使用以下语法:
这两种语法都是等价的:
class c: @staticmethod def meth(): <statements> class c: def meth(): <statements> meth=staticmethod(meth)
staticmethod仍然是一个内置函数,它可以用于装饰语法中,是因为它把一个函数当作参数并返回一个可调用的对象。
这些都是Python的高级应用,对工具编写者有意义,但对于应用程序员就没那么重要。
适当的使用类,可以提高代码的复用性,但是过多的包装和继承绝对不是好事,这让代码的逻辑太深,维护性和可读性太差。
相关文章推荐
- 《Python 学习手册4th》 第十九章 函数的高级话题
- Python学习笔记---高级主题
- 【Python学习】python学习手册--第十九章 函数的高级话题
- 【Python学习】python学习手册--第二十四章 高级模块话题
- Python菜鸟学习手册06----函数
- Python高级主题:MetaClass 元类
- Python 学习入门(24)—— 进程高级
- Python学习入门基础教程(learning Python)--5.6 Python读文件操作高级
- python核心高级学习总结4-------python实现进程通信
- 《Python 学习手册4th》 第十七章 作用域
- python第七天学习记录——面向对象高级以及socket编程
- (2011.10.02)《C++ Primer》第五部分学习笔记汇总——高级主题
- Python学习手册 - 09
- Python学习笔记3---PYTHON函数与高级特性
- python开发学习-day08(socket高级、socketserver、进程、线程)
- Spring4学习:Spring容器高级主题
- 《Python 学习手册4th》 第四章 介绍Python对象类型
- python学习手册4 知识记录。
- Python 3 初探,第 2 部分: 高级主题
- 31python类的高级主题