1.使用__slots__:主要是节省内存,其次可以限制定义
我们可以给一个实例绑定一个属性:
直接写:实例名.属性名 = 数据 ,给实例绑定的属性只能在该实例中使用
我们也可以给实例添加一个方法:
例:
>>> class Student():
"""定义一个学生的类"""
def __init__(self,name,age):
self.name = name
self.age = age
>>> from types import MethodType # 导入模块
>>> s = Student('Bob',18)
>>> s.name
'Bob'
>>> s.age
18
>>> # 定义一个函数作为实例方法
>>> def score_show(self,score):
self.score = str(score)
print('%s' % self.score)
>>> s.score_show = MethodType(score_show,s)
>>> s.score_show(98)
98
但要注意的是给实例绑定的方法,只能用在该实例中
要想在所有实例中都能使用,需要绑定在类上
Student.score_show = MethodType(score_show,Student)
如果我们要限制绑定的实例,只允许绑定特定的实例可以使用__slots__:
>>> # 限制绑定的属性
>>> class Std():
"""定义一个学生的类"""
__slots__ = ('name','age')
def __init__(self,name,age):
self.name = name
self.age = age
>>> s = Std('bob',19)
>>> s.score = 98 # 当想要绑定我们定义之外的属性时就会报错
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
s.score = 98
AttributeError: 'Std' object has no attribute 'score'
>>> class Std1():
def __init__(self,name,age):
self.name = name
self.age = age
>>> st2 = Std1('Bob',19)
NameError: name 'std2' is not defined
>>> st2.score = 98
>>> st2.score
98
但需要注意,定义的限制属性只在当前类中起作用,在继承它的子类中不起作用
除非在子类中也定义了__slots__,那么子类将包含父类中的限制和本身定义的
3.__module__:查看这个类来自哪个模块
from m1 import t
c = t.C()
print(c.__module__) #m1.t
4.__del__:析构方法,高级语言不需要考虑内存的使用与释放,当内存被释放时,会触发该方法
5.__del__:内存被释放时会触发
class User:
def __init__(self,name):
self.name = name
def __del__(self):
print("我执行啦")
s1 = User("alxe")
# del s1.name # --------->
# print("--------->") #我执行啦
del s1 #我执行啦 # 只有删除实例时才会触发,
# 上面也触发是因为程序结束了,内存也被回收了
print("------------->") #------------->
6.数据描述符:本质上是一个类,用来在其他类的类属性中调用,来描述类属性,之后类属性的操作都有这个描述符来管理
注意事项:
1.描述符本身应定义成新式类,被代理的类也应该是新式类
2.必须把描述符定义成这个类的类属性,不能定义到构造函数中
3.必须严格遵循优先级
# 描述符的优先级
"""
类属性>数据描述符(至少有__get__和__set__)>实例属性>非数据描述符(只有__get__方法)>__getattr__
"""
class Foo:
"""这就是定义了一个描述符"""
def __get__(self, instance, owner):
print("====>__get__")
def __set__(self, instance, value):
print("====>__set__")
def __delete__(self, instance):
print("====>__delete__")
class Date:
x = Foo() # 描述符必须定义在另一个类里面,被描述的属性调用、设置、删除都只会触发描述符中的定义的方法
b = Date()
b.x # ====>__get__
b.x = 1 # ====>__set__
del b.x #====>__delete__
7.__enter__和__exit__:上下文管理协议
with open("文件名") as f:
"代码块"
这个操作会将文件加载到内存,并自动回收,就是用上下文管理协议实现的
举例:
class Open:
def __init__(self,name):
self.name = name
def __enter__(self):
print("====>enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("====>exit")
print(exc_type) #<class 'NameError'>
print(exc_val) #name 'skdvuhsod' is not defined
print(exc_tb) #<traceback object at 0x00000273E0BAED48>
return True
# with Open("a.txt") as f:
# print("........")
"""
====>enter
........
====>exit
"""
# 当文件操作中出现异常
with Open("a.txt") as f:
print("------------")
print(skdvuhsod)
"""
一个异常就由这三部分组成,异常类、异常值和追踪信息
<class 'NameError'>
name 'skdvuhsod' is not defined
<traceback object at 0x00000273E0BAED48>
"""
print("-----------") # 当出现异常后,会直接触发__exit__,之后的语句都不会执行
print("34134141")
print("aadsdas") # 文件操作代码块出现异常时,当__exit__返回True时,异常会被吞掉,程序会继续执行,
"""
====>enter
------------
====>exit
<class 'NameError'>
name 'skdvuhsod' is not defined
<traceback object at 0x000002311AA6ED48>
aadsdas # __exit__返回True,回收文件,程序继续执行
"""
8.元类:既然类是一个对象,那么就也有产生类的类,就是元类(type)
# metaclass:元类就是类的类
# class Foo:
# pass
# s = Foo()
# print(type(s)) #<class '__main__.Foo'>
# print(type(Foo)) #<class 'type'> type就是元类,我们定义的类都是由它生成的
# 那么我们就可以用type生成一个类
# def __init__(self,name,age):
# self.name = name
# self.age = age
# Foo = type("Foo",(object,),{"__init__":__init__}) # 三个参数,类名、继承的类,属性
# f1 = Foo('alxe',10)
# print(f1.__dict__) #{'name': 'alxe', 'age': 10}
# 下面我们来自定制一个元类
class Mytype(type):
def __init__(self,a,b,c):
pass
#self:【<class '__main__.Foo'>】a:【Foo】,b:【()】c:【{'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x000002C42459DBF8>}】
def __call__(self, *args, **kwargs):
#print(args,kwargs) #('alxe',) {}
obj = object.__new__(self) # self就是Foo,这里使用Foo创建一个对象
self.__init__(obj,*args,**kwargs) # 调用Foo的__init__,为生成的对象添加数据属性
return obj
class Foo(metaclass=Mytype): #"metclass=":声明元类
def __init__(self,name):
self.name = name
f = Foo('alxe') #执行类名()就会触发元类的__call__
f1 = Foo("python")
print(f.name)
print(f.__dict__)
print("=============")
print(f1.name)
print(f1.__dict__)