Python24_魔法方法
2019-09-27 本文已影响0人
jxvl假装
- __slot__
- 使用
__slot__
后,不能再动态添加属性 - 使用
__slot__
后,每个子类都需要定义__slot__
属性,这个属性不会被继承
# 对于一个对象
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
s = Student("张3",23)
print(s.__dict__)
#这种内存利用率低
#使用__slot__
class Student:
__slots__ = ("name", "age") #规定了以后只能有这两个属性,以元组方式
def __init__(self, name, age):
self.name = name
self.age = age
s = Student("zhang3",23)
print(s.name)
print(s.age)
print(s.__dict__) #报错,提示没有这个属性
-** __contains__**
判断该类是否包含某个属性
- __eq__
判断两个对象是否相等,可以自己重写
描述符
是一个类,定义了访问另一个类属性的方式。
实现了__get__()
和__set__()
的描述符称为数据描述符。
只实现了__get__()
的描述符称为非数据描述符。
访问对象属性的时候:obj.attr,一般会先调用__getattribut__()
方法,查找的顺序如下:
- 数据描述符
-
__dict__
属性 - 非数据描述符
class RevealAccess:
def __init__(self, initval = None, name = "var"):
self.val = initval
self.name = name
def __get__(self, instance, owner):
print("获取...", self.name)
return self.val
#注意有set和无set时的区别
def __set__(self, instance, value):
print("设置值...",self.name)
self.val = value
class MyClass:
x = RevealAccess(10,"var_x")
y = 5
def __init__(self):
pass
m = MyClass()
print(m.x)
m.x = "hello world"
print(m.x)
# 输出如下:
# 获取... var_x
# 10
# 设置值... var_x
# 获取... var_x
# hello world
# 延迟加载:即需要用到的时候再加载,可以减小不必要的资源占用
class InitOnAccess:
def __init__(self, klass, *args, **kwargs):
self.klass = klass
self.args = args
self.kwargs = kwargs
self._initialized = None
def __get__(self, instance, owner):
if self._initialized is None:
print("_initialized is None")
self._initialized = self.klass(*self.args,**self.kwargs)
else:
print("cached")
return self._initialized
#ps:是一个非数据描述符,因为没有实现set方法
class TestClass:
laze_initialized = InitOnAccess(list,"arguments")
t = TestClass()
t.laze_initialized
t.laze_initialized
#输出
# _initialized is None
# cached
-__getattr__
查找不存在的属性时调用
-__getattribute__
查找属性时调用,如果发现不存在,再调用getattr
-** __setattr__
**
设置属性时调用
-** __delattr__
**
删除属性时调用
class Cache:
_cache = dict()
# def __init__(self):
# self._cache = dict()
def __setattr__(self,key, value):
if not Cache._cache.keys().__contains__(key):
Cache._cache[key] = []
Cache._cache[key].append(value)
def __getattr__(self, item):
if not Cache._cache.keys().__contains__(item):
return None
return Cache._cache[item]
c = Cache()
c.user = "zhang3"
c.user = "li4"
print(c.user)
- __call__
如果一个类重写了call方法,则在实例中可以通过对象名()
对该方法进行调用
class Test:
def __call__(self):
print("hello wold")
t = Test()
t()
__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
即:可以把对象当字典用
复习:当类中实现了__iter__
方法和__next__
方法,就是一个迭代器,可以用于for循环
class Foo:
def __init__(self, name, age):
self.info = {"name": name, "age": age}
def __getitem__(self, item):
return self.info[item]
def __setitem__(self, key, value):
self.info[key] = value
def __delitem__(self, key):
del self.info[key]
obj = Foo("zhagn3",23)
print(obj["name"])
obj["height"] = 174
print(obj["height"])
del obj["age"]
print(obj["age"]) # 报错
'''输出结果如下:
zhagn3
174
'''