文档章节

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

lionets
 lionets
发布于 2013/12/31 21:38
字数 1643
阅读 664
收藏 15
点赞 0
评论 0

在定制类的过程中,添加的方法和属性能完成大部分工作。但若想要类表现出一些特殊行为或者能够响应某些内建函数或操作符,那么就需要构建一些特殊方法。这些特殊方法的标识是方法名以双下划线(__)开头与结尾,除了常用的构造器 __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
粉丝 90
博文 96
码字总数 131014
作品 0
朝阳
程序员
Python学习之面向对象高级编程

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

stone_zhu ⋅ 06/19 ⋅ 0

Python面向对象之运算符重载

运算符重载只是意味着在类方法中拦截内置的操作,也就是说当类的实例出现在内置操作中,Python自动调用我们的方法,并且我们的方法的返回值变成了相应操作的结果。 关于重载的关键知识点: ...

bigstone2012 ⋅ 06/08 ⋅ 0

你想要的Python面试都在这里了【315+道题】

写在前面 近日恰逢学生临近毕业,课程后期大家“期待+苦逼”的时刻莫过于每天早上内容回顾和面试题问答部分【临近毕业每天课前用40-60分钟对之前内容回顾、提问和补充,专挑班里不爱说话就的...

p柯西 ⋅ 06/12 ⋅ 0

Python基础面试题80问 Python自动化开发

为什么学习Python? 2. 通过什么途径学习的Python? 3. Python和Java、PHP、C、C#、C++等其他语言的对比? 4. 简述解释型和编译型编程语言? 5. Python解释器种类以及特点? 6. 位和字节的关...

zhouzhou2018 ⋅ 05/24 ⋅ 0

王老板Python面试(10):17道python笔试面试真题

1、一行代码实现1--100之和 利用sum()函数求和 2、如何在一个函数内部修改全局变量 利用global 修改全局变量 3、列出5个python标准库 os:提供了不少与操作系统相关联的函数 sys: 通常用于命...

程序员八阿哥 ⋅ 05/22 ⋅ 0

学习了Python那么长的世界,有没有玩转过hello word?

很多人学习Python很长时间,对于'hello word' 的认知,就只有: 但是有没有让hello word 变得不一样?(想要源码可以加群:725479218,群文件里面可以找到) 开始 (先决条件) 首先在你的操作系...

柯西带你学编程 ⋅ 06/03 ⋅ 0

超详细Python正则表达式操作指南(re使用),一

Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。Python 1.5之前版本则是通过 regex 模块提供 Emecs 风格的模式。Emacs 风格模式可读性稍差些,而且功能也不强,因此编...

Python雁横 ⋅ 05/26 ⋅ 0

Python写代码的时候为什么要注释?Sun因此被Oracle收购

导读: 此块分为:1.注释的重要性 2.如何正确注释 注释的重要性 在我们看代码的时候,会遇到很多看不懂得代码,特别是在做项目的时候,代码的注释以及命名习惯的重要性就有了为什么这么说呢?...

柯西带你学编程 ⋅ 05/27 ⋅ 0

云计算Python自动化:Python标识符讲解

开发人员在程序中自定义的一些符号和名称。标示符是自己定义的,如变量名,函数名等。在日常生活中,标示符是用来指定某个东西、人,要用到它,他或她的名字;在数学中解方程时,我们也常常用到...

长沙千锋 ⋅ 05/15 ⋅ 0

Python面向对象编程之我见

面向对象基本概念 面向对象是一种编程范式。范式是指一组方法论。编程范式是一组如何组织代码的方法论。编程范式指的是软件工程中的一种方法学。 一些主流的编程范式: OOP - 面向对象编程 ...

bigstone2012 ⋅ 05/31 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Cloud构建微服务架构—创建“服务注册中心”

创建一个基础的Spring Boot工程,命名为eureka-server,并在pom.xml中引入需要的依赖内容: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par......

itcloud ⋅ 20分钟前 ⋅ 0

拖动

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>event</title> <style> #box { width: 100px; height: 100px; background-color: aquamarine; position: absolute; } </style......

fyliujj ⋅ 23分钟前 ⋅ 0

es6 polyfill array

polyfill之javascript函数的兼容写法——Array篇 1. Array.isArray(obj) if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[objec......

球球 ⋅ 25分钟前 ⋅ 0

kibana启动异常

检查一下:kibana.yml 每一对key:value中,冒号之后应有空格。

增删改查1 ⋅ 27分钟前 ⋅ 0

js修改img的src属性刷新图片时的图片缓存问题

问题:上传一张图片,通过js更新src属性刷新图片使其即时显示时, 当img的src当前的url与上次地址无变化时(只更改图片,名称不变,不同图片名称相同)图片不变化(仍显示原来的图片) 但通过...

HaierBrother ⋅ 27分钟前 ⋅ 0

Mysql

1.Jdbc Url 设置allowMultiQueries为true和false mysql的批量更新是要我们主动去设置的, 就是在数据库的连接url上设置一下,加上* &allowMultiQueries=true *即可。 参数名称 参数说明 缺省...

瑟青豆 ⋅ 30分钟前 ⋅ 0

mysql导出导入表结构与数据

当我们需要进行数据迁移时,mysql自带的mysqldump会是最好的方式。 1.导出某张表的结构和数据 首先,我们应当使用服务器,打开终端,连接到所需要导出的表所在的服务器上。执行命令: mysqld...

hengbao5 ⋅ 31分钟前 ⋅ 0

世界杯也走向“比拼”大数据的时代

《日本经济新闻》6月19日报道称,俄罗斯足球世界杯已于6月14日揭开战幕。作为第21次举办的足球世界杯,如何活用大数据有可能成为决定各支球队胜负的重要因素。从对阵球队的分析到战术建议,还...

加米谷大数据 ⋅ 31分钟前 ⋅ 0

金额转为千分制,金额转中文大写

金额转关为大写 /** 数字金额大写转换(可以处理整数,小数,负数) */ function digitUppercase(n){ if(!n) reutrn "" let fraction = ['角', '分']; let digit = [...

YXMBetter ⋅ 34分钟前 ⋅ 0

开发利器JRebel部署SpringBoot项目

不要以为年纪轻轻就跌倒了人生谷底,未来还有更大的下降空间等着你。 idea下载和安装JRebel 激活JRebel 访问https://my.jrebel.com/ 使用facebook或twitter登录 勾选 Build project automati...

郑龙飞 ⋅ 39分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部