Python常用魔术方法总结

__init__:构造函数

  • 触发时机:实例化对象之后自动触发,在__new__之后执行。实例化对象其实包含两步,1:制作一个对象 2:为对象初始化操作
  • 作用:为对象添加对象的所属成员
  • 参数:self必填,接收当前对象,其他参数可根据实例化的传参决定
  • 返回值:无
  • 注意事项:无
class Human:

    def __init__(self, name):
        print('init method for {}'.format(name))

    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('chengjie')  # 执行这一步实例化对象human之后, 会触发 __init__, 打印出init method for chengjie

__new__:构造函数

  • 触发时机:实例化对象的时候自动触发,在__init__之前执行。实例化对象其实包含两步,1:制作一个对象 2:为对象初始化操作
  • 作用:管理控制对象的生成过程;实现单例设计模式
  • 参数:cls必填,其他参数可根据实例化的传参决定
  • 返回值:必须返回类的实例化对象
  • 注意事项:无
class Human:

    def __init__(self, name):
        print('init method for {}'.format(name))

    def __new__(cls, name):
        print(name)
        if name == 'chengjie':
            r = super(Human, cls).__new__(cls)
            return r
        else:
            pass


    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('chengjie')  # 执行这一步实例化对象human之后, 会先触发__new__打印出chengjie,返回实例化对象,再触发 __init__,打印出init method for chengjie

__del__:析构方法

  • 触发时机:对象被系统回收的时候自动触发(del不一定触发)
  • 作用:回收程序使用过程中的信息和变量等
  • 参数:self必填,接收当前对象
  • 返回值:无
  • 注意事项:如果主动使用del(非__del__),则会在调用del的时候触发,而非程序最后,但也不是调用了del一定会触发__del__
class Human:

    def __init__(self, name):
        print('init method for {}'.format(name))

    def __new__(cls, name):
        print(name)
        if name == 'chengjie':
            r = super(Human, cls).__new__(cls)
            return r
        else:
            pass

    def __del__(self):
        print('del method')


    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('chengjie')  # 执行这一步实例化对象human之后, 会先触发__new__打印出chengjie,返回实例化对象,再触发 __init__,打印出init method for chengjie
human2 = human
del human # 此时不会触发__del__,在程序最后才会触发,如果没有human2 = human,则在此处调用del会触发__del__,程序最后则不会触发
print('running') # 在执行完这一句之后,会触发__del__,打印出del method,__del__总是会在程序最后被触发

__call__

  • 触发时机:将实例化对象当做函数调用的时候自动触发(函数其实也是对象,python中一切皆对象)
  • 作用:常用语归结类或对象的操作步骤,方便后期操作
  • 参数:self必填,接收当前对象
  • 返回值:可有可无
  • 注意事项:无
class MakeCake:

    def buy_yuan_liao(self):
        print('购买原料')

    def huo_mian(self):
        print('和面')

    def fa_jiao(self):
        print('发酵')

    def hong_bei(self):
        print('烘焙')

    def __call__(self, *args, **kwargs):
        self.buy_yuan_liao()
        self.huo_mian()
        self.fa_jiao()
        self.hong_bei()
        print('蛋糕制作完成')


maek_cake = MakeCake() # 实例化一个类MakeCake的对象make_cake
maek_cake() # 把对象make_cake当做一个函数调用
>>>>购买原料
    和面
    发酵
    烘焙
    蛋糕制作完成

__len__

  • 触发时机:使用len函数检测对象长度的时候自动触发
  • 作用:使len函数可以直接检测对象中某个数据的长度
  • 参数:self必填,接收当前对象,无其他参数
  • 返回值:必须有,且必须是整形
  • 注意事项:无
class Human:

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

    def __len__(self):
        # 必须有返回值,而且必须是整形
        return len(self.name)


    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('chengjie')
print(len(human)) #如果没有实现__len__, 则无法直接使用len(human), 否则报TypeError: object of type 'Human' has no len(), 实现了__len__后,可以根据需要

>>>>8

__str__

  • 触发时机:使用print打印对象的时候触发
  • 作用:可以自定义打印对象时输出的内容
  • 参数:self必填,接收当前对象
  • 返回值:必须有,且一定是字符串类型
  • 注意事项:除print之外,只用str()时也会触发该魔术方法
class Human:

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

    def __str__(self):
        return 'Name: %s' % self.name

    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('Python')
print(human)   #如果没有__str__魔术方法,则打印出来的是类似于<__main__.Human object at 0x000001BFE3F39828>,这是继承自object的__str__方法

>>>>>Name: Python

__repr__

  • 触发时机:使用repr转换对象的时候触发
  • 作用:可以设置repr函数操作对象的输入结果
  • 参数:self必填,接收当前对象
  • 返回值:必须有,且一定是字符串类型
  • 注意事项:其实__str____repr__是完全一样的,在实际中,我们可以只用实现__repr__,因为如果一个对象没有实现__str__,解释器会用__repr__代替
class Human:

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

    # def __str__(self):
    #     return 'Name: %s' % self.name

    def __repr__(self):
        return 'Name:%s' % self.name

    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('Python')
print(human) # 该类没有实现__str__,但是打印对象的时候,会执行__repr__

>>>>>Name:Python

__bool__

  • 触发时机:使用bool()转换对象的时候触发
  • 作用:用于检测对象成员的信息
  • 参数:self必填,接收当前对象
  • 返回值:必须有,且一定是bool值,即TrueFalse
  • 注意事项:无
class Human:

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

    def __bool__(self):
        if self.name == 'cheng':
            return True
        else:
            return False

    # 方法
    def eat(self):
        print('eat method')

    def run(self):
        print('run method')


human = Human('cheng')
human2 = Human('Python')
print(bool(human))
print(bool(human2))

>>>>>True
>>>>>False

与属性相关的魔术方法

属性的访问顺序

  1. 调用__getattribute__
  2. 调用数据描述符
  3. 调用当前对象的所属成员
  4. 调用类的所属成员
  5. 调用非数据描述符
  6. 调用父类的所属成员
  7. 调用__getattr__

__getattribute__

  • 触发时机:访问对象的成员属性的时候自动触发,无论该成员属性是否存在
  • 作用:可以在用户访问成员属性的时候进行数据处理等操作,例如对敏感信息进行脱敏处理
  • 参数:self接收当前对象,第二个参数接收访问的成员属性名称字符串
  • 返回值:可有可无,没有的话就返回None
  • 注意事项:在该魔术方法中,禁止使用 当前对象.成员 的方式(例如:self.name)访问成员,否则会发生递归次数过大的错误RecursionError: maximum recursion depth exceeded while calling a Python object
class Human:

    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18

    def __getattribute__(self, item):
        print('getattribute call by %s' % self)
        # return self.name   如果返回的是self.name,则会报错
        return super().__getattribute__(item)

    def eat(self):
        print('eat method is running')


human = Human()
print(human.name)

>>>>>>>>getattribute call by <__main__.Human object at 0x000001D633849240>
>>>>>>>>Python

__getattr__

  • 触发时机:访问不存在的对象成员属性的时候自动触发
  • 作用:防止访问不存在的对象成员的时候报错;为不存在的成员定义值
  • 参数:self接收当前对象,第二个参数接收访问的成员属性名称字符串
  • 返回值:可有可无,没有的话就返回None
  • 注意事项:__getattribute____getattr__可以同时存在,如果同时存在,那么在访问不存在的值时,__getattribute____getattr__都会触发
class Human:

    # 成员属性
    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18

    def __getattr__(self, item):
        if item == 'score':
            return 88
        else:
            return 'error item'

    def eat(self):
        print('eat method is running')


human = Human()
print(human.score)
print(human.school)

>>>>88
>>>>error item

__setattr__

  • 触发时机:添加或者修改对象成员的时候自动触发
  • 作用:可以限制或者管理对象成员的添加或修改操作
  • 参数:self接收当前对象,第二个参数接收设置的成员名称字符串,第三个参数接收设置的值
  • 返回值:无
  • 注意事项:在该魔术方法中,禁止使用 当前对象.成员=值 的方式(例如:self.name = 'Mike')设置成员,否则会发生递归次数过大的错误RecursionError: maximum recursion depth exceeded while calling a Python object
class Human:

    # 成员属性
    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18

    def __setattr__(self, key, value):
        if key == 'school':   # 当设置的成员名称为school时,直接跳过,不设置
            pass
        else:
            super().__setattr__(key,value) #注意此处不可以用self.key = value

    def eat(self):
        print('eat method is running')


human = Human()
human.school = 'QH'
human.score = 99
print(human.school)  # 报错,school不存在
print(human.score) # 输出 99

>>>>AttributeError: 'Human' object has no attribute 'school'
>>>>99

__delattr__

  • 触发时机:删除对象成员的时候自动触发
  • 作用:可以限制删除对象成员或者在删除时执行额外的工作
  • 参数:self接收当前对象,第二个参数接收删除的成员名称字符串
  • 返回值:可有可无,无的话则不会执行删除操作
  • 注意事项:在该魔术方法中,禁止使用 del 当前对象.成员 的方式(例如:del self.name)删除成员,否则会发生递归次数过大的错误RecursionError: maximum recursion depth exceeded while calling a Python object
class Human:

    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18

    def __delattr__(self, item):
        if item == 'name': # 当删除的对象成员名称为name时,不执行删除操作,即限制了删除name成员
            pass
        else:
            # del self.sex  如果执行此行,则会报错,递归数过大
            return super().__delattr__(item)

    def eat(self):
        print('eat method is running')


human = Human()
del human.name  # 不会删除name属性
del human.sex  # 会删除sex属性
print(human.name)
print(human.sex)

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

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,723评论 0 10
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,734评论 0 8
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,089评论 1 32
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,733评论 2 9
  • 付出马上就想得到回报,适合去做钟点工。 目光长远,用心经营,十年树木,百年树人,不要想太多回报,真正的回报在你自我...
    龙之子阅读 1,175评论 0 0