python学习4——元类,迭代器生成器

getattr__与__getattribute

当访问的属性不存在时,会自动调用__getattr__魔法方法

class User(object):
    def __init__(self, name, info):
        self.name = name
        self.info = info

    def __getattr__(self, item):# item就是传入的gender/agg
        try:
            return self.info[item]
        except Exception as e:
            return f'不存在{item}这个属性'


ls = User("lisi", {"gender":"male"})

print(ls.gender)
print(ls.age)

当定义了__getattribute__时,它会无条件的优先执行。优先级高于__getattr__。当定义了__getattribute__就不会调用__getattr__了。

属性描述符

只要实现了 __get__和__set__和__delete__三个方法
中的任意一个,这个类就算是描述符
用类的方式创建描述符如下:

class IntFiled(object):
    def __set__(self, instance, value):
        # print("Set")
        # print(isinstance)
        # print(value) # 20
        if not isinstance(value, int):
            raise ValueError("不是整数")
        self.values = value

    def __get__(self, instance, owner):
        # print("get")
        # print(isinstance)  # <built-in function isinstance>
        # print(owner)  # <class '__main__.User'>
        return self.values

    def __delete__(self, instance):
        print("delete")

class User(object):
    age = IntFiled()

ls = User()
ls.age=20
print(ls.age)
del ls.age

使用属性类型创建描述符:property

class AgeDemo:
    def __init__(self, age):
        self.age = age

    def get_age(self):
        return self.age

    def set_age(self, age):
        if not isinstance(age, int):
            raise TypeError("TypeError")
        self.age = age

    age_pro = property(fget=get_age, fset=set_age)


a = AgeDemo(19)
print(a.age_pro)
a.age_pro = 30
print(a.age_pro)

描述符的查找顺序

class IntFiled(object):
    def __set__(self, instance, value):
        # print("Set")
        # print(isinstance)
        # print(value) # 20
        if not isinstance(value, int):
            raise ValueError("不是整数")
        self.values = value

    def __get__(self, instance, owner):
        # print("get")
        # print(isinstance)  # <built-in function isinstance>
        # print(owner)  # <class '__main__.User'>
        return self.values

    def __delete__(self, instance):
        print("delete")

class User(object):
    age = IntFiled()
    # pass

ls = User()
# ls = IntFiled()
ls.age=20  # 不是实例属性 这是类属性
print(ls.__dict__)

ls.__dict__['age'] = 30


print(ls.age)  # 当是数据描述符时,get优先级高于dict优先级

print(ls.__dict__)

元类

元类其实就是创建类的类

def create_class(name):
   if name =="user":
        class User(object):
            def __str__(self):
                return "user"
        return User
   elif name == "person":
        class Person(object):
           def __str__(self):
               return "person"
        return Person


myclass = create_class("person")
obj = myclass()
print(obj)

type()创建元类

type(“类名”,(父类,),{属性,方法})
(注意这里的父类,若只有一个父类,那么后面要加上逗号,不然会报错。这里也支持C3算法规则)

class fa:
    def info(self):
        print("info")

class fa2:
    def info(self):
        print("info2")

    def test(self):
        print("test2")
        
@staticmethod
def stat_func():
    print("i am staticmethod")

@classmethod
def cls_func(cls):
    print("i am classmethod")

def __init__(self, name):
    self.name = name
    print("i am init")

User = type("User",(fa,fa2),{"age":18, "__init__":__init__, "stat_func":stat_func, "cls_func":cls_func})
obj = User("lisi")
print(obj.age)
obj.info()
obj.test()

metaclass属性

如果一个类中定义了metaclass 属性,那么python就会用元类的方式来创建类,就可以控制创建类的行为
下面的例子是传入属性名,在不改变类代码的情况下,自动把属性名和属性值都转换为大写

def upper_attr(cls_name, cls_parents, cls_attr):
    new_attr = {}
    for name, value in cls_attr.items():
        if not name.startswith("_"):
            new_attr[name.upper()] = value.upper()
    return type(cls_name, cls_parents, new_attr)

class MyClass(object, metaclass=upper_attr): # 元类来改变
    name = "ls"

my = MyClass()
print(my.NAME)

当一个类继承多个类的时候,会优先查找继承type的类去执行

# 会优先寻找metaclass类

class Demo(object):
    def __new__(cls, *args, **kwargs):
        print("demo")
        return super().__new__(cls)

class MetaClass(type): #继承元类
    def __new__(cls, *args, **kwargs):
        print("metaclass")
        return super().__new__(cls,*args,**kwargs)

class User(Demo,metaclass=MetaClass): #metaclass 优先级最高
    def __str__(self):
        return "user"

obj = User()
print(obj)

在这里插入图片描述

迭代器

说到迭代器,那就要先说说可迭代对象。可迭代对象就是能被for循环的对象。
str,list,dict,set,tuple都是可迭代对象,但可迭代对象都是迭代器吗?
不不不不,可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。

from collections import Iterable
list1 = [1,2,3]
print(isinstance(list1, iterable)) # False

可迭代对象不一定是迭代器,可迭代对象没有__iter__(),__next__方法。当使用next()时就会报错。
如果想要一个可迭代对象变成迭代器,直接通过iter(list1) 即可把可迭代对象变成迭代器。

from collections import Iterator
list1 = [1,2,3]
list2 = iter(list1)
print(isinstance(list2, Iterator)) # True

当对象变为迭代器对象时,就可以使用next()方法了,但是不能通过下标取值

迭代器和可迭代对象的区别

  1. 可以for循环的对象都是可迭代对象
  2. 作用next()的都是迭代器类型
  3. list,dict,str,set,tuple都是可迭代对象,但都是不是迭代器
  4. 可迭代对象可以使用 iter()转换为迭代器对象
  5. python的for循环就是不断调用next()函数实现的

生成器

何为生成器,先说说为什么要引入生成器。列表的所有数据都是存在内存中的,当数据量很大的时候,就很耗费内存。有时候我们只访问前面的几个数据,用不到那么多数据的时候,该怎么节省内存呢。这时候可以引入生成器。生成器generator可以在循环过程中使用算法不断推算得出后面的数据,这样就不需要创建完整的列表,从而节省大量的空间。它就是一边循环一边计算的机制。

生成器表达式

生成器表达式来源于迭代和列表解析的结合

de = (i for i in range(100000))

print(type(de))
# <class 'generator'>

生成器使用next来下一步的时候,超出会报错

de = (i for i in range(5))
print(next(de))
print(next(de))
print(next(de))
print(next(de))
print(next(de))
print(next(de))  # 报错了

生成器函数

当一个函数包含yeild关键字时,那它就变成了生成器函数
下面是用生成器函数输出斐波那契数列

def createNums():
    print("start")
    a, b = 0, 1
    for i in range(6):
        yield b
        a, b  = b, a+b

    print("end")

g = createNums()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g)) # 报错,意味着结束 打印了  end
yield

yield和return都是返回数据,但是yield可以记住这个返回值的位置,等到下次调用next()时,会从yield下一行的语句开始执行。return是直接结束函数。

迭代器与生成器

迭代器拥有的生成器都有,生成器能做到迭代器做的所有事。
而且生成器自动创建了iter()和next()方法,生成器更加简洁,而且高效。

读取大文件

def readlines(f,newline):
    buf = ""
    while True:
        while newline in buf:
            pos = buf.index(newline)
            yield buf[:pos]
            buf = buf[pos + len(newline):]
        chunk = f.read(4096*10)
        if not chunk:
            yield buf
            break
        buf += chunk
with open('demo.txt') as f:
    for line in readlines(f,"{|}"):  # 分隔符 |
        print(line)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值