文档章节

Python 定制类的特殊方法与授权

lionets
 lionets
发布于 2013/12/31 21:38
字数 1643
阅读 713
收藏 15

在定制类的过程中,添加的方法和属性能完成大部分工作。但若想要类表现出一些特殊行为或者能够响应某些内建函数或操作符,那么就需要构建一些特殊方法。这些特殊方法的标识是方法名以双下划线(__)开头与结尾,除了常用的构造器 __init__() 外,还有一些常用的特殊方法。

基础方法:

  • C.__new__(self[,arg1,…])        构造器(带一些可选的参数);通常用在设置不可变数据类型的子类
  • C.__del__(self)        解构器
  • C.__str__(self)        可打印的字符串输出;内建 str() 及 print() 函数
  • C.__repr__(self)        运行时的字符串输出;内建 repr() 函数及 ' ' 操作符
  • C.__call__(self,*args)        用于可调用的实例;可以用来替代闭包的实现
  • C.__nonezero__(self)        为实例定义 False 值;内建 bool() 函数
  • C.__len__(self)        长度;内建 len()

类的值比较:

  • C.__cmp__(self,obj)        对象比较;内建 cmp()
  • C.__lt__(self,obj) & C.__le__(self,obj)        小于或小于等于;内建< & <=
  • C.__gt__(self,obj) & C.__ge__(self,obj)        大于或大于等于;内建 > & >=
  • C.__eq__(self,obj) & C.__ne__(self,obj)        等于或不等于;内建 = & !=

类的属性:

  • C.__getattr__(self,attr)        获取属性;内建 getattr();仅在属性没有找到时调用
  • C.__setattr__(self,attr)        设置属性
  • C.__delattr__(self,attr)        删除属性
  • C.__getattribute__(self,attr)        获取属性;内建 getattr();总是被调用
  • C.__get__(self,attr)        (描述符)获取属性
  • C.__set__(self,attr)        (描述符)设置属性
  • C.__delete__(self,attr)        (描述符)删除属性

数值类型,二进制操作符:

  • C.__*add__(self,obj)        加;+ 操作符
  • C.__*sub__(self,obj)        减;+ 操作符
  • C.__*mul__(self,obj)        乘;* 操作符
  • C.__*dev__(self,obj)        除;/ 操作符
  • C.__*truediv__(self,obj)        真正的除法;/ 操作符
  • C.__*floordiv__(self,obj)        地板除;// 操作符
  • C.__*mod__(self,obj)        取模;% 操作符
  • C.__*divmod__(self,obj)        除和取模;内建 divmod()
  • C.__*pow__(self,obj[,mod])        乘幂;内建 pow() ; ** 操作符
  • C.__*lshift__(self,obj)        左移位;<< 操作符
  • C.__*rshift__(self,obj)        右移位;>> 操作符
  • C.__*and__(self,obj)        按位与;& 操作符
  • C.__*or__(self,obj)        按位或;| 操作符
  • C.__*xor__(self,obj)        按位异或;^ 操作符

数值类型,一元操作符:

  • C.__neg__(self)        一元负
  • C.__pos__(self)        一元正
  • C.__abs__(self)        绝对值;内建 abs()
  • C.__invert__(self)        按位求反;内建 ~ 操作符

数值类型,数值转换:

  • C.__complex__(self, com)        内建 complex()
  • C.__int__(self)        内建 int()
  • C.__float__(self)        内建 float()

数值类型,数值压缩:

  • C.__index__(self)        在有必要时,压缩可选的数值类型为整型(比如用于切片索引时等)

序列类型:

  • C.__len__(self)        序列中的项目数
  • C.__getitem__(self, ind)        获取一个元素
  • C.__setitem__(self, ind,val)        设置一个元素
  • C.__delitem__(self, ind)        删除一个元素
  • C.__getslice__(self, ind1,ind2)        获取切片元素
  • C.__setslice__(self, i1, i2,val)        设置切片元素
  • C.__delslice__(self, ind1,ind2)        删除切片元素
  • C.__contains__(self, val)        含有成员;内建 in 关键字
  • C.__*add__(self,obj)        串联;+ 操作符
  • C.__*mul__(self,obj)        重复;* 操作符
  • C.__iter__(self)        生成迭代器;内建 iter() 函数

映射类型:

  • C.__len__(self)        类中的项目数
  • C.__hash__(self)        散列(hash)函数值
  • C.__getitem__(self,key)        获取某个值
  • C.__setitem__(self,key,val)        设置某个值
  • C.__delitem__(self,key)        删除某个值
  • C.__missing__(self,key)        给定键若不存在,则返回一个默认值

一般常用的特殊方法就是上面这些,某些如 coerce() 这样在 Python3 中被删除或失效的内建函数就没有再列出来。因为 Python 的内建类型已经能够满足日常需求,所以下面的例子就只来实现一个功能吧:虽然 float 类型有 .hex() 方法,但内建的 hex() 函数却不支持 float 类型。所以我们来自定义一个可以被内建的 hex() 调用的浮点类型。为了省事,我们就直接从 float 派生了~

class iFloat(float):
    def __index__(self):
        return int(self)

运行结果如下:

>>> a = iFloat(1.1)
>>> hex(a)
'0x1'

P.S. 上面这个例子是个伪栗子。因为他实际是通过将浮点数强制转换为整数来满足调用 hex() 函数的条件的。按照官方文档的说法,hex() 函数只接受 int 类型做参数,你在 iFloat 里实现 __hex__() 也没用,这也是我把 __oct__() 和 __hex__() 从上面删除的原因。同时按照官方文档的说法,如果你硬要调用内建 hex() 函数,则必须实现 __index__() 方法来返回一个整数(是的,还是得要整数…)

即,下面这种方法是木有用的:

class iFloat(float):
    def __hex__(self):
        return self.hex()

仍然会报错,尽管 __hex__(self) 可以返回正常值:

>>> a = iFloat(1.1)
>>> hex(a)
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    hex(a)
TypeError: 'iFloat' object cannot be interpreted as an integer
>>> a.__hex__()
'0x1.199999999999ap+0'

我觉得这可能是因为内建 hex() 函数已经不只是调用 __hex__() 这么简单了。

__getattr__()与授权:

在Python 2.2 以前,标准类型还不可以派生。为解决此问题而常被使用的手段是“包装”,这种方式的行为就和他的名字一样:

class WrappedList():
    def __init__(self,obj):
        self.__data = obj

但这还不够,我们要实现的主要目标是在需要的时候可以像子类一样自动访问被包装对象的属性或方法。而实现这一功能的关键便是 __getattr__() 特殊方法。这个方法的作用是:当试图访问一个实例的属性时,本地属性会首先被找到,如果本地没有就会去类属性和祖先类属性里找,如果那里也没有的话,就会调用实例的 __getattr__() 方法。因此这里就给我们提供了一个将属性访问重定向到被包装的类型(伪父类)的机会。其具体的实现方法便是,在 __getattr__() 中调用内建的 getattr() 函数:

class WrappedList():
    def __init__(self,obj):
        self.__data = obj
    def __getattr__(self,attr):
        return getattr(self.__data,attr)
    def __str__(self): 
        self.__atime = time()
        return str(self.__data)
    __repr__ = __str__

运行结果:

>>> a = WrappedList([1,2,3])
>>> a
[1, 2, 3]
>>> a.append(4)
>>> a
[1, 2, 3, 4]

不过这里仍有一个缺陷便是,当你对包装对象进行特殊行为时,例如上面 WrappedList 的切片操作,就会遇到问题。因为这已经超出了访问属性的范畴。因此在标准类型已经可以派生的现在,就没必要再去包装他们了,至于其他用途么,也可以先尝试用装饰器去实现。

© 著作权归作者所有

共有 人打赏支持
lionets
粉丝 91
博文 98
码字总数 132850
作品 0
朝阳
程序员
Python基础总结成千行代码,让Python入门更简单!

只要学会这千行代码,不管你是零基础还是弱基础或是没有接触过编程,都可以快速入门Python!当时我就不信邪啊,等我看完之后,即使作为一个Python老鸟了,还是领会到了很多教授他的独特见解!...

糖宝lsh
09/10
0
0
转-深入探讨Ruby与Python语法比较

自:http://developer.51cto.com/art/200912/169306.htm 1. Ruby的case可以匹配很多东西:范围/数组,对象,正则表达,python没有case/switch而使用if/else比较死板点 2. python的缩进很漂亮...

玉龙
2011/10/12
0
0
Python学习之面向对象高级编程

数据封装、继承和多态只是面向对象程序设计中最基础的3个概念。在Python中,面向对象还有很多高级特性,如:多重继承、定制类、元类等概念。 slots 作用:限制实例的属性。 Python允许在定义...

stone_zhu
06/19
0
0
Python动态特性应对动态情况

Python有一些定制类的特殊方法,如、、,其中一些具有动态特性的方法可以用来很方便地处理某些动态状况。 Duck-typing When I see a bird that walks like a duck and swims like a duck and...

HeHa
2015/09/21
0
0
Python学习笔记-面向对象篇

定义 实例化和调用 访问限制 双下划线: 私有变量(解释器把双下划线改成了单下划线,依旧可以通过单下划线访问) 单下划线: 可以被外部访问,但约定俗称不要访问 双下划线包围: 特殊变量,...

路小磊
2015/07/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

20181018 上课截图

![](https://oscimg.oschina.net/oscnet/49f66c08ab8c59a21a3b98889d961672f30.jpg) ![](https://oscimg.oschina.net/oscnet/a61bc2d618b403650dbd4bf68a671fabecb.jpg)......

小丑鱼00
27分钟前
0
0
WinDbg

参考来自:http://www.cnit.net.cn/?id=225 SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols ctrl + d to open dump_file Microsoft (R) Windows Debugger Version 6.12.0002.633......

xueyuse0012
今天
2
0
OSChina 周五乱弹 —— 想不想把92年的萝莉退货

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @罗马的王:分享松澤由美的单曲《地球ぎ》 很久没看圣斗士星矢了 《地球ぎ》- 松澤由美 手机党少年们想听歌,请使劲儿戳(这里) @开源中国首...

小小编辑
今天
14
2
springBoot条件配置

本篇介绍下,如何通过springboot的条件配置,控制Bean的创建 介绍下开发环境 JDK版本1.8 springboot版本是1.5.2 开发工具为 intellij idea(2018.2) 开发环境为 15款MacBook Pro 前言 很多时候,...

贺小五
今天
1
0
javascript source map 的使用

之前发现VS.NET会为压缩的js文添加一个与文件名同名的.map文件,一直没有搞懂他是用来做什么的,直接删除掉运行时浏览器又会报错,后来google了一直才真正搞懂了这个小小的map文件背后的巨大...

粒子数反转
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部