Python元类与迭代器生成器案例详解

1.__getattr__和__getattribute__魔法函数

__getattr__是当类调用一个不存在的属性时才会调用getattr魔法函数,他传入的值item就是你这个调用的不存在的值。
__getattribute__则是无条件的优先执行,所以如果不是特殊情况最好不要用__getattribute__。

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

    def __getattr__(self, item):
        return self.info[item]

ls = User("李四",{"gender":"male"})
print(ls.gender)

2.属性描述符

属性描述符介绍
属性描述符是一个强大的通用协议。它是properties, methods, static methods, class methods 和super()的调用原理。

属性描述符协议
属性描述符是实现了特定协议的类,只要实现了__get__,__set__和__delete__三个方法中的任意一个,这个类就是描述符,它能实现对多个属性运用相同存取逻辑的一种方式,通俗来说就是:创建一个实例,作为另一个类的类属性。

注意

• 如果一个对象同时定义了__get__和__set__方法,它被称做数据描述符(data descriptor)。

• 只定义__get__方法的对象则被称为非数据描述符(non-data descriptor)。

使用类方法创建描述符

• 定义一个IntField类为描述符类

• 创建IntField类的实例,作为另一个User类的属性

class IntField(object):
    def __set__(self, instance, value):
        print("__set__")

    def __get__(self, instance, owner):
        print("__get__")

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

class User(object):
    age = IntField()

ls = User()
ls.age
ls.age = 30
del ls.age

使用属性类型创建描述符

除了使用类当作一个属性描述符,我们之前学习的 property(),就是可以轻松地为任意属性创建可用的描述符。创建 property() 的语法是 property(fget=None, fset=None, fdel=None, doc=None)

描述符查找顺序

• 当为数据描述符时, __get__优先级高于__dict__
• 当为非数据描述符时,__dict__优先级高于__get__

元类

元类介绍

元类实际上就是创建类的类

实现如下:

• 定义创建类的函数create_class
• 如果给create_class传的参数为user,则创建User类

type()创建元类

• 第一个参数:name表示类名称,字符串类型
• 第二个参数:bases表示继承对象(父类),元组类型,单元素使用逗号
• 第三个参数:attr表示属性,这里可以填写类属性、类方式、静态方法,采用字典格式,key为属性名,value为属性值

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

User = type("User", (), {"age":18 , "__init__":__init__})
obj = User("amy")
print(obj.name)

metaclass属性

如果一个类中定义了__metalass__ = xxx,Python就会用元类的方式来创建类,就可以控制类的创建行为
比如,以下代码,再不改变类属性的抒写情况下,将属性名规定为大写访问。

class MyClass(object):
    name = "ls"
mc = MyClass()
print(mc.name)

Python迭代器

迭代器指的是迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上一次结果而来
迭代提供了一种通用的不依赖索引的迭代取值方式

可迭代对象

可以用for循环遍历的对象都是可迭代对象。
• str,list,tuple,dict,set等都是可迭代对象。
• generator,包括生成器和带yield的生成器函数。

判断是否可迭代

除了看内置是否含有__iter__方法来判断该对象是否是一个可迭代的对象之外,我们还可以使用 isinstance() 判断一个对象是否是 Iterable 对象
• isinstance()–>用来判断对象是否是相应类型,与type()类似。

from collections import Iterable,Iterator
print(isinstance('abc',Iterable))   # True
print(isinstance([1,2,3,4],Iterable))   # True
print(isinstance(123,Iterable))     # False

迭代器对象

• 有内置的__next__()方法的对象,执行该方法可以不依赖索引取值
• 有内置的__iter__()方法的对象,执行迭代器的__iter__()方法得到的依然是迭代器本身
需要注意的是,可迭代对象不一定是迭代器

iter()

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
那我们可以通过iter()方法将可迭代的对象,转为迭代器。

li = [1,2,3,4]
lis = iter(li)
print(type(lis))    # <class 'list_iterator'>

注意:
• 迭代器不可以通过下标取值,而是使用__next__()或者next()。但是只要超出范围则直接报错StopIteration。

print(lis[0])    # 报错 not subscriptable
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(next(lis))
print(next(lis))
print(next(lis))
print(next(lis))

• next()只能顺延调用,不能往前。

可迭代对象与迭代器区别
• 可用于for循环的都是可迭代类型
• 作用于next()都是迭代器类型
• list、dict、str等都是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器
• python的for循环本质就是通过不断调用next()函数实现的

生成器

生成器定义
在Python中,一边循环一边计算的机制,称为生成器:generator。
为什么要有生成器
列表所有数据都在内存中,如果有海量数据的话会非常消耗内存。
比如说:我们仅仅需要访问前面几个元素,但后面绝大多元素占用的内存就会浪费了。
那么生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。
总而言之,就是当我们想要使用庞大数据,又想让它占用的空间少,那就使用生成器。

如何创建生成器

生成器表达式
生成器表达式来源于迭代和列表解析的组合,生成器和列表解析类似,但是它使用()而不是[]。

g = (x for x in range(5))
print(g)       # generator object
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 超出报错
print(next(g))
for i in g:
    print(i)

生成器函数
当一个函数中包含yield关键字,那么这个函数就不再是一个普通的函数,而是一个generator。调用函数就是创建了一个生成器对象。其工作原理就是通过重复调用next()或者__next__()方法,直到捕获一个异常。
比如:
实现斐波那契数列,除第一个和第二个数外,任何一个数都可以由前两个相加得到:
1,1,2,3,5,8,12,21,34…

def createNums():
    print("-----func start-----")
    a,b = 0,1
    for i in range(5):
        # print(b)
        print("--1--")
        yield b
        print("--2--")
        a,b = b,a+b
        print("--3--")
    print("-----func end-----")

g = createNums()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

注意:

• yield返回一个值,并且记住这个返回值的位置,下次遇到next()调用时,代码从yield的下一条语句开始执行。与return的差别是,return也是返回一个值,但是直接结束函数。

迭代器与生成器

• 生成器能做到迭代器能做的所有事

• 而且因为生成器自动创建了iter()和next()方法,生成器显得简洁,而且高效。

读取大文件

文件300G,文件比较特殊,一行 分隔符 {|}

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)

到此这篇关于Python元类与迭代器生成器案例详解的文章就介绍到这了,更多相关Python元类与迭代器生成器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python学习之可迭代对象、迭代器、生成器

    Iterable – 可迭代对象 能够逐一返回其成员项的对象. 可迭代对象的例子包括所有序列类型 (例如 list, str 和 tuple) 以及某些非序列类型例如 dict, 文件对象以及定义了__iter__()方法或是实现了序列语义的__getitem__() 方法的任意自定义类对象. 可迭代对象可用于 for 循环以及许多其他需要一个序列的地方(zip().map() -).当一个可迭代对象作为参数传给内置函数 iter() 时,它会返回该对象的迭代器.这种迭代器适用于对值集合的一次性

  • Python自定义元类的实例讲解

    1.说明 一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类. 2.实例 我们可以使用类属性 __metaclass__ 把一个类的创建过程,转交给其它地方. class A(object): __metaclass__ = ... # 这个类的创建转交给其他地方 pass 先定义了类 A,然后定义了一个类属性 __metaclass__,这个属性表示创建类 A 的过程,转交给其它地方处理. 类属性 __metaclass__ 可以是

  • 一篇文章带你了解python迭代器和生成器

    目录 python迭代器和生成器 2.生成器 总结 python迭代器和生成器 1.迭代器 这里用字典示例 while True 属于无限循环,因字典元素有限,所以用try做异常处理 dict1 = { 'name':'laowang', 'age':18, 'high':180 } iterator = dict1.__iter__() while True: try: res = iterator.__next__() except: break else: print(res,dict1[

  • Python基础之元类详解

    1.python 中一切皆是对象,类本身也是一个对象,当使用关键字 class 的时候,python 解释器在加载 class 的时候会创建一个对象(这里的对象指的是类而非类的实例) class Student: pass s = Student() print(type(s)) # <class '__main__.Student'> print(type(Student)) # <class 'type'> 2.什么是元类 元类是类的类,是类的模板 元类是用来控制如何创建类的,

  • 详解python metaclass(元类)

    元编程,一个听起来特别酷的词,强大的Lisp在这方面是好手,对于Python,尽管没有完善的元编程范式,一些天才的开发者还是创作了很多元编程的魔法.Django的ORM就是元编程的一个很好的例子. 本篇的概念和例子皆在Python3.6环境下 一切都是对象 Python里一切都是对象(object),基本数据类型,如数字,字串,函数都是对象.对象可以由类(class)进行创建.既然一切都是对象,那么类是对象吗? 是的,类也是对象,那么又是谁创造了类呢?答案也很简单,也是类,一个能创作类的类,就像

  • 正确理解python迭代器与生成器

    目录 一.迭代器 二.生成器 三.生成器函数 3.1.zip(可迭代对象1,可迭代对象2......) 3.2.enumerate(iterable[,start]) 一.迭代器 迭代器就是iter(可迭代对象函数)返回的对象,说人话.......可迭代对象由一个个迭代器组成 可以用next()函数获取可迭代对象的数据 迭代是访问集合元素的一种方式(因为集合是无序的,所以不能索引),naxt(集合), 迭代器对象从集合的第一个元素开始访问,直到所有元素被访问结束,迭代器只能往前不会往后退 迭代器

  • Python元类与迭代器生成器案例详解

    1.__getattr__和__getattribute__魔法函数 __getattr__是当类调用一个不存在的属性时才会调用getattr魔法函数,他传入的值item就是你这个调用的不存在的值. __getattribute__则是无条件的优先执行,所以如果不是特殊情况最好不要用__getattribute__. class User(object): def __init__(self, name, info): self.name = name self.info = info def

  • Python 中闭包与装饰器案例详解

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 1.Python中一切皆对象 这恐怕是学习Python最有用的一句话.想必你已经知道Python中的list, tuple, dict等内置数据结构,当你执行: alist = [1, 2, 3] 时,你就创建了一个列表对象,并且用alist这个变量引用它: 当然你也可以自己定义一个类: class House(object): def __init__(self, are

  • SpringBoot之通过BeanPostProcessor动态注入ID生成器案例详解

    在分布式系统中,我们会需要 ID 生成器的组件,这个组件可以实现帮助我们生成顺序的或者带业务含义的 ID. 目前有很多经典的 ID 生成方式,比如数据库自增列(自增主键或序列).Snowflake 算法.美团 Leaf 算法等等,所以,会有一些公司级或者业务级的 ID 生成器组件的诞生.本文就是通过 BeanPostProcessor 实现动态注入 ID 生成器的实战. 在 Spring 中,实现注入的方式很多,比如 springboot 的 starter,在自定义的 Configuratio

  • python内置函数之slice案例详解

    英文文档: class slice(stop) class slice(start, stop[, step]) Return a slice object representing the set of indices specified by range(start, stop, step). The start and step arguments default to None. Slice objects have read-only data attributes start, st

  • Python实现OCR识别之pytesseract案例详解

    Python实现OCR识别:pytesseract Python常用pytesseract进行图片上的文字识别,即OCR识别,完整的代码比较简单,只要下面一行即可,但是实际使用时环境配置上容易出错. from PIL import Image import pytesseract text = pytesseract.image_to_string(Image.open('/Users/alice/Documents/Develop/PythonCode/textinphoto.PNG')) p

  • Python Pycurl的属性与方法案例详解

    Pycurl包是一个libcurl的Python接口,由C语言编写的,功能强大,速度快.由于pycurl的属性和方法太多了,写这篇博文记录一下pycurl的属性和方法. 正常安装 pip install pycurl 如果出现问题,可以按照系统版本搜索安装方法,比如centos7.1 安装pycurl 通用请求方法 import pycurl,urllib from io import BytesIO url = 'http://www.baidu.com' headers = [ "User-

  • Python中的tkinter库简单案例详解

    目录 案例一 Label & Button 标签和按钮 案例二 Entry & Text 输入和文本框 案例三 Listbox 部件 案例四 Radiobutton 选择按钮 案例五 Scale 尺度 案例六 Checkbutton 勾选项 案例七 Canvas 画布 案例八 Menubar 菜单 案例九 Frame 框架 案例十 messagebox 弹窗 案例十一 pack grid place 放置 登录窗口 TKinterPython 的 GUI 库非常多,之所以选择 Tkinte

  • python爬虫爬取微博评论案例详解

    前几天,杨超越编程大赛火了,大家都在报名参加,而我也是其中的一员. 在我们的项目中,我负责的是数据爬取这块,我主要是把对于杨超越 的每一条评论的相关信息. 数据格式:{"name":评论人姓名,"comment_time":评论时间,"comment_info":评论内容,"comment_url":评论人的主页} 以上就是我们需要的信息. 爬虫前的分析: 以上是杨超越的微博主页,这是我们首先需要获取到的内容. 因为我们需要等

  • c/c++单例模式类的混合编译案例详解

    目录 C/C++混合编译 解决方案: 中间层调用 log案例 解决方案: 源代码 C/C++混合编译 难点:c++支持重载,因此g++编译后的函数名有额外信息,在gcc编译的c文件中无法识别符号,导致链接失败. 解决方案: extern “C” { } 中间层调用 extern “C” ​ 对c++文件编译时使用extern “C“ { },让编译器安装c语言的规则对其中的内容进行编译,主要解决c++中重载函数名导致符号不识别的问题. ​ 同时配合ifdef __cplusplus和endif实

  • Python 的类、继承和多态详解

    类的定义 假如要定义一个类 Point,表示二维的坐标点: # point.py class Point: def __init__(self, x=0, y=0): self.x, self.y = x, y 最最基本的就是 __init__ 方法,相当于 C++ / Java 的构造函数.带双下划线 __ 的方法都是特殊方法,除了 __init__ 还有很多,后面会有介绍. 参数 self 相当于 C++ 的 this,表示当前实例,所有方法都有这个参数,但是调用时并不需要指定. >>&g

随机推荐