介绍关于类的一些高级主题,这些是可选的,在Python应用程序中,不会常常遇到。

==========================================================================

slots实例

将字符串属性名称顺序赋值给特殊的__slots__类属性。就能够限制类的实例将有的合法属性集。

这个特殊属性通常是在class语句顶层内将字符串名称顺序赋值给变量__slots__而设置:仅仅有__slots__列表内的这些变量名可赋值为实例属性。而实例属性名必须在引用前赋值,即使是列在__slots__中也是这样。看下述样例:

>>> class limiter(object):
__slots__ = ['age','name','job'] >>> x = limiter()
>>> x.age
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
x.age
AttributeError: age
>>> x.age = 40
>>> x.age
40
>>> x.ape = 1000
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
x.ape = 1000
AttributeError: 'limiter' object has no attribute 'ape'

假设创建了非常多实例而且仅仅有几个属性是必需的话。那么为每一个实例对象分配一个命名空间字典可能在内存方面的代价过于昂贵。要节省空间和运行速度,slot属性能够顺序存储以供高速查找,而不是为每一个实例分配一个字典。

-------------------------------------------------------------------------------------------------------------------------------------

Slot和通用代码

实际上。有些带有slots的实例或许根本就没有__dict__属性字典。所以在有些程序中要使用比__dict__更为存储中立的工具,比如getattr、setattr和dir内置函数。

>>> class C:
__slots__ = ['a','b'] >>> X = C()
>>> X.a = 1
>>> X.a
1
>>> X.__dict__
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
X.__dict__
AttributeError: 'C' object has no attribute '__dict__'
>>> getattr(X,'a')
1
>>> setattr(X,'b',2)
>>> X.b
2
>>> 'a' in dir(X)
True
>>> 'b' in dir(X)
True

没有属性命名空间字典,不可能给不是slots列表中名称的实例来分配新的名称,然而,通过在__slots__中包括__dict__仍然能够容纳额外的属性,从而考虑到一个属性空间字典的须要。在这个样例中。两种机制都用到了,可是,getattr这种通用工具同意我们将它们当做单独一组属性对待:

>>> class D:
__slots__ = ['a','b','__dict__']
c = 3
def __init__(self):
self.d = 4 >>> X = D()
>>> X.d
4
>>> X.__dict__
{'d': 4}
>>> X.__slots__
['a', 'b', '__dict__']
>>> X.c
3
>>> X.a
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
X.a
AttributeError: a
>>> X.a = 1
>>> getattr(X,'a'),getattr(X,'c'),getattr(X,'d')
(1, 3, 4)

==========================================================================

类特性

有一种称为特性(property)的机制,提供还有一种方式让类定义自己主动调用的方法,来读取或赋值实例属性。

【特性和slots都是基于属性描写叙述器的新概念】



简而言之,特性是一种对象,赋值给类属性名称。特性的产生是以三种方法(获得、设置以及删除运算的处理器)以及通过文档字符串调用内置函数property。假设不论什么參数以None传递或者省略。该运算就不能支持。

特性一般都是在class语句顶层赋值【比如,name = property(...)】。这样赋值时。对类属性本身的读取(比如。obj.name),就会自己主动传给property的一个读取方法。例如以下例:

>>> class new():
def getage(self):
return 40
age = property(getage,None,None,None) # get,set,del,docs >>> x = new()
>>> x.age
40
>>> x.name
Traceback (most recent call last):
File "<pyshell#34>", line 1, in <module>
x.name
AttributeError: 'new' object has no attribute 'name'

特性比传统技术执行起来更快。

比如,当我们新增属性赋值运算支持时,特性就变得更有吸引力:输入的代码更少,对我们不希望动态计算的属性进行赋值运算时,不会发生额外的方法调用。

>>> class new():
def getage(self):
return 40
def setage(self,value):
print('set age:',value)
self._age = value
age = property(getage,setage,None,None) >>> x = new()
>>> x.age
40
>>> x.age = 42
set age: 42
>>> x.age
40
>>> x._age
42
>>> x.job = 'trainer'
>>> x.job
'trainer'

==========================================================================

__getattribute__和描写叙述符



__getattribute__能够让类拦截全部属性的引用。而不局限于没有定义的引用(假设__getattr__)。

除了特性和运算符重载方法,Python支持属性描写叙述符的概念——带有__get__和__set__方法的类,分配给类属性而且由实例继承,这拦截了对特定属性的读取和写入訪问。描写叙述符在某种意义上是特性的一种更加通用的形式。



关于特性、__getattribute__和描写叙述符这些高级话题将在兴许逐步介绍。

==========================================================================

静态方法

类方法通常在其第一个參数中传递一个实例对象。以充当方法调用的一个隐式主体。有时候。程序须要处理与类而不是与实例相关的数据,也就是我们须要一个类中的方法不仅不传递并且也不期待一个self实例參数。

Python通过【静态方法】的概念来支持这种目标——嵌套在一个类中的没有self參数的简单函数。



比如。如果我们想使用类属性去计算从一个类产生了多少实例。我们能够把一个计数器存储为类属性。每次创建一个新的实例的时候。构造函数都会对计数器加1。而且,有一个显示计数器值的方法。【记住,类属性是由全部实例共享的】:

>>> class Spam:
numInstances = 0
def __init__(self):
Spam.numInstances += 1
def printNumInstances():
print('Number of instances created:',Spam.numInstances)

printNumInstances方法旨在处理类数据而不是实例数据——它是关于全部实例的,而不是某个特定的实例。因此,我们想要不必传递一个实例就能够调用它。

实际上,我们不想生成一个实例来获取实例的数目。由于这本身就会改变我们想要获取的实例的数目。

换句话说:我们想要一个无self的静态方法。

我们能够看一下測试结果:

>>> a = Spam()
>>> b = Spam()
>>> c = Spam()
>>> Spam.printNumInstances()
Number of instances created: 3
>>> a.printNumInstances()
Traceback (most recent call last):
File "<pyshell#66>", line 1, in <module>
a.printNumInstances()
TypeError: printNumInstances() takes 0 positional arguments but 1 was given

能够看到,我们通过类调用无self方法执行成功。而通过实例调用无self方法出错了,由于參数不正确。通过一个实例调用方法。这个实例会自己主动传递给方法的第一个參数中,可是这个无self方法并不存在參数来接收它。

假设你可以坚持仅仅通过类调用无self方法。那么事实上你已经有了一个静态方法了。然而假设你还想通过实例调用,那么就须要採取其它设计,或者把这个方案标记为特殊的。

-------------------------------------------------------------------------------------------------------------------------------------

使用静态方法

要将这个无self方法标记为静态方法。须要调用内置函数staticmethod。例如以下:

>>> class Spam:
numInstances = 0
def __init__(self):
Spam.numInstances += 1
def printNumInstances():
print('Number of instances created:',Spam.numInstances)
printNumInstances = staticmethod(printNumInstances) # staticmethod >>> a = Spam()
>>> b = Spam()
>>> c = Spam()
>>> a.printNumInstances()
Number of instances created: 3

静态方法对于处理一个类本地的数据来说是更好的解决方式。

==========================================================================

装饰器和元类:初识



上边提到的staticmethod可能比較奇怪。所以新增了一个功能,要让这个运算变得简单。【函数装饰器】提供了一种方式,替函数明白了特定的运算模式。也就是将函数包裹了还有一层,在还有一函数的逻辑内实现。

函数装饰器变成了通用的工具:除了静态方法使用方法外。也可用于新增多种逻辑的函数。比如,能够用来记录函数调用的信息和在出错时检查传入的參数类型等



Python提供了一下内置的函数装饰器,来做一些运算,比如。标识静态方法,可是我们也能够编写自己的随意装饰器。尽管不限于使用类,但用户定义的函数装饰器通常也写成类,把原始函数和其它数据当成状态信息。

-------------------------------------------------------------------------------------------------------------------------------------

函数装饰器基础

从语法上讲,函数装饰器是它后边的函数的执行时的声明。

函数装饰器是写成一行,就在定义函数或方法的def语句之前,并且由@符号、后面跟着所谓的元函数组成:也就是管理还有一函数的函数。

比如,如今的静态方法我们能够用下述的装饰器语法编写:

class C:
@staticmethod
def printNumInstances():
...

这个语法和以下的写法有同样的效果:

class C:
def meth():
...
meth = staticmethod(meth)

结果就是,调用方法函数的名称。实际上是触发了它staticmethod装饰器的结果。

-------------------------------------------------------------------------------------------------------------------------------------

装饰器样例

之前介绍过,__call__运算符重载方法为类实例实现函数调用接口。

以下的程序通过这样的方法定义类。在实例中存储装饰的函数,并捕捉对最初变量名的调用。

class tracer:
def __init__(self,func):
self.calls = 0
self.func = func
def __call__(self,*args):
self.calls += 1
print('call %s to %s'%(self.calls,self.func.__name__))
self.func(*args) @tracer
def spam(a,b,c):
print(a,b,c) spam(1,2,3)
spam('a','b','c')
spam(4,5,6)

由于spam函数时通过tracer装饰器运行的,所以当最初的变量名spam调用时。实际上触发的是类中的__call__方法,这种方法会计算和记录该次调用,然后托付给原始的包裹的函数。

因此,此装饰器可用于包裹携带随意数目參数的不论什么函数。

结果就是新增一层逻辑至原始的spam函数。执行结果例如以下:第一行来自tracer类,第二行来自spam函数。

call 1 to spam
1 2 3
call 2 to spam
a b c
call 3 to spam
4 5 6

这里仅仅是初步了解。兴许我们将会介绍各种各种的方法来编写函数装饰器。

-------------------------------------------------------------------------------------------------------------------------------------

类装饰器和元类



类装饰器类似于函数装饰器,可是。它们在一条class语句的末尾执行,而且把一个类名又一次绑定到一个可调用对象,相同的,它们能够用来管理类,或者当随后创建实例的时候插入一个包装逻辑层来管理实例。代码结构例如以下:

def decorator(aClass):...

@decorator
class C:...

被映射为下列相当代码:

def decorator(aClass):...

class C:...
C = decorator(C)

元类是一种类似的基于类的高级工具。其用途往往与类装饰器有所重合。

它们提供了一种可选的模式。会把一个类对象的创建导向到顶级type类的一个子类。

关于装饰器和元类的内容,将在之后更加具体地介绍。

Python——类的高级主题的更多相关文章

  1. python类的高级属性

    ---恢复内容开始--- 类方法:通过@classmethod装饰器实现,类方法和普通方法的区别是,类方法只能访问类变量,不能访问实例变量,代码如下: class Person(object): de ...

  2. Python 类的高级属性(可选)

    1.slots实例:限制类的实例有合法的属性集,只有__slots__属性列表中的属性才可能成为实例属性. 对象的实例通常没有一个属性字典,可以在__slots__列表中包含一个属性字典__dict_ ...

  3. Python高级主题:Python ABC(抽象基类)

    #抽象类实例 作用统一规范接口,降低使用复杂度.import abcclass Animal(metaclass = abc.ABCMeta): ##只能被继承,不能实例化,实例化会报错 @abc.a ...

  4. Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)

    Python:高级主题之(属性取值和赋值过程.属性描述符.装饰器) 背景 学习了Javascript才知道原来属性的取值和赋值操作访问的“位置”可能不同.还有词法作用域这个东西,这也是我学习任何一门语 ...

  5. Python之路,Day8 - Python基础 面向对象高级进阶与socket基础

    类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的 ...

  6. python类及其方法

    python类及其方法 一.介绍 在 Python 中,面向对象编程主要有两个主题,就是类和类实例类与实例:类与实例相互关联着:类是对象的定义,而实例是"真正的实物",它存放了类中 ...

  7. python 的一些高级编程技巧

    正文: 本文展示一些高级的Python设计结构和它们的使用方法.在日常工作中,你可以根据需要选择合适的数据结构,例如对快速查找性的要求.对数据一致性的要求或是对索引的要求等,同时也可以将各种数据结构合 ...

  8. 再学python类(终结篇)

    续写 初学python类,这几天吃坏东西了,拖着虚弱的身躯写的.有些乱请各位看官海涵. 声明:本人编程新手,还在学习中.所表述的东西都是基础语法之类的,分享我的学习笔记.还望多多指点,我一定虚心接受. ...

  9. 【Python&数据结构】 抽象数据类型 Python类机制和异常

    这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...

随机推荐

  1. arrive 和reach 的区别

    例如:He arrived yesterday. 没宾语的话就用arrive了reach作抵达讲时是及物动词,后面要宾语的 分清arrive和reach的区别arrive是不及物动词,后面不能直接加地 ...

  2. 【SaltStack】一些常用模块举例

    一.用户和用户组模块 说明:该sls文件用来在Minion端创建nginx用户和nginx用户组,当创建nginx用户时,对nginx用户组是否已存在做判断! (1)  /srv/salt/creat ...

  3. Linux下安装MySQLdb模块(Python)

    一.MySQLdb-python模块 https://pypi.python.org/pypi/MySQL-python ` 二.安装依赖包 yum -y install python-devel m ...

  4. luogu3755 [CQOI2017]老C的任务

    扫描线水题. #include <algorithm> #include <iostream> #include <cstdio> using namespace ...

  5. python ConfigParser 学习

    [安装] ConfigParser 是解析配置文件的第三方库,需要安装 pip install ConfigParser   [介绍] ConfigParser 是用来读取配置文件(可以是.conf, ...

  6. Opencv学习笔记——视频高斯模糊并分别输出

    用两个窗口进行对比 #include "stdafx.h" #include <iostream> #include <opencv2/core/core.hpp ...

  7. SPOJ QTREE Query on a tree V ——动态点分治

    [题目分析] QTREE4的弱化版本 建立出分治树,每个节点的堆表示到改点的最近白点距离. 然后分治树上一直向上,取min即可. 正确性显然,不用担心出现在同一子树的情况(不会是最优解),请自行脑补. ...

  8. [BZOJ1575] [Usaco2009 Jan]气象牛Baric(DP)

    传送门 DP f[i][j]表示前i个中选j个的最优解 预处理g[i][j]表示选i~j对答案的贡献 那么就可以n^3乱搞了! 注意边界 #include <cstdio> #includ ...

  9. [暑假集训--数位dp]hdu2089 不要62

    杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍, ...

  10. 仓库建设(bzoj 1096)

    Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天, ...