Python 的类里提供的,两个下划线开始,两个下划线结束的方法,就是魔法方法,魔法方法在恰当的时候就会被激活,自动执行。

一、__new__()方法

类名() 创建对象时,在自动执行 __init__()方法前,会先执行 object.__new__方法,在内存中开辟对象空间并返回;

如果Person类中没有__new__()方法,会执行父类object中的__new__()方法;

class Person():
    def __init__(self, name):
        self.name = name
        print('执行init方法...')

    def __new__(cls, *args, **kwargs):
        print('执行new方法...')
        # pass # 此时返回的是None
        return object.__new__(cls)


yuan = Person('sxm')
print(yuan)
print(yuan.name)

通过重写__new__()方法实现类的单例模式:

# 单例模式
class Person():
    mem = None
    def __new__(cls, *args, **kwargs):
        print('new方法...')
        if not cls.mem:
            cls.mem = object.__new__(cls)
        return cls.mem


p1 = Person()
p2 = Person()
print(p1 == p2)

二、__str__()方法

改变对象的字符串显示。可以理解为使用print函数打印一个对象时,会自动调用对象的__str__方法;

# __str__方法
class Person(object):

    def __init__(self, name, age):
        print("__init__方法执行")
        self.name = name
        self.age = age

    def __str__(self):
        # return object.__str__(self)    # 返回实例对象的内存地址
        return self.age    #必须要返回字符串,返回非字符串时,会报错
        # return self.name


yuan1 = Person("yuan", 23)
print(yuan1)

三、__repr__()方法

如下是在python终端命令中的执行效果:

>>> class Person():
...     def __init__(self.name,age):
  File "<stdin>", line 2
    def __init__(self.name,age):
                     ^
SyntaxError: invalid syntax
>>> class Person():
...     def __init__(self,name,age):
...             print('init...')
...             self.name=name
...             self.age=age
...     def __str__(self):
...             return self.name+self.name
...     def __repr__(self):
...             return self.name
...
>>> yuan1 = Person('sxm',12)
init...
>>> yuan2 = Person('sjj',13)
init...
>>> print(yuan1)        #执行的是__str__()方法
sxmsxm
>>> yuan1                # 执行的是__repr__()方法
sxm
>>> print(yuan2)
sjjsjj
>>> yuan2
sjj

问:__str__()方法与__repr__()方法的区别

1.在python终端命令下执行print(instance)等同于执行__str__()方法;str返回的结果可读性更强
2.在python终端命令下输入实例对象名并执行等同于__repr__()方法;repr目的在于调试,便于开发使用;

# 案例二
>>> import datetime
>>> now = datetime.datetime.now()
>>> print(now)
2022-02-10 16:23:04.661556
>>> now
datetime.datetime(2022, 2, 10, 16, 23, 4, 661556)

# 案例三
>>> s = 'hello'
>>> s
'hello'
>>> print(s)
hello

四、__del__()方法

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

# __del__()方法
class Person(object):
    def __init__(self, name, age):
        print("__init__方法执行")
        self.name = name
        self.age = age


    def __del__(self):
        print('del方法,删除%s' % self.name)

sxm1 = Person('ss',13)
sxm2 = Person('xx',14)
print('111')
# del sxm1                  # 程序执行结束时,垃圾回收机制会自动触发del命令删除实例对象;所以该行注释掉时,也会执行del sxm1
# del sxm2
# 案例二
class A():
    def open(self):
        self.f = open('a.txt','w')

    def __del__(self):
        print('文件关闭')
        self.f.close()

a = A()
a.open()

五、__eq__()方法

拥有__eq__方法的对象支持相等的比较操作

# __eq__()方法
class Person(object):

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

    def __eq__(self, obj):
        print('eq方法...')
        print(self.name)
        print(obj.name)
        return self.name == obj.name
        # return object.__eq__(self, obj)


yuan = Person("yuan", 23)
alvin = Person("alvin", 23)
print(yuan == alvin)

六、__len__()方法

# __len__()方法
class G(object):
    def __len__(self):
        print('len...')
        return 100

g=G()
print(len(g))   # 执行的是__len__()方法


# 案例二
l  = [1,2,3,4,5]
print(len(l))   # 等同于l.__len__()

七、item系列

# item系列
class Person():
    def __init__(self, name, age):
        print('init...')
        self.name = name
        self.age = age

    def __getitem__(self, item):
        print('getitem...')
        return self.__dict__.get(item)

    def __setitem__(self, key, value):
        print('setitem...')
        print(key)
        print(value)
        self.__dict__[key] = value

    def __delitem__(self, key):
        print('delitem...')
        self.__dict__.pop(key)


p1 = Person('sxm',13)
# print(p1.name)                           # 句点表示法
print(p1['name'])                          # 取值操作:执行的是__getitem__()方法
p1['gender'] = 'famale'                    # 赋值操作:执行的是__setitem__()方法
print(p1['gender'])
del p1['gender']                           # 删除操作:执行的是__delitem__()方法

print(p1.__dict__)      # 以dict格式返回实例对象的属性和属性值
print(dir(p1))          # 以list格式返回实例对象的所有属性名,包含许多魔法方法属性

八、attr系列 

# attr系列
class Person(object):

    def __init__(self, name, age):
        print('init...')
        self.name = name         # 执行的是__setattr__()方法
        self.age = age

    def __getattr__(self, item):
        print('getattr...')

    def __setattr__(self, key, value):
        print('setattr...')
        print(key)
        print(value)
        self.__dict__[key] = value

    def __delattr__(self, item):
        print('delattr...')
        self.__dict__.pop(item)


p1 = Person('sxm', 14)
# print(p1.name)
# print(p1.xxx)                         # 句点表示法:取值操作,执行的是__getattr__()方法;获取不存在的属性时执行的是Person类中重写的__getattr__()方法
p1.gender = 'male'                    # 句点表示法:复制操作:执行的是__setattr__()方法;
# print(p1.gender)

del p1.gender                         # 句点表示法;删除操作;执行的是__delattr__()方法
print(p1.__dict__)