元类及迭代器生成器
01.__getattr__和__getattribute__魔法函数
- __getattr__是当类调用一个不存在的属性时才会调用getattr魔法函数,他传入的值item就是你这个调用的不存在的值。访问的属性不存在,自动触发这个魔术方法。
- getattribute__则是无条件的优先执行,所以如果不是特殊情况最好不要用__getattribute。
02.属性描述符
属性描述符是实现了特定协议的类,只要实现了__get__,__set__和__delete__三个方法中的任意一个,这个类就是描述符,它能实现对多个属性运用相同存取逻辑的一种方式,通俗来说就是:创建一个实例,作为另一个类的类属性。
除了使用类当作一个属性描述符,我们之前学习的 property(),就是可以轻松地为任意属性创建可用的描述符。创建 property() 的语法是 property(fget=None, fset=None, fdel=None, doc=None)
描述符查找顺序
• 当为数据描述符时, get__优先级高于__dict
• 当为非数据描述符时,dict__优先级高于__get
03.元类
就是创建类的类
- 用type创建元类
# 定义魔法方法
def __init__(self, name):
self.name = name
# 添加实例方法 slef
def info(self):
return self.age
# 添加静态方法 无需self 与 cls 参数
@staticmethod
def stat_func():
print("i am staticmethod")
# 添加类方法 注意一定有cls参数
@classmethod
def cls_method(cls):
print("classmethod")
User = type("User", (), {"age":18, "__init__":__init__, "info":info, "stat_func":stat_func})
# print(User) # <class '__main__.User'>
zs = User("C") # 实例化
# print(zs) # <__main__.User object at 0x000002B6086BE860>
print(zs.age) # 类属性
print(zs.name) # 实例属性
zs_age = zs.info() # 访问 实例方法
print(zs_age)
zs.stat_func() # 访问静态方法
type也可以继承
class BaseClass(object):
def test(self):
return "baseclass test"
def test1(self):
return "baseclass test1"
class BaseClass2(object):
def test(self):
return "baseclass2 test"
User = type("User",(BaseClass2, BaseClass),{"name":"oy"}) # 元组必须打逗号 否则报错
oy = User()
print(oy.test()) # 访问父类的test方法
print(oy.test1())
- metaclass属性
如果一个类中定义了__metalass__ = xxx,Python就会用元类的方式来创建类,就可以控制类的创建行为
比如,以下代码,再不改变类属性的抒写情况下,将属性名规定为大写访问
# 2.创建upper_attr函数
def upper_attr(cls_name, cls_parents, cls_attr):
# print(cls_name) # MyClass,当前指定的类名
# print(cls_parents) # (<class 'object'>,)
# print(cls_attr) # {'__module__': '__main__', '__qualname__': 'MyClass', 'name': 'ls'}
"""
4.将属性名规定为大写访问
- 遍历取出属性
- 如果属性是非_开头的
- 将其转为大写
"""
new_attr = {}
for name, value in cls_attr.items():
# print(name)
# print(value)
if not name.startswith("_"): #判断是否以下划线开头
new_attr[name.upper()] = value.upper()
# 5.返回type创建的类
return type(cls_name, cls_parents, new_attr)
# # 3.返回type创建的类
# return type(cls_name, cls_parents, cls_attr)
# 1.创建MyClass类,指定metaclass=upper_attr
class MyClass(object, metaclass=upper_attr):
name = "ls"
mc = MyClass()
print(mc.NAME)
04.迭代器
指一个重复的过程,每一次重复都是基于上一次结果而来,迭代提供了一种通用的不依赖索引的迭代取值方式
可迭代对象不一定是迭代器
- 判断是否可迭代
isinstance()–>用来判断对象是否是相应类型,与type()类似。 - 可以通过iter()方法将可迭代的对象,转为迭代器。
- 可迭代对象与迭代器区别
• 可用于for循环的都是可迭代类型
• 作用于next()都是迭代器类型
• list、dict、str等都是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器
• python的for循环本质就是通过不断调用next()函数实现的
05.生成器
为什么要有生成器
列表所有数据都在内存中,如果有海量数据的话会非常消耗内存。
比如说:我们仅仅需要访问前面几个元素,但后面绝大多元素占用的内存就会浪费了。
那么生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。
总而言之,就是当我们想要使用庞大数据,又想让它占用的空间少,那就使用生成器。
当一个函数中包含yield关键字,那么这个函数就不再是一个普通的函数,而是一个generator。
注意:
• yield返回一个值,并且记住这个返回值的位置,下次遇到next()调用时,代码从yield的下一条语句开始执行。与return的差别是,return也是返回一个值,但是直接结束函数。
06.迭代器与生成器
- 生成器能做到迭代器能做的所有事
- 而且因为生成器自动创建了iter()和next()方法,生成器显得简洁,而且高效