这里只分析几个可能会常用到的魔法方法,像__new__这种不常用的,用来做元类初始化的或者是__init__这种初始化使用的 每个人都会用的就不介绍了。

其实每个魔法方法都是在对内建方法的重写,和做像装饰器一样的行为。理解这个道理 再尝试去理解每个细节装饰器会比较方便。

关于__str__和__repr__:

直接上例子:

class Test(object):
def __init__(self, world):
self.world = world def __str__(self):
return 'world is %s str' % self.world def __repr__(self):
return 'world is %s repr' % self.world t = Test('world_big')
print str(t)
print repr(t) output:

world is world_big str
world is world_big repr

其实__str__相当于是str()方法 而__repr__相当于repr()方法。str是针对于让人更好理解的字符串格式化,而repr是让机器更好理解的字符串格式化。

其实获得返回值的方法也很好测试,在我们平时使用ipython的时候,在不使用print直接输出对象的时候,通常调用的就是repr方法,这个时候改写repr方法可以让他方便的输出我们想要知道的内容,而不是一个默认内容。

关于__hash__和__dir__:

其实在实际应用中写了这么久python,也没有用到需要这两个方法出现的地方,但是在有些库里面是有看到过。

__hash__是hash()方法的装饰器版本,而__dir__是dir()的装饰器版本。

上代码展示一下__hash__用法:

class Test(object):
def __init__(self, world):
self.world = world x = Test('world')
p = Test('world')
print hash(x) == hash(p)
print hash(x.world) == hash(p.world) class Test2(object):
def __init__(self, song):
self.song = song def __hash__(self):
return 1241 x = Test2('popo')
p = Test2('janan') print x, hash(x)
print p, hash(p) output:

False
True
<__main__.Test2 object at 0x101b0c590> 1241
<__main__.Test2 object at 0x101b0c4d0> 1241

可以看到这里的hash()方法总是会返回int型的数字。可以用于比较一个唯一的对象,比方说一个不同内存的object不会相当,而相同字符串hash之后就会相等。然后我们通过修改__hash__方法来修改hash函数的行为。让他总是返回1241,也是可以轻松做到的。

另外一个方法是dir(),熟悉python的人都知道dir()可以让我们查看当前环境下有哪些方法和属性可以进行调用。如果我们使用dir(object)语法,可以获得一个对象拥有的方法和属性。同样的道理如果我们在类中定义了__dir__(),就可以指定哪些方法和属性能够被dir()方法所查看查找到。道理一样我这里不再贴出代码了,有兴趣的朋友可以自己去试试。

关于控制参数访问的__getattr__, __setattr__, __delattr__, __getattribute__:

__getattr__是一旦我们尝试访问一个并不存在的属性的时候就会调用,而如果这个属性存在则不会调用该方法。

来看一个__getattr__的例子:

class Test(object):
def __init__(self, world):
self.world = world def __getattr__(self, item):
return item x = Test('world123')
print x.world4 output:
world4

这里我们并没有world4属性,在找不到属性的情况下,正常的继承object的对象都会抛出AtrributeError的错误。但是这里我通过__getattr__魔法方法改变了找不到属性时候的类的行为。输出了查找的属性的参数。

__setattr__是设置参数的时候会调用到的魔法方法,相当于设置参数前的一个钩子。每个设置属性的方法都绕不开这个魔法方法,只有拥有这个魔法方法的对象才可以设置属性。在使用这个方法的时候要特别注意到不要被循环调用了。

下面来看一个例子:

class Test(object):
def __init__(self, world):
self.world = world def __setattr__(self, name, value):
if name == 'value':
object.__setattr__(self, name, value - 100)
else:
object.__setattr__(self, name, value) x = Test(123)
print x.world
x.value = 200
print x.value output:
123
100

这里我们先初始化一个Test类的实例x,通过__init__方法我们可以注意到,会给初始化的world参数进行赋值。这里的self.world = world语句就是在做这个事情。

注意,这里在进行world参数赋值的时候,就是会调用到__setattr__方法。这个例子来看world就是name,而后面的值的world就是value。我在__setattr__里面做了一个行为改写,我将判断name 值是'value'的进行特殊处理,把它的value值减少100. 所以输出了预期的结果。

我为什么说__setattr__特别容易出现循环调用?因为任何赋值方法都会走这个魔法方法,如果你在你改写__setattr__方法里面使用了类似的赋值,又回循环调用回__setattr__方法。例如:

class Test(object):
def __init__(self, world):
self.world = world def __setattr__(self, name, value):
self.name = value x = Test(123)
print x.world output:
RuntimeError: maximum recursion depth exceeded

这里我们想让__setattr__执行默认行为,也就是将value赋值给name,和object对象中的同样方法,做类似的操作。但是这里我们不调用父类__setattr__的方法来实现,做这样的尝试得到的结果就是,超过循环调用深度,报错。因为这里在执行初始化方法self.world = world的时候,就会调用__setattr__方法,而这里的__setattr__方法里面的self.name = value又会调用自身。所以造成了循环调用。所以使用该魔法方法的时候要特别注意。

__delattr__的行为和__setattr__特别相似,同样需要注意的也是循环调用问题,其他都差不多,只是把属性赋值变成了 del self.name这样的表示。下面直接上个例子,不再多赘述。

class Test(object):
def __init__(self, world):
self.world = world def __delattr__(self, item):
print 'hahaha del something'
object.__delattr__(self, item) x = Test(123)
del x.world
print x.world output:

hahaha del something
Traceback (most recent call last):
File "/Users/piperck/Desktop/py_pra/laplace_pra/practie_01_23/c2.py", line 12, in <module>
print x.world
AttributeError: 'Test' object has no attribute 'world'

可以看到我们将属性删除之后,就找不到那个属性了。但是在删除属性的时候调用了__delattr__,我在里面打印了一段话,在执行之前被打印出来了

__getattribute__和__getattr__方法唯一不同的地方是,上面我们已经介绍了__getattr__方法只能在找不到属性的时候拦截调用,然后进行重载或者加入一些其他操作。但是__getattribute__更加强大,他可以拦截所有的属性获取。所以也容易出现我们上面提到的,循环调用的问题。下面上一个例子来说明这个问题:

class Test(object):
def __init__(self, world):
self.world = world def __getattribute__(self, item):
print 'get_something: %s' % item
return item x = Test(123)
print x.world
print x.pp output:
get_something: world
world
get_something: pp
pp

可以看到,区别于__getattr__只拦截不存在的属性,__getattribute__会拦截所有的属性。所以导致了已经被初始化的world值123,也被改写成了字符串world。而不存在的属性也被改写了成了pp。

后面可能我会再撰文,阐述一些常用的protocol

Reference:

A Guide to Python’s Magic Methods --Rafe Kettler  September 4, 2015 

Python魔法方法(magic method)细解几个常用魔法方法(上)的更多相关文章

  1. Python魔法方法(magic method)细解几个常用魔法方法(下)

    接上文,再介绍最后几个常用的魔法方法. 关于__dict__: 先上个例子: class Test(object): fly = True def __init__(self, age): self. ...

  2. Python魔术方法-Magic Method

    介绍 在Python中,所有以"__"双下划线包起来的方法,都统称为"Magic Method",例如类的初始化方法 __init__ ,Python中所有的魔 ...

  3. <转>详解DNS的常用记录(上):DNS系列之二

    详解DNS的常用记录(上) 在上篇博文中,我们介绍了DNS服务器的体系结构,从中我们了解到如果我们希望注册一个域名,那么必须经过顶级域名服务器或其下级的域名服务器为我们申请的域名进行委派,把解析权委派 ...

  4. 流动python - 什么是魔术方法(magic method)

    我们经常看到各种各样的方法已经被包围了由双下划线,例如__init__,他们是魔术方法. 魔术方法python语言预订好"协议",在不同情况下不同的魔术方法,是隐式调用.我们重写这 ...

  5. Python基础:面向对象基础 (一) 类及其属性和魔法方法

    定义类,添加和获取对象属性 # 定义类 格式如下 # class 类名: # 方法列表 # 新式类定义形式 # info 是一个实例方法,第一个参数一般是self,表示实例对象本身 class Her ...

  6. python类:magic魔术方法

    http://blog.csdn.net/pipisorry/article/details/50708812 魔术方法是面向对象Python语言中的一切.它们是你可以自定义并添加"魔法&q ...

  7. (转)python类:magic魔术方法

    原文:https://blog.csdn.net/pipisorry/article/details/50708812 版权声明:本文为博主皮皮http://blog.csdn.net/pipisor ...

  8. python字符串常用的方法解析

    这是本人在学习python过程中总结的一些关于字符串的常用的方法. 文中引用了python3.5版本内置的帮助文档,大致进行翻译,并添加了几个小实验. isalnum S.isalnum() -> ...

  9. OpenCV常用图像拼接方法(一) :直接拼接

    OpenCV常用图像拼接方法将分为四部分与大家分享,这里是第一种方法,欢迎关注后续. OpenCV常用图像拼接方法(一) :直接拼接,俗称硬拼,就是简单的将两张图片合并成一张大图. 方法比较简单,这里 ...

随机推荐

  1. UVA215-Spreadsheet Calculator(模拟+拓扑排序)

    Problem UVA215-Spreadsheet Calculator Accept:401  Submit:2013 Time Limit: 3000 mSec Problem Descript ...

  2. numpy中矩阵乘法,星乘(*)和点乘(.dot)的区别

    import numpy a = numpy.array([[,], [,]]) b = numpy.array([[,], [,]]) 星乘表示矩阵内各对应位置相乘,矩阵a*b下标(0,0)=矩阵a ...

  3. 【转】Android hdpi ldpi mdpi xhdpi xxhdpi适配详解

    1.了解几个概念(1)分辨率.分辨率就是手机屏幕的像素点数,一般描述成屏幕的“宽×高”,安卓手机屏幕常见的分辨率有480×800.720×1280.1080×1920等.720×1280表示此屏幕在宽 ...

  4. 【angular】 ng-click 失效

    情况一:ng-click 和ng-if 一起使用 情况二:AngularJS中动态添加的ng-click 失效 正常情况(即非动态插入 DOM 对象)下,ng-click 这样的指令之所以有效(即点击 ...

  5. .NET 环境中使用RabbitMQ 转发 http://www.cnblogs.com/yangecnu/p/4227535.html

    .NET 环境中使用RabbitMQ   在企业应用系统领域,会面对不同系统之间的通信.集成与整合,尤其当面临异构系统时,这种分布式的调用与通信变得越发重要.其次,系统中一般会有很多对实时性要求不高的 ...

  6. Java关系运算

    关系运算符用来比较两个值的关系.关系运算符是二元运算符,运算结果是 boolean 型.当运算符对应的关系成立时,运算结果是 true,否则是 false. 关系表达式是由关系运算符连接起来的表达式. ...

  7. Python分析微信好友性别比例和省份城市分布比例

    如需转发请注明:小婷儿的博客:https://www.cnblogs.com/xxtalhr/p/10642241.html 一.安装模块 pip install itchat pip install ...

  8. Feature Extractor[ResNet]

    0. 背景 众所周知,深度学习,要的就是深度,VGG主要的工作贡献就是基于小卷积核的基础上,去探寻网络深度对结果的影响.而何恺明大神等人发现,不是随着网络深度增加,效果就好的,他们发现了一个违背直觉的 ...

  9. 【php增删改查实例】第二十六节 - 个人详情页制作

    在一般的系统中,当用户点击头像的时候,就会跳转到对应的个人详情页,在这个页面,他可以查看和修改自己的个人信息,或者更换头像. 本案例中,个人详情页使用bootstrap框架. 首先,我们新建一个htm ...

  10. ubuntu 添加开机启动服务

    新建umpserver.service [Unit] Description=UMPServer After=syslog.target network.target remote-fs.target ...