python的多种魔术方法
定制类和魔法方法
- new
- str , repr
- iter
- getitem , setitem , delitem
- getattr , setattr , delattr
- call
new
在 Python 中,当我们创建一个类的实例时,类会先调用 new(cls[, ...]) 来创建实例,然后 init 方法再对该实例(self)进行初始化。
关于 new 和 init 有几点需要注意:
new 是在 init 之前被调用的;
new 是类方法,init 是实例方法;
重载 new 方法,需要返回类的实例;
一般情况下,我们不需要重载 new 方法。但在某些情况下,我们想控制实例的创建过程,这时可以通过重载 _new 方法来实现。
class A(object):
_dict = dict()
def __new__(cls):
if 'key' in A._dict:
print "EXISTS"
return A._dict['key']
else:
print "NEW"
return object.__new__(cls)
def __init__(self):
print "INIT"
A._dict['key'] = self
str & repr
class Foo(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Foo object (name: %s)' % self.name
def __repr__(self):
return 'Foo object (name: %s)' % self.name
print Foo('ethan') # 使用 print
Foo object (name: ethan)str(Foo('ethan')) # 使用 str
'Foo object (name: ethan)'Foo('ethan') # 直接显示
<main.Foo at 0x10c37a490>Foo('ethan') # 使用repr(类中实现)
'Foo object (name: ethan)'
iter
在某些情况下,我们希望实例对象可被用于 for...in 循环,这时我们需要在类中定义 iter 和 next(在 Python3 中是 next)方法,其中,iter 返回一个迭代对象,next 返回容器的下一个元素,在没有后续元素时抛出 StopIteration 异常.
看一个斐波那契数列的例子:
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self): # 返回迭代器对象本身
return self
def next(self): # 返回容器下一个元素
self.a, self.b = self.b, self.a + self.b
return self.a
fib = Fib()
for i in fib:
... if i > 10:
... break
... print i
getitem、setitem、delitem
geitem 用于获取值,类似地,setitem 用于设置值,delitem 用于删除值,让我们看下面一个例子:
class Point(object):
def __init__(self):
self.coordinate = {}
def __str__(self):
return "point(%s)" % self.coordinate
def __getitem__(self, key):
return self.coordinate.get(key)
def __setitem__(self, key, value):
self.coordinate[key] = value
def __delitem__(self, key):
del self.coordinate[key]
print 'delete %s' % key
def __len__(self):
return len(self.coordinate)
__repr__ = __str__
在上面,我们定义了一个 Point 类,它有一个属性 coordinate(坐标),是一个字典,让我们看看使用:
>>> p = Point()
>>> p['x'] = 2 # 对应于 p.__setitem__('x', 2)
>>> p['y'] = 5 # 对应于 p.__setitem__('y', 5)
>>> p # 对应于 __repr__
point({'y': 5, 'x': 2})
>>> len(p) # 对应于 p.__len__
2
>>> p['x'] # 对应于 p.__getitem__('x')
2
>>> p['y'] # 对应于 p.__getitem__('y')
5
>>> del p['x'] # 对应于 p.__delitem__('x')
delete x
>>> p
point({'y': 5})
>>> len(p)
1
getattr、setattr、delattr
当我们获取对象的某个属性,如果该属性不存在,会抛出 AttributeError 异常,比如:
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
>>> p = Point(3, 4)
>>> p.x, p.y
(3, 4)
>>> p.z
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-547-6dce4e43e15c> in <module>()
----> 1 p.z
AttributeError: 'Point' object has no attribute 'z'
那有没有办法不让它抛出异常呢?当然有,只需在类的定义中加入 getattr 方法,比如:
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __getattr__(self, attr):
if attr == 'z':
return 0
>>> p = Point(3, 4)
>>> p.z
0
现在,当我们调用不存在的属性(比如 z)时,解释器就会试图调用 getattr(self, 'z') 来获取值,但是,上面的实现还有一个问题,当我们调用其他属性,比如 w ,会返回 None,因为 getattr 默认返回就是 None,只有当 attr 等于 'z' 时才返回 0,如果我们想让 getattr 只响应几个特定的属性,可以加入异常处理,修改 getattr 方法,如下:
def __getattr__(self, attr):
if attr == 'z':
return 0
raise AttributeError("Point object has no attribute %s" % attr)
setattr, delattr
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __getattr__(self, attr):
if attr == 'z':
return 0
raise AttributeError("Point object has no attribute %s" % attr)
def __setattr__(self, *args, **kwargs):
print 'call func set attr (%s, %s)' % (args, kwargs)
return object.__setattr__(self, *args, **kwargs)
def __delattr__(self, *args, **kwargs):
print 'call func del attr (%s, %s)' % (args, kwargs)
return object.__delattr__(self, *args, **kwargs)
>>> p = Point(3, 4)
call func set attr (('x', 3), {})
call func set attr (('y', 4), {})
>>> p.z
0
>>> p.z = 7
call func set attr (('z', 7), {})
>>> p.z
7
>>> p.w
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __getattr__
AttributeError: Point object has no attribute w
>>> p.w = 8
call func set attr (('w', 8), {})
>>> p.w
8
>>> del p.w
call func del attr (('w',), {})
>>> p.__dict__
{'y': 4, 'x': 3, 'z': 7}
call
我们一般使用 obj.method() 来调用对象的方法,那能不能直接在实例本身上调用呢?在 Python 中,只要我们在类中定义 call 方法,就可以对实例进行调用,比如下面的例子:
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def __call__(self, z):
return self.x + self.y + z
使用如下:
>>> p = Point(3, 4)
>>> callable(p) # 使用 callable 判断对象是否能被调用
True
>>> p(6) # 传入参数,对实例进行调用,对应 p.__call__(6)
13 # 3+4+6
slots
在 Python 中,我们在定义类的时候可以定义属性和方法。当我们创建了一个类的实例后,我们还可以给该实例绑定任意新的属性和方法。
看下面一个简单的例子:
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
>>> p = Point(3, 4)
>>> p.z = 5 # 绑定了一个新的属性
>>> p.z
5
>>> p.__dict__
{'x': 3, 'y': 4, 'z': 5}
在上面,我们创建了实例 p 之后,给它绑定了一个新的属性 z,这种动态绑定的功能虽然很有用,但它的代价是消耗了更多的内存。
因此,为了不浪费内存,可以使用 slots 来告诉 Python 只给一个固定集合的属性分配空间,对上面的代码做一点改进,如下:
class Point(object):
__slots__ = ('x', 'y') # 只允许使用 x 和 y
def __init__(self, x=0, y=0):
self.x = x
self.y = y
上面,我们给 slots 设置了一个元组,来限制类能添加的属性。现在,如果我们想绑定一个新的属性,比如 z,就会出错了,如下:
>>> p = Point(3, 4)
>>> p.z = 5
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-648-625ed954d865> in <module>()
----> 1 p.z = 5
AttributeError: 'Point' object has no attribute 'z'
注意:
使用 slots 有一点需要注意的是,slots 设置的属性仅对当前类有效,对继承的子类不起效,除非子类也定义了 slots,这样,子类允许定义的属性就是自身的 slots 加上父类的 slots。
python的多种魔术方法的更多相关文章
- Python 类的魔术方法
Python中类的魔术方法 在Python中以两个下划线开头的方法,__init__.__str__.__doc__.__new__等,被称为"魔术方法"(Magic method ...
- 流动python - 什么是魔术方法(magic method)
我们经常看到各种各样的方法已经被包围了由双下划线,例如__init__,他们是魔术方法. 魔术方法python语言预订好"协议",在不同情况下不同的魔术方法,是隐式调用.我们重写这 ...
- Python学习笔记之面向对象编程(三)Python类的魔术方法
python类中有一些方法前后都有两个下划线,这类函数统称为魔术方法.这些方法有特殊的用途,有的不需要我们自己定义,有的则通过一些简单的定义可以实现比较神奇的功能 我主要把它们分为三个部分,下文也是分 ...
- Python中的魔术方法详解
介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ...
- Python类之魔术方法
一.什么是魔术方法? 在Python的方法,我们经常会遇见__XXX__(),这样的方法,我们一般称为"魔术方法",赶紧搬个小板凳,我们一起来看看魔术方法有啥神奇的地方,这些方法又 ...
- python所有的魔术方法
据说,Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围,他们是面向对象的 Python 的一切. 他们是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个, ...
- Python中的魔术方法详解(双下方法)
介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ...
- Python基础之魔术方法(控制属性的访问和设置)
# 魔术方法--常规方法# 1. __int__ 构造函数# 2. __new__ 在类实例之前就创建了# 3. __iter__ 迭代器# 4. __del__ 析构方法,用来清除释放的对象内存# ...
- Python - 面向对象编程 - 魔术方法(双下划线方法)
什么是魔术方法 在Python中,所有以 __ 双下划线包起来的方法,都统称为 Magic Method 魔术方法,也叫双下划线方法 有哪些重要的魔术方法? __new__ https://www.c ...
随机推荐
- 5. JsonFactory工厂而已,还蛮有料,这是我没想到的
少年易学老难成,一寸光阴不可轻.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[ ...
- java基础-01:dos命令
进入cmd方式 win + r 输入 cmd 随便进入一个文件夹 在导航栏输入cmd,回车即进入命令行 命令 盘符切换:直接输入 E: ,回车即可 查看文件夹下所有目录:dir 切换目录: cd 跨盘 ...
- 更好用 更简单的Java缓存框架 jscache
比Spring Cache 更好用 更简单的缓存工具 jscache 取名意义为 java simple cache,基于AOP实现,支持注解到接口 自定义单个缓存过期时间配置 ttl,轻松扩展缓存实 ...
- 微信小程序发送订阅消息(之前是模板消息)
之前的模板消息已经废弃,现在改为订阅消息,订阅消息发布前,需要用户确认后才能接收订阅消息. 小程序端 index.wxml <button bindtap="send"> ...
- 区块链入门到实战(18)之以太坊(Ethereum) – 什么是智能合约
作用:提供优于传统合约的安全方法,并减少与合约相关的其他交易成本. 以太坊网络基石:以太坊虚拟币和智能合约. 智能合约(Smart contract )是一种旨在以信息化方式传播.验证或执行合同的计算 ...
- Spring boot程序的部署及运行
将 spring boot 应用程序打包成 jar 包 我们使用 spring boot 的 maven 插件来构建管理整个应用程序,使用 mvn package 将应用程序打包成一个 jar 包 将 ...
- .NET Core3.1 Dotnetty实战第三章
一.概要 本章主要内容就是讲解如何在dotnetty的框架中进行网络通讯以及编解码对象.数据包分包拆包的相关知识点. 后续会专门开一篇避坑的文章,主要会描述在使用dotnetty的框架时会遇到的哪些问 ...
- php利用快递100接口获取物流信息
PHP使用CURL调用快递100接口查询运单信息 类代码如下: <?php/** * 快递100接口调用类 * @author 齐云海 * date: 2019/05/29 */ class E ...
- MySQL常用指令,java,php程序员,数据库工程师必备。程序员小冰常用资料整理
MySQL常用指令,java,php程序员,数据库工程师必备.程序员小冰常用资料整理 MySQL常用指令(备查) 最常用的显示命令: 1.显示数据库列表. show databases; 2.显示库中 ...
- JavaScript 究竟是怎样去执行的?
摘要: 理解 JS 引擎运行原理. 作者:前端小智 原文:搞懂 JavaScript 引擎运行原理 Fundebug经授权转载,版权归原作者所有. 一些名词 JS 引擎 — 一个读取代码并运行的引擎, ...