第四章 面向对象编程 -- 魔术方法1

第零章 学前准备
第一章 数据结构 – 基本数据类型
第一章 数据结构 – 字符串
第一章 数据结构 – 列表、元组和切片
第一章 数据结构 – 字典
第一章 数据结构 – 集合
第一章 – 数组、队列、枚举
第一章 数据结构 – 序列分类
第二章 控制流程
第三章 函数也是对象 – 函数定义以及参数
第三章 函数也是对象 – 高阶函数以及装饰器
第三章 函数也是对象 – lambda 表达式、可调用函数及内置函数
第四章 面向对象编程 – 自定义类、属性、方法和函数
第四章 面向对象编程–魔术方法1


第四章 面向对象编程 – 魔术方法1

4.4 特殊方法(magic method)

一个类可以定义一些特殊命名的方法,它们使用特殊语法调用,比如算术运算符、下标以及切片。魔术方法(magic method)是特殊方法的昵称。

4.4.1 特殊方法一览

更多可参考DataModel

表 1-1 跟运算符无关的特殊方法
类别 方法名
字符串/字节序列表示形式 __repr____str____format__(格式化字符串str.format)__bytes__
数值转换 __abs____bool____complex____int____float____hash____index__
集合模拟 __len____length_hint____getitem____setitem____delitem____missing____contains__
迭代枚举 __iter____reverse____next__
可调用模拟 __call__
上下文管理 __enter____exit__
实例创建和销毁 __new____init____del__
属性管理 __getattr____getattribute____setattr____delattr____dir__
属性描述符 __get____set____delete__
跟类相关的服务 __prepare____instancecheck____subclasscheck__
表 1-2 跟运算符有关的特殊方法
类别 方法名
一元运算符 __neg__ -__pos__ +__abs__ abs()
众多比较运算符 __lt__ <__le__ <=__eq__ ==__ne__ !=__gt__ >__ge__ >=
算术运算符 __add__ +__sub__ -__mul__ *__truediv__ /__floordiv__ //__mod__ %__divmod__ divmod__pow__ **或pow()__round round()
反向算术运算符 __radd____rsub____rmul____rtruediv____rfloordiv____rmod____rdivmod____rpow__
增量赋值算术运算符 __iadd____isub____imul____itruediv____ifloordiv____imod____ipow__
位运算符 __invert__ -__lshift__ <<__rshift__ >>__and__ &__or__
反向位运算符 __rlshift____rrshift____rand____ror____rxor__
增量赋值位运算符 __ilshift____irshift____iand____ior____ixor__

4.4.2 重要特殊方法调用

4.4.2.1 实例创建和销毁
  1. object.__new__(cls[, ...])

    new方法在调用后可以产生类cls的实例。并且,new是静态方法,第一个参数必须是需要创建实例的cls为第一个参数,该参数在实例化时由解释器自动提供。new的典型实现应该通过super().__new__(cls[, ...])调用父类的__new__方法先创建cls的实例,在将实例返回之前可以做一些想要的修改,以达到自己的目标。

    如果__new__被调用并返回cls的实例,那么__init__方法将会被调用。然而,如果__new__没有返回实例,__init__方法不会调用。

    __new__可以让我们在继承不可变类型(比如intstrtuple)创建实例时实现一些自定义操作。

  2. object.__init__(self[, ...])

    init方法在实例被创建之后调用。如果一个基类有init方法,那么在子类的init方法中,必须显示地调用基类的init方法(比如:super().__init__([args...])),这样才能保证实例中基类部分被初始化,实例被完整地实现。一般来说,new创建实例,init自定义实例。如果一个non-None值在init被返回,那么在运行时,将会抛出TypeError异常。

  3. object.__del__(self)

    当一个对象要被销毁时,这时解释器就会调用对象的__del__对象。一般,程序员很少主动调用__del__去销毁对象,而是系统自动调用。__del__与内置函数del不同,del只是删除一个对象的引用,而__del__是当引用的数量为零时才会被调用。
# 使用__new__实现单例类
class Singleton:
    __instance = None

    def __new__(cls):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance


s_1 = Singleton()
s_2 = Singleton()
print(s_1 is s_2)
4.4.2.2 类相关的服务
  1. class.__instancecheck__(self, instance):如果 instance 应被视为 class 的一个(直接或间接)实例则返回真值。如果定义了此方法,则会被调用以实现 isinstance(instance, class)

  2. class.__subclasscheck__(self, subclass)Return true 如果 subclass 应被视为 class 的一个(直接或间接)子类则返回真值。如果定义了此方法,则会被调用以实现 issubclass(subclass, class)

  3. __prepare__
4.4.2.2 字符串/字节序列表示形式
  1. object.__repr__(self):调用内置函数repr时被调用,返回一个对象的字符串表达形式,即返回该对象的描述。如果没有实现,得到的字符串将会是"xxx object at 0x102100070"的形式。交互式控制台和调试程序(debugger)用repr函数来获取字符串表示形式,所以返回的字符串应该准确", "无歧义,并且尽可能表达出如何用代码创建出这个被打印的对象。

  2. object.__str__(self):内置函数str时调用吗,与__repr__不同,__str__返回的字符串将会是更易于阅读的,并且,如果定义了rep而没有定义__str__,那么会用__repr__代替__str__。总之,尽量实现__repr__,如果你觉得__repr__不够易懂,那么可以再实现__str__,实现一个更易于阅读的版本。

  3. object.__bytes__(self):Called by bytes to compute a byte-string representation of an object. This should return a bytes object.

  4. object.__format__(self, format_spec):调用内置的formatstr.format()方法时,调用,返回对象的格式化字符串表达式。参数format_spec是对格式化选项的描述,比如:%s", "%r等。

4.4.2.3 数值转换
  1. object.__hash__(self):通过内置函数hash()以及像set", “frozenset”, "dict散列容器中对成员的操作时调用。__hash__返回值应该是一个整数。比较推荐的一种实现是把对象内部所有的属性放进一个元组,然后返回该元组的哈希值。

    If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

    User-defined classes have __eq__() and __hash__() methods by default. 这时,默认的__eq__也是使用is判断是否相等。

    A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None. When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError when a program attempts to retrieve their hash value, and will also be correctly identified as unhashable when checking isinstance(obj, collections.abc. Hashable).

    If a class that does not override __eq__() wishes to suppress hash support, it should include __hash__ = None in the class definition.

  2. object.__bool__(self):Called to implement truth value testing and the built-in operation bool(); should return False or True. When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __bool__(), all its instances are considered true.

  3. object.__complex__(self)object.__int__(self)object.__float__(self)object.__abs__(self):Called to implement the built-in functions complex(), int(), float() and abs(). Should return a value of the appropriate type.

  4. object.__index__(self):Called to implement operator.index(), and whenever Python needs to losslessly convert the numeric object to an integer object (such as in slicing, or in the built-in bin(), hex() and oct() functions). Presence of this method indicates that the numeric object is an integer type. Must return an integer.

    If __int__(), __float__() and __complex__() are not defined then corresponding built-in functions int(), float() and complex() fall back to __index__().

    PEP 357 – Allowing Any Object to be Used for Slicing

猜你喜欢

转载自blog.csdn.net/qq_31654025/article/details/132780889