3-魔法方法
0x-wen

4.魔法函数

4.1 __new____init____call ____del__

__new__ 实例化对象(1.创建对象 2.分配内存)
__init__ 构造方法,实例化对象时自动调用(1.可以没有 2.如果有方法必须返回None,默认不写return语句)
__call __ 对象可以被调用时触发执行
__del__ 析构方法,当对象被回收时触发执行(程序结束、对象引用计数为零称为垃圾时)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyClass(object):

def __init__(self):
print("__init__ is running...")

def __new__(cls):
print("__new__ is running...")
return super().__new__(cls) # 创建对象 分配内存

def __call__(self, *args, **kwargs):
print("__call__ is running...")

def __del__(self):
print("__del__ is running...")


MyClass() # 匿名对象程序并未使用到,执行完后就销毁了
print("----------------------")

a = MyClass() # 这里会先执行__new__ 在执行 __init__
assert hasattr(a, "__del__") # True
print(callable(a)) # True 可以被调用时结果为True,对象如果没有__call__ 属性则是False
assert hasattr(lambda x, y: x + y, "__call__") # True
print(callable(lambda x, y: x + y)) # True

4.2 __str____repr__

两个方法都只是为了自定义对象的打印信息

对象被打印时执行,一般默认先找str, str没有则使用repr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A(object):

def __init__(self):
self.name = "李四"

def __str__(self):
print("__str__ is running ...")
return "str"

def __repr__(self):
print("__repr__ is running ...")
return ""


print(A()) # 默认为 <__main__.A object at 0x1043aa710>

4.3 compare系列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student:
def __init__(self, age):
self.age = age

def __eq__(self, other):
print("__eq__ is running ... 可自定义比较逻辑")
if isinstance(other, Student):
return self.age == other.age # 返回布尔值
return False


print(Student(18) == Student(18))
print(Student(18) != 18) # nq, 不相等的逻辑。如果没有实现,则默认是eq的结果取反。
print(dir(Student(18))) # __lt__、__gt__、__le__、__ge__ 分别表示小于、大于、小于等于和大于等于。

4.4 attr系列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class MyClass(object):

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

def __getattr__(self, item):
print("getattr 获取不存在的对象属性时触发")
# super().__delattr__(item) # 'MyClass' object has no attribute 'id'
return self.__dict__.get(item)

def __setattr__(self, key, value):
print("setattr 设置修改对象属性时触发")
super().__setattr__(key, value)

def __delattr__(self, item):
print("delattr 删除对象属性时触发")
if item == "name": # 属性是name时抛出异常,或者不进行删除操作
# raise AttributeError("name 属性不让删除...")
pass
else:
super().__delattr__(item)

def __getattribute__(self, name):
# 访问任何属性(包括存在的和不存在的属性)时都会调用 __getattribute__ 方法
print("__getattribute__ called")
return super().__getattribute__(name)


a = MyClass("李四", 18) # 每一次给属性赋值 都会执行setattr方法
print(a.id)
del a.age # 触发delattr方法
print(f"查看对象属性:{a.__dict__}")

4.5 item系列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 一个普通对象通过[] 操作取值时会触发 __getitem__
class Person(object):

def __setitem__(self, key, value):
print("setitem []设置值时触发")
setattr(self, key, value)

def __getitem__(self, item):
print("getitem []取值时触发")
return getattr(self, item)

def __delitem__(self, key):
print("delitem del p[key]时触发", key)


p = Person()
p['id'] = 1 # 触发setitem方法
print(p['id']) # 触发getitem方法
del p['id'] # 触发delitem方法

4.6 __enter____exit__

上下文管理器: 支持”上下文管理协议”的对象,包含 enter() 和 exit() 方法
with 可以操作一个 支持上下文管理协议的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyOpen:
def __init__(self, file_name: str, mode="r"):
self.file = open(file_name, mode)

def __enter__(self):
print("进入with语句块时触发")
return self.file # 返回值赋值给 as后面的接收值

def __exit__(self, exc_type, exc_val, exc_tb):
print("退出with语句块时触发,不论with语句块是否有异常报错,__exit__都会被执行")
self.file.close()


with MyOpen("test", "w") as f:
f.write("hello world")

4.7 __slots__

该类实例只能创建__slots__中声明的属性,否则报错, 具体作用就是节省内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from memory_profiler import profile


class Test(object):
__slots__ = ['a', 'name']

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


Test.c = 3 # 类属性仍然可以自由添加
t = Test("xx")
t.a = 1
print(t.c) # 绕过限制就是给类添加属性
# t.b = 2 # AttributeError: 'Test' object has no attribute 'b'


class TestA(object):
__slots__ = ['a', 'b', 'c']

def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c


class TestB(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c


@profile
def func_02():
temp = [TestA(i, i + 1, i + 2) for i in range(10000)]
del temp
temp = [TestB(i, i + 1, i + 2) for i in range(10000)]
del temp


func_02()

4.8 __add____dict____bases____all__

__add__: 手动实现相加操作
__dict__: 获取对象的属性
__bases__: 获取类继承的元素
__all__: 当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyClass(object):

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

def __add__(self, other):
# other这里传入的是第二个对象 obj2 obj2.value ==》 __init__ 初始化中传入的value
return self.value + other.value


a = MyClass(10)
print(a + MyClass(20))
print(MyClass.__dict__)


# __bases__ 这是一个元祖,里面的元素是继承的类
class A(object):
pass


print(A.__bases__)

# 当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 `__all__` 列表中指定的成员
__all__ = ["MyClass"]
由 Hexo 驱动 & 主题 Keep
总字数 42.8k