【Python学习】python学习手册--第三十一章 类的高级主题

新式类

  • 在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 "<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的高级应用,对工具编写者有意义,但对于应用程序员就没那么重要。
适当的使用类,可以提高代码的复用性,但是过多的包装和继承绝对不是好事,这让代码的逻辑太深,维护性和可读性太差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值