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):
# 返回对象 其他参数会传给__init__方法
return object.__new__(cls)
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("A",16)
使用场景:
__new__
来初始化数据;class float_g(float):
def __new__(cls, kg):
return float.__new__(cls, kg*1000)
a = float_g(50) # 50kg 转 g,由于继承了float,所以可以直接运算
__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)) # False
__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 = '张三' # 调用__setattr__
p1.age = 20 # 调用__setattr__
print(p1.name, p1.age) # 张三 20
setattr(p1, 'name', '李四') # 调用__setattr__
setattr(p1, 'age', 30) # 调用__setattr__
print(p1.name, p1.age) # 李四 30
print(p1.sex) # 调用__getattr__
print(p1.hello)
# 上面只要是访问属性的地方,都会调用__getattribute__方法
...
...
张三 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 # False
p1 == p3 # True
__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)
self[key]
__delitem__(self, key)
del self[key]
__len__(self)
len()
调用时,返回容器元素的个数;__iter__(self)
__contains__(self, item)
in
或not in
时的行为;__reversed__(self)
reversed()
调用时的行为;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):
# __iter__返回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 # 10 20
a(100,200)
a.x,a.y # 100 200
通过__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):
# 执行 pick.dumps时 忽略age属性
return {
'name': self.name,
'birthday':self.birthday
}
def __setstate__(self, state):
# 执行 pick.loads时 忽略age属性
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序列化对象时,要仔细些,避免一些可能的坑