深入解析Python的内置魔术方法——探索Python对象的神奇力量

?? 前言

博客地址:

  • CSDN:https://blog.csdn.net/powerbiubiu

?? 简介

在Python的类中,以两个下划线开始和结束的方法如__init__、__del__、__str__等称为魔术方法,它们常常被视为一种私有方法,不能通过类及其子类的实例调用。
魔术方法与普通方法的区别是不需要调用,需要触发。在类或对象的某些事件触发后会自动执行,如果希望根据自己的程序定制特殊功能的类,那么就需要对魔术方法进行重写。魔术方法众多,下面介绍一些常用的魔术方法。

?? 正文

1 构造与初始化

构造方法

  • 触发时机: 实例化对象时自动触发(在__init__之前触发)
  • 参数:至少一个cls 接收当前类,其他参数根据初始化方法参数决定
  • 返回值:必须返回一个对象实例,没有返回值,则实例化对象的结果为None
  • 作用:实例化对象
  • 注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
1.1 new
class Test:
    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls)
        print('__new__()方法被调用')
        print(obj)
        return obj

    def __init__(self):
        print('__init__()方法被调用')
        print(self)


t = Test()

# __new__()方法被调用
# <__main__.Test object at 0x0000026C2B2731D0>
# __init__()方法被调用
# <__main__.Test object at 0x0000026C2B2731D0>

备注:在__new__方法中,需要return语句,否则程序不会继续往下执行初始化函数__ini__

1.2 init

初始化方法

  • 触发机制:实例化对象之后立即触发
  • 参数:至少有一个self,接收当前对象,其他参数根据需要进行定义
  • 返回值:无
  • 作用:初始化对象的成员
class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age
        print(f'我叫{self.name},今年{self.age}岁了')


p = Person('张三', 18)

# 我叫张三,今年18岁了
1.3 del

析构函数

  • 触发时机:当该类对象被销毁时,自动触发
  • 参数:一个self,接受当前对象
  • 返回值:无
  • 作用:关闭或释放对象创建时资源
  • 注意:del不一定会触发当前方法,只有当前对象没有任何变量引用时才会触发
class Test:
    def __init__(self):
        print('对象初始化')

    def __del__(self):
        print('对象被销毁')

t = Test()

# 对象初始化
# 对象被销毁

2 可调用对象

2.1 call

可调用对象魔术方法

  • 触发时机:将对象当作函数调用时触发,方式: 对象()
  • 参数:至少一个self接收对象,其余根据调用时参数决定
  • 返回值:根据情况而定
  • 作用:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用
class Test:
    def __call__(self, *args, **kwargs):
        print('__call__方法被调用了')


t = Test()
t()

# __call__方法被调用了

3 类的表示

3.1 str

需要对象转换为string时,python都会默认调用该魔法方法,如print的时候,与字符串进行+运算的时候,凡是需要进行隐示类型转换为字符串的地方,都会自动调用该方法。

class Person:

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

    def __str__(self):
        return f'我叫{self.name},今年{self.age}岁了'


p = Person('Tom', 18)
print(p)

# 我叫张三,今年18岁了
3.2 repr

函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式,某对象没有适于人阅读的解释形式的话,str() 会返回与repr(),所以print展示的都是str的格式。

class Person:

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

    def __repr__(self):
        return f'Person[name:{self.name}, age:{self.age}]'


p = Person('Tom', 18)
print(p)

# Person[name:Tom, age:18]
3.3 同时使用__str__和__repr__
class Person:

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

    def __str__(self):
        return f'我叫{self.name},今年{self.age}岁了'

    def __repr__(self):
        return f'Person[name:{self.name}, age:{self.age}]'


p = Person('Tom', 18)
print(str(p))
print(repr(p))

# 我叫Tom,今年18岁了
# Person[name:Tom, age:18]
3.4 bool
  • 触发时机: 使用bool(对象)的时候触发
  • 参数:一个self接收对象
  • 返回值:必须是布尔值
  • 作用:根据实际情况决定,可以作为快捷方式使用
  • 注意:仅适合于返回布尔值的操作
class Test:
    def __init__(self, age):
        self.age = age

    def __bool__(self):
        print()
        return self.age >= 18
        # 恒等于True
        # return True 
    	# 恒等于False
    	# return False 


t = Test(18)
print(bool(t))

4 属性访问

4.1 getattr

定义当用户试图获取一个不存在的属性时的行为。

  • 触发时机:获取不存在的对象成员时触发
  • 参数:一个是接收当前对象的self,一个是获取成员名称的字符串
  • 返回值:必须有值
  • 作用:为访问不存在的属性设置值
  • 注意:getattribute无论何时都会在getattr之前触发,触发了getattribute就不会在触发getattr了
4.2 getattribute

定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)

  • 触发时机:使用对象成员时触发,无论成员是否存在
  • 参数:1个接收当前对象self,一个是获取的成员的名称字符串
  • 返回值:必须有
  • 作用:在具有封装操作(私有化时),为程序开部分访问权限使用
4.3 setattr

定义当一个属性被设置时的行为

  • 触发时机:设置对象成员值的时候触发
  • 参数:1个当前对象的self,一个是要设置的成员名称字符串,一个是要设置的值
  • 返回值:无 过程操作
  • 作用:接管设置操作,可以在设置前之前进行判断验证等行为
  • 注意:在当前方法中无法使用成员=值的方式直接设置成员,否则会无限递归,必须借助object的设置方法来完成
4.4 delattr

定义当一个属性被删除时的行为

  • 触发时机:删除对象成员时触发
  • 参数:一个当前对象的self
  • 返回值:无
  • 作用:可以在删除成员时进行验证。
class Test:
    def __getattribute__(self, item):
        print('__getattribute__')
        return super().__getattribute__(item)
 
    def __getattr__(self, item):
        print('__getattr__')
 
    def __setattr__(self, key, value):
        print('__setattr__')
        super().__setattr__(key, value)
 
    def __delattr__(self, item):
        print('__delattr__')
        super().__delattr__(item)
        
t = Test()
t.x
# __getattribute__
# __getattr__
t.x = 1
# __setattr__
del t.x
# __delattr__

5 运算符魔术方法

  • __add__(self,other):实例之间的加法运算+
  • __sub__(self,other):实例之间的减法运算-
  • __mul__(self,other):实例之间的乘法运算*
  • __truediv__(self,other):类与类之间的真除。只有from future import division之后它才有效/
  • __floordiv__(self,other):类与类之间的浮点除法运算//
  • __mod__(self,other):类与类之间的取余运算%
  • __pow__(self,other[,module])):类与类之间的指数运算**
  • __and__(self,other):类与类之间的按位与运算&
  • __xor__(self,other):类与类之间的按位异或运算^
  • __or__(self,other):类与类之间的按位或运算|
  • __lt__(self,other):定义了比较操作符<
  • __gt__(self,other):定义了比较操作符>
  • __le__(self,other):定义了比较操作符<=
  • __eq__(self,other):定义了比较操作符==
  • __ne__(self,other):定义了比较操作符!=
  • __setitem__(self, key, value):使用self[nkey] = value赋值容器中的一项
  • __delitem__(self, key):删除self[nkey]
5.1 加减乘除
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Point(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Point(self.x * scalar, self.y * scalar)
    
    def __truediv__(self, scalar):
        return Point(self.x / scalar, self.y / scalar)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
 
p1 = Point(1, 2)
p2 = Point(3, 4)
 
# 加法操作
p3 = p1 + p2
print(p3.x, p3.y) 
# 输出: 4, 6
 
# 减法操作
p4 = p1 - p2
print(p4.x, p4.y) 
# 输出: -2, -2
 
# 乘法操作
p5 = p1 * 2
print(p5.x, p5.y) 
# 输出: 2, 4
 
# 除法操作
p6 = p1 / 2
print(p6.x, p6.y) 
# 输出: 0.5, 1.0
 
# 等值比较操作
print(p1 == p2) 
# 输出: False
print(p1 == Point(1, 2)) 
# 输出: True
5.2 比较运算
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def __lt__(self, other):
        return self.age < other.age
 
    def __eq__(self, other):
        return self.age == other.age
 
p1 = Person("Alice", 25)
p2 = Person("Bob", 30)
p3 = Person("Charlie", 25)
print(p1 < p2)  
# 输出: True
print(p1 == p3)  
# 输出: True

6 赋值运算符魔术方法

  • iadd(self, other):定义赋值加法的行为:+=
  • isub(self, other):定义赋值减法的行为:-=
  • imul(self, other):定义赋值乘法的行为:*=
  • itruediv(self, other):定义赋值真除法的行为:/=
  • ifloordiv(self, other):定义赋值整数除法的行为://=
  • imod(self, other):定义赋值取模算法的行为:%=
  • ipow(self, other[, modulo]):定义赋值幂运算的行为:**=
  • ilshift(self, other):定义赋值按位左移位的行为:<<=
  • irshift(self, other):定义赋值按位右移位的行为:>>=
  • iand(self, other):定义赋值按位与操作的行为:&=
  • ior(self, other):定义赋值按位或操作的行为:|=
  • ixor(self, other):定义赋值按位异或操作的行为:^=

7 容器相关魔术方法

  • __len__(self) :定义当被 len() 调用时的行为(返回容器中元素的个数)
  • __getitem__(self, key): 定义获取容器中指定元素的行为,相当于 self[key]
  • __setitem__(self, key, value): 定义设置容器中指定元素的行为,相当于 self[key] = value
  • __delitem__(self, key) :定义删除容器中指定元素的行为,相当于 del self[key]
  • __iter__(self) :定义当迭代容器中的元素的行为
  • __next__(self):从iterable对象中获取下一个元素
  • __reversed__(self): 定义当被 reversed() 调用时的行为
  • __contains__(self, item): 定义当使用成员测试运算符(in 或 not in)时的行为
  • __missing__字典使用__getitem__()调用时,key不存在执行该方法
7.1 getitem__和__setitem
class MyList:
    def __init__(self, items):
        self.items = items

    def __getitem__(self, index):
        return self.items[index]

    def __setitem__(self, index, value):
        self.items[index] = value

l = MyList([1, 2, 3, 4])
print(l[2])  
# 3
l[2] = 5
print(l[2]) 
# 5

7.2 contains
class MyList:
    def __init__(self, items):
        self.items = items
 
    def __contains__(self, item):
        return item in self.items
 
l = MyList([1, 2, 3, 4])
print(2 in l) 
# True
print(5 in l)  
# False

7.2 iter__和__next_

迭代器

class MyIterator:
    def __init__(self, start, end):
        self.start = start
        self.end = end
 
    def __iter__(self):
        return self
 
    def __next__(self):
        if self.start >= self.end:
            raise StopIteration
        value = self.start
        self.start += 1
        return value
 
iterator = MyIterator(0, 5)
for iter in iterator:
    print(iter)  
    
# 0 
# 1
# 2
# 3
# 4

8 魔法属性

8.1 doc

获取类或对象内部文档

class MyClass():
    """
    自定义一个类,这里写了一些说明
    """
 
    def __init__(self):
        pass
 
 
print(MyClass.__doc__)
# 自定义一个类,这里写了一些说明

8.2 name

获取类名或函数名

class Foo:
    pass

class MyClass:
    def task(self, func):
        print(func.__name__)
 
 
def func():
    print("我是func1函数")


obj = MyClass()
obj.task(Foo)
# Foo
obj.task(func)
# func
8.3 class

获取当前对象获取的类

class Foo:
    pass
 
 
obj = Foo()
print(obj.__class__)
# <class '__main__.Foo'>
print(obj.__class__.__name__)
# Foo
8.4 base

获取一个类直接继承的所有父类,返回元组

class Foo:
    pass
 
 
class Boo:
    pass
 
 
class MyClass(Foo, Boo):
    pass

print(MyClass.__bases__)

# (<class '__main__.Foo'>, <class '__main__.Boo'>)
8.5 dict

获取类或对象的的内部成员结构
主要用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典

class MyClass:
    name = "zhangsan"
    age = 18
 
    def one(self):
        print("one")
 
    def two(self):
        print("two")
 
 
print(MyClass.__dict__)
# {'__module__': '__main__', 'name': 'zhangsan', 'age': 18, 'one': <function MyClass.one at 0x000001D07AD54AF0>, 'two': <function MyClass.two at 0x000001D07AD54B80>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

?? 欢迎我的关注公众号

在这里插入图片描述