内容简介
这篇文章还是围绕类属性和魔法方法及装饰器进行展开学习的。
涉及的类属性:
__slots__
其值为类初始化时用到的参数名列表或元组,主要用于设置(关闭或者限制)类的动态绑定属性,一旦设置了该属性,则类实例化之后,不可再 动态添加其他没有在该属性中声明的变量。
魔法方法
__new__ # 注意:在类实例化时,该方法比__init__先执行,并且必须返回类(return super().__new__(cls))
__enter__
__exit__
__lt__
__eq__
__gt__
__getattr__
__getattribute__
__get__
__set__
__delete__
装饰器
from functools import total_ordering
import contextlib
@total_ordering
class compare():
def __init__(self, a):
pass
@contextlib.contextmanager
def file_open(file):
pass
with上下文
对于一个类或者方法,要想支持with语句,需要在类中实现魔法方法:
__enter__
__exit__
代码实例:
class Sample(object):
def __init__(self):
print('init')
def __enter__(self):
print('start')
return self # 注意:必须返回self 给后面的程序调用
def demo(self):
print('this is demo')
def __exit__(self, exc_type, exc_val, exc_tb):
# 异常类
print(exc_type, '1')
# 异常值
print(exc_val, '2')
# traceback
print(exc_tb, '3')
print('end')
with Sample() as sample:
sample.demo()
也可以使用上下文装饰器简化上述过程。
import contextlib
@contextlib.contextmanager
def demo():
print('this is demo')
yield '' # 必须为迭代器 或者 生成器
print('end')
with demo() as sample:
print('ok')
类实例动态绑定变量
就是在类 实例化之后,对实例进行任意属性的绑定,例如:
import sys
class x():
def __init__(self):
print('123')
>>> aa=x()
123
>>> sys.getsizeof(aa) # 查看实例 aa 所占内存大小
56
>>> aa.xx=12345 # 任意绑定属性名xx,属性值12345
>>> print(aa.xx)
12345
>>> sys.getsizeof(aa.xx) # 查看新增属性xx所占内存大小
28
为了避免动态绑定属性带来的内存浪费,需要引入类属性:“__slots__”
import sys
class x():
__slots__ = ["id"]
def __init__(self, id):
print('123')
print(id)
aa = x('user1')
>>> aa.s=1 # 设置 __slots__ 之外的属性时,报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'x' object has no attribute 's'
>>> aa.id=1
>>> print(aa.id)
1
类实例的比较
对于一个类实例,如果要想支持大小比较:
<, =, > ,>= ,<=
则需要分别实现魔法方法
__lt__
__eq__
__gt__
__ge__
__le__
但是也可以借助装饰器简化,只需实现 其中的两个:
__eq__ 和 __lt__ 或者 __eq__ 和 __gt__
代码实现:
from functools import total_ordering
@total_ordering
class cmpares():
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
def __lt__(self, other):
return self.value < other.value
a = cmpares(12)
b = cmpares(6)
>>> print(a > b)
True
>>> print(a == b)
False
>>> print(a < b)
False
>>> print(a <= b)
False
>>> print(a >= b)
True
实例属性查找
此处涉及的魔法方法为:
__getattr__
__getattribute__
其中 __getattribute__的优先级比 __getattr__高,所以前者先执行,当调用实例的属性不存在时,后者会被调用。
代码实例:
class xx():
def __init__(self, name, age, attrs = {}):
self.name = name
self.age = age
self.attrs = attrs
def __getattr__(self,item):
return self.attrs.get(item, 'not exists.')
a=xx('li',9)
print(a.b) # 属性不存在,返回 'not exists.'
属性描述符
涉及的方法:
__get__
__set__
__delete__
上述方法主要使属性的获取和设置便于批量操作,适用于数据描述符(至少实现前两个方法)和非数据描述符(只实现__get__方法)。
代码实例:
class Inld(object):
def __get__(self, instance, owner):
print('get')
return self.values
def __set__(self, instance, value):
print('set')
self.values = value
def __delete__(self, instance):
pass
class ts:
age = Inld() #类属性
a = ts()
a.age = 88
print(a.age)
属性查找顺序(优先级依次降低):
数据描述符 > 实例__dict__ > 类(基类)__dict__ ( 非数据描述符 > __dict__)
type创建类
type不只是用于查看对象类型,还可以动态创建类。
def get_age(self):
print(111)
User = type("User", (), {'name': 'test111', 'method1': get_age})
user = User()
print(user)
print(user.name)
user.method1()