Python面向对象类型中的魔法方法梳理,总结

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

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

1.关于strrepr:

    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是让机器更好理解的字符串格式化

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

2.关于hashdir:

其实在实际应用中,这两个用到的频率并不高,但是在有些库里面是有看到过
hash是hash()方法的装饰器版本,而dir是dir()的装饰器版本。

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()方法所查看查找到。

3.关于控制参数访问的getattrsetattrdelattrgetattribute:

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

    def __init__(self, world):
        self.world = world

    def __getattr__(self, item):
        return item


x = Test('world123')
print x.world4

output:
world4

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

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

    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这样的表示。下面直接上个例子,不再多赘述。

    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,我在里面打印了一段话,在执行之前被打印出来了

getattributegetattr方法唯一不同的地方是,上面我们已经介绍了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。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 字符串格式化调用方法 —— format 通过创建字符串模板,利用format函数,替代相应的值。 可以通过绝对位...
    plutoese阅读 1,514评论 0 47
  • python 魔术方法 前言 在做python开发的过程中,我们大家都会遇到在class(类)中使用双下划线的方法...
    shu_ke阅读 445评论 1 2
  • 天机神算子阅读 186评论 0 0
  • 又到半个月探望一次儿子的时间了。我拎着儿子电话嘱咐我要带的东西,走进了他们宿舍。 宿舍里到处是人,...
    婉叶老师阅读 974评论 5 18
  • 独自站在大道中央, 看四通八达的路向着前方, 孤单感到迷茫 我又...
    尘霞阅读 268评论 0 2