Python 常用魔法方法(下)

Python 常用魔法方法(下)

回顾

魔法方法是 Python 内置方法, 不需要我们手动调用, 它存在的目的是给 解释器 调用的. 比如我们在写 "1 + 1 " 的时候, 这个 "+ " 就会自动调用内置的魔法方法 "__ add__" . 几乎每个魔法方法, 都有一个对应的内置函数或运算符. 当我们使用这些方法去操作数据时, 解释器会自动调用这些对应的魔法方法. 也可以理解为, 重写内置函数, 如果改变的话.

具体的魔法方法等. 可以去看 内置的 builtins.py 这个接口文档.

内置函数对应魔法方法: 如 next() 对应 __ next __ , 类名() 对应 __ call __ 等这样的映射关系 ....

这一块的上篇呢, 还主要分享 type 类和 object 类来阐明 "万物皆对象". object 类是所有类的 基类. 而 type 类则用来判断某个实例对象所属的 "父类" 是谁, 类似父类,不绝对准确, 用来理解. 比如, 123 是 "int" class; "123" 是 "str" class; "str" 的 type 就是 type; object 的类型也是 type, 但 object 是 type 类的基类.

上篇引出 type 类, 当时用了一些哲学概念上的, "一, 二, 三" 来比喻, 仔细一想, 表述不太对, "元类" 的概念没说

元类 (metaclass): 如果是 type类是用来 静态创建类, 则 metaclass 是用来创建类的行为.

这一块先不谈了, 不太敢妄言, 待之后仔细查完资料在总结吧.

本篇还是继续介绍常用的魔法方法. 上篇主要对 __ new , __ init , __ call __ , __ str , __ del __ 初步认识, 并应用场景简单举了例子. go on...

补: 关于 __ new __:

  • 通常与 __ init , 被称为 "构造函数". ___ del __ 被称为 "析构函数".
  • 我目前用的的例子, 就只用 "单例" 用到.
  • new 方法还涉及到 metaclass 的知识, 平时也不太用得到, 姑且先不涉及了.
  • 用于继承一个不可边类型对象类 (tuple, int, str...) 的构造器, 当一个实例被创建时的初始化方法.

魔法方法总结

常用

__ new__ (cls, ....) 实例化所调用, 返回一个实例对象,(若无, 则不会调 __ init __ 在单例场景中时有用过.

__ init __ (self,...) 类实例化时, 的初始化值设置.

__ del __ (self) 也称为析构器. 当一个实例被 del 的时候会被触发.

__ call __(self, ...) 将类实例对象, "装饰" 为像函数一行可调用, 即 obj(*args.), 在 装饰器 有用到.

__ str __ (self) 描述对象信息, 在 print(obj) 时被触发.

__ len __ (self) 在使用 len() 时被调用.

__ repr __ (self) 在使用 repr() 时被调用.

repr(), 返回一个对象的 string 格式, 就是在外面套一个 "", 跟 eval() 函数像是其逆.

# repr(obj) -> str
# eval(str) -> obj

>>> repr(123)
'123'
>>> repr([1,2,"cj", [1,[2]]])
"[1, 2, 'cj', [1, [2]]]"

t = repr({'a':123, 'b':{"c":4}})
>>> t
"{'a': 123, 'b': {'c': 4}}"

>>> eval(t)
{'a': 123, 'b': {'c': 4}}

__ bytes __ (self) 在使用 bytes() 时被调用.

__ hash __ (self) 在使用 hash() 时被调用. 返回可哈希对象的数值, 传不可哈希(如list) 则报错

__ bool __ (self) 在 bool() 时被调用.

__ format __ (self,...) 在使用 format() 被调用. 不过我更多使用 f"{变量名} hello" 这样的语法多一点.

....

属性的

__ getattr __(self, item) 试图获取一个不存在属性的行为. 曾用来, 用来做异常判断.

__ getattribute __(self, item) 该类属性被访问时的行为. 跟 getattr 其实不太好搭配.

__ setattr __(self, key, value) 当一个属性被设置时的行为, obj.name = "youge"

__ delattr __(self, item) 属性被删除时的行为.

__ dir __(self) 定义当 dir() 被调用时的行为

__ get__ (self, instance, owner) 定义当描述符的值被取得时的行为

__ set__ (self, instance, value) 定义当描述符的值被改变时的行为

__ delete __(self, instance) 定义当描述符的值被删除时的行为

...

比较的

__ lt__ (self, other) 小于号的行为:x < y 调用 x.__ lt __(y)

__ le__ (self, other) 小于等于号的行为:x <= y 调用 x.__ le__(y)

__ eq__ (self, other) 等于号的行为:x == y 调用 x.__ eq__(y)

__ ne__ (self, other) 不等号的行为:x != y 调用 x.__ ne__(y)

__ gt __ (self, other) 大于号的行为:x > y 调用 x.__ gt__(y)

__ ge __ (self, other) 大于等于号的行为:x >= y 调用 x.__ ge__(y)

...

算数的

__ add__(self, other) 定义加法的行为:+

__ sub__(self, other) 定义减法的行为:-

__ mul__(self, other) 定义乘法的行为:*

__ truediv__(self, other) 定义真除法的行为:/

__ floordiv__(self, other) 定义整数除法的行为://

__ mod__(self, other) 定义取模算法的行为:%

__ divmod__(self, other) 定义当被 divmod() 调用时的行为

__ pow__(self, other[, modulo]) 定义当被 power() 调用或 ** 运算时的行为

... 还有什么 位运算, 逆运算, 增量赋值 .. 各种计算符号, 都是一个个的魔法方法, 即都是可以改写的.

这些有啥用呢, 举个算数的, 通过重写, 可以自定义 运算符, 比如 1 +1 = 3 是可以的

# 重写 "+" 这个运算符, 即重写 __add__ 这个方法
class Num:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        print(self.value + other + 1)

if __name__ == '__main__':
    one = Num(1)
    one + 1

# output
3

类型转换

__ complex__(self) 定义当被 complex() 调用时的行为(需要返回恰当的值)

__ int__(self) 定义当被 int() 调用时的行为

__ float__(self) 定义当被 float() 调用时的行为

__ round__(self[, n]) 定义当被 round() 调用时的行为

__ index__(self)

这一块了解就行, 建议不要乱改, 是关联的, 比如 index 被重写, 那 int 也有重写, 而且返回值也是要相同的.

上下文管理

__ enter__ (self)

定义当使用 with 语句时的初始化行为
__ enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定

__ exit__ (self, exc_type, exc_value, traceback)

定义当一个代码块被执行或者终止后上下文管理器应该做什么
一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作

容器类型

__ len__(self) 定义当被 len() 调用时的行为(返回容器中元素的个数)

__ getitem__(self, key) 定义获取容器中指定元素的行为,相当于 self[key]

__ setitem__(self, key, value) 定义设置容器中指定元素的行为,相当于 self[key] = value

__ delitem__(self, key) 定义删除容器中指定元素的行为,相当于 del self[key]

__ iter__(self) 定义当迭代容器中的元素的行为

__ reversed__(self) 定义当被 reversed() 调用时的行为

__ contains__(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为

容器这个概念, 很直观有抽象, 是有点矛盾, 但 非常重要.

这里举个 迭代器 的栗子, 后面会单独来讲, 这里引入一波, 迭代器: 实现了 __ iter __ , __ next __ 的类 (容器)

class Iterator:
    """迭代器, 以list 作为底层结构"""
    def __init__(self, lst):
        self.lst = lst
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < len(self.lst):
            # get current value
            value = self.lst[self.index]
            self.index += 1
        else:
            raise StopIteration
        return value

    # __next__ 为了能与 for 对应上
    # __iter__ 迭代后返回自身
       

小结

  • 每一个魔法方法, 几乎都跟咱用的 内置函数是有映射关系的
  • 可以通过重写魔法方法来适应业务, 如运算符重载, 类属性判断, 异常检测等.
  • 还是在于设计类这方面会很有用的.

本篇的目的是大致了解魔法方法, 留印象为主, 具体用啥, 再进行百度即可.而上篇呢重点是举了几个常用来重写魔法方法的应用场景, 当然也是我自己经验有限, 目前只用到的非常少吧.

原文地址:https://www.cnblogs.com/chenjieyouge/p/12271619.html

时间: 2024-12-11 08:02:09

Python 常用魔法方法(下)的相关文章

python常用魔术方法概览

构造和初始化 __init__(self, args) 构造函数 __new__(cls) 传入的是类实例 __del__(self) 析构函数,调用 del cls 时会被调用 属性访问控制 __getattr__(self, name) 如果属性已经定义了那么不会再执行__getattr__()了,而是直接通过访问实例字典返回结果,__getattr__()只在访问未定义的属性时被触发 __setattr__(self, name, value) 直接给属性赋值 cls.name = val

magic method细解python一直让我疑惑的几个常用魔法方法(上)

这里只分析几个可能会常用到的魔法方法,像__new__这种不常用的,用来做元类初始化的或者是__init__这种初始化使用的 每个人都会用的就不介绍了. 其实每个魔法方法都是在对内建方法的重写,和做像装饰器一样的行为.理解这个道理 再尝试去理解每个细节装饰器会比较方便. 关于__str__和__repr__: 直接上例子: class Test(object): def __init__(self, world): self.world = world def __str__(self): re

21 python的魔法方法(转)

魔法方法 含义   基本的魔法方法 __new__(cls[, ...]) 1. __new__ 是在一个对象实例化的时候所调用的第一个方法2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用4. __new__ 主要是用于继承一个不可变的类型比如

python中魔法方法__str__与__repr__的区别

提出问题 当我们自定义一个类时,打印这个类对象或者在交互模式下直接输入这个类对象按回车,默认显示出来的信息好像用处不大.如下所示 In [1]: class People: ...: def __init__(self, name, sex): ...: self.name = name ...: self.sex = sex ...: In [2]: p = People('xiaoming', 'male') In [3]: p Out[3]: <__main__.People at 0x7

python之魔法方法

is 和 == 的关系 ''' == 值相等 值运算 is 内存地址相等 身份运算 is 要求更苛刻 不仅要求值相等,还要求内存地址相同 ''' a = 111 b = 111 a == b # 值相等 值运算使用 a is b # 值相等内存地址不相等使用 is 和 isinstance的关系 class A: pass class B(A): pass b = B() print(isinstance(b, B)) print(isinstance(b, A)) print(issubcla

python 魔法方法(学习过程的笔记)

有小伙伴会问,什么是python的魔法方法,python的魔法方法有什么用呢, 它们在面向对象的Python的处处皆是.它们是一些可以让你对类添加"魔法"的特殊方法. 它们经常是两个下划线包围来命名的. 我感觉魔法方法很牛逼的, 目前我们常见的魔法方法大致可分为以下几类: 构造与初始化 类的表示 访问控制 比较操作 容器类操作 可调用对象 Pickling序列化 在我们写python中最常见的就是__init__,这是python的构造方法,这是初始化对象,定义一个对象的初始化的值,_

python中的魔法方法

1.什么是魔法方法? 魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的.它们经常是两个下划线包围来命名的(比如 __init__,__lt__),Python的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要! 2.__init__(self[, ...]),__new__(cls[, ...]),__del__(self) __init__ 构

python 魔法方法之:__getitem__ __setitem__ __delitem__

python的魔法方法: 在Python中,如果我们想实现创建类似于序列和映射的类,可以通过重写魔法方法__getitem__.__setitem__.__delitem__.__len__方法去模拟. __getitem__(self,key):返回键对应的值. __setitem__(self,key,value):设置给定键的值 __delitem__(self,key):删除给定键对应的元素. __len__():返回元素的数量 下面我们模仿dict创建自己的类: class MyDic

python_面向对象魔法方法指南

原文: http://www.rafekettler.com/magicmethods.html 原作者: Rafe Kettler 翻译: hit9 原版(英文版) Repo: https://github.com/RafeKettler/magicmethods Contents (译)Python魔法方法指南 简介 构造方法 操作符 比较操作符 数值操作符 一元操作符 常见算数操作符 反射算数运算符 增强赋值运算符 类型转换操作符 类的表示 访问控制 自定义序列 预备知识 容器背后的魔法方