Python魔术方法
2021-11-30 学习内容整理
魔术方法:
- 以两个下划线开头、两个下划线结尾的方法,常见的如
__init__ ; - 魔术方法会在类或对象的某些事件发生后自动执行,如果希望在这些事件节点定制化一些特殊功能,可以对这些方法进行重写;
python中常见的魔术方法:
- 构造与初始化
- 类的表示
- 访问控制
- 比较操作
- 容器类操作
- 可调用对象
- 序列化
构造与初始化
__init__ 方法可以定义一个对象的初始化操作;实际在实例化一个类的时候,还有一个__new__ 的方法会被调用;在对象生命周期的另一端,还有一个__del__ 方法;
__new__
__new__(cls,[...])
- 是在一个对象实例化的时候所调用的第一个方法,它才是真正意义上的构造方法;
- 第一个参数是类对象,其他参数会直接传递给
__init__ 方法; __new__ 方法还决定了是否使用该__init__ 方法,因为__new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例;- 如果
__new__ 方法没有返回实例对象,则__init__ 方法不会被调用;
class Person(object):
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("A",16)
使用场景:
- 需要继承内置类时,比如int str tuple,只能通过
__new__ 来初始化数据;
class float_g(float):
def __new__(cls, kg):
return float.__new__(cls, kg*1000)
a = float_g(50)
__init__
__init__ 构造器,当一个实例被创建的时候调用的初始化方法;
__del__()
__del__() 析构器,当一个实例被销毁时自动调用的方法;
class Washer:
def __del__(self):
print('deleted')
类的表示
__str__() / __repr__() __bool__()
__str__() / __repr__()
这两个方法都是用来描述类或对象信息的,如果直接打印一个对象,正常输出的是对象的地址;重新定义类中的这两个方法,打印出来的结果就是方法的返回信息;
class Washer:
def __repr__(self):
return "repr"
def __str__(self):
return "str"
区别在于:
__repr__ 的目标是准确性,其结果是让解释器用的;__str__ 的目标是可读性,是对类或对象状态的说明,是给人看的,print会优先使用这个方法的返回值;
__bool__()
当调用bool(obj) 时,会调用__bool__() 方法,返回True或False;
class Person(object):
def __init__(self, uid):
self.uid = uid
def __bool__(self):
return self.uid > 10
bool(Person(4))
访问控制
__setattr__ :定义一个属性被设置时的行为;__getattr__ :定义当用户试图获取一个不存在的属性时的行为;__delattr__ :删除某个属性是调用;__getattribute__ :访问任意属性或方法时调用;
class Person(object):
def __setattr__(self, key, value):
"""属性赋值"""
if key not in ('name', 'age'):
return
if key == 'age' and value < 0:
raise ValueError()
super(Person, self).__setattr__(key, value)
def __getattr__(self, key):
"""访问某个不存在的属性"""
return 'unknown'
def __delattr__(self, key):
"""删除某个属性"""
if key == 'name':
raise AttributeError()
super().__delattr__(key)
def __getattribute__(self, key):
"""所有属性/方法调用都经过这里"""
print('...')
if key == 'money':
return 100
elif key == 'hello':
return self.say
return super().__getattribute__(key)
p1 = Person()
p1.name = '张三'
p1.age = 20
print(p1.name, p1.age)
setattr(p1, 'name', '李四')
setattr(p1, 'age', 30)
print(p1.name, p1.age)
print(p1.sex)
print(p1.hello)
...
...
张三 20
...
...
李四 30
...
unknown
...
...
unknown
比较操作
__eq__() __ne__() __lt__() __gt__()
__eq__()
__eq__() 方法,用于判断两个对象是否相等;
class Person(object):
def __init__(self, uid):
self.uid = uid
def __eq__(self, other):
return self.uid == other.uid
p1 = Person(1)
p2 = Person(2)
p3 = Person(1)
p1 == p2
p1 == p3
__ne__()
判断两个对象是否不相等,用法和__eq__() 一致;
def __ne__(self, other):
return self.uid != other.uid
__lt__() & __gt__()
__lt__() 小于;__gt__() 大于;
class Person(object):
def __init__(self, uid):
self.uid = uid
def __lt__(self, other):
return self.uid < other.uid
def __gt__(self, other):
return self.uid > other.uid
容器类操作
常用的容器类型:字典 元组 列表 字符串,它们都可迭代(实现了容器协议)
__setitem__(self, key, value)
- 设置容器元素,相当于
self[key] = value __getitem__(self, key)
__delitem__(self, key)
__len__(self)
__iter__(self)
__contains__(self, item)
- 定义使用成员测试运算符
in 或not in 时的行为; __reversed__(self)
class MyList(object):
def __init__(self, values=None):
self.values = values or []
self._index = 0
def __setitem__(self, key, value):
self.values[key] = value
def __getitem__(self, key):
return self.values[key]
def __delitem__(self, key):
del self.values[key]
def __len__(self):
return len(self.values)
def __iter__(self):
return self
def __next__(self):
if self._index >= len(self.values):
raise StopIteration()
value = self.values[self._index]
self._index += 1
return value
def __contains__(self, item):
return item in self.values
def __reversed__(self):
return MyList(list(reversed(self.values)))
__iter__ 方法的返回值有两种:
- 返回
iter(obj) :代表使用obj对象的迭代协议,一般是obj是内置的容器对象; - 返回
self ,代表迭代的逻辑由本类实现,此时需要重写next方法,实现自定义的迭代逻辑;
可调用对象
Python中有一个特殊的方法可以让类的实例的行为表现的像函数一样,即__call__(self,[args...]) ;
class Circle(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __call__(self, x, y):
self.x = x
self.y = y
a = Circle(10,20)
a.x,a.y
a(100,200)
a.x,a.y
通过__call__ 方法,python中的实例,也可以被调用;
这个方法通常会用在装饰器、元类编程场景;
序列化
Python中的序列化模块是pickle,当使用这个模块序列化一个实例对象时,可以通过__getstate__() 和__setstate__() 方法实现自己的逻辑;
import pickle
class Person(object):
def __init__(self, name, age, birthday):
self.name = name
self.age = age
self.birthday = birthday
def __getstate__(self):
return {
'name': self.name,
'birthday':self.birthday
}
def __setstate__(self, state):
self.name = state['name']
self.birthday = state['birthday']
person = Person('aa', 20 , (2017,2,23))
p_person = pickle.dumps(person)
n_person = pickle.loads(p_person)
使用pickle序列化对象时,要仔细些,避免一些可能的坑
|