第四阶段 -- python核心特性:【生成器;迭代器;装饰器;闭包;python的动态性】

1. 生成器

  • 什么是生成器?generator
    • 生成器记录一个算法,可以一边循环,一边计算的一种机制。
  • 生成器生成方式有哪些?
    • 有这样一个需求:存储1-10000000中所有的偶数。
  1. 使用list(列表)

    # 直接使用list,但这种方式占用很多内存
    import time
    import sys # 系统模块
    
    time.clock() # 获取CPU计算的时长
    
    list1 = []
    for i in range(2,10000001,2):
    	list1.append(i)
    print(list1)
    
    costTime = time.clock()
    print("创建列表耗时:%g"%costTime)
    print("创建列表的内存开销:%d"%sys.getsizeof(list1)) # 获取内存开销
    
    # 使用列表推导式
    list2 = [i for i in range(2,10000001) if i%2==0]
    print(list2)
    
  • 使用列表会占用很多内存;如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。
  1. 使用生成器:可以存储数据,其实就是存储算法

    1. 创建生成器:

      1. 方式一:g = (i for i in range(2,10000001,2))
    		############# 方式一:#############
    import time
    import sys # 系统模块
    
    time.clock() # 获取CPU计算的时长
    # 创建生成器g
    g = (i for i in range(2,10000001,2)) 
    print(type(g1))
    
    # 1.next():生成器元素访问方式,但是一次只生成一个元素
    # print(next(g)) 
    
    # 2.用for循环遍历
    for i in g:
       print(i)
    
    # 3.使用send()方式访问生成器中的元素
    print(g.send(None))
    print(g.send("abc"))
    
    costTime = time.clock()
    print("创建生成器耗时:%g"%costTime)
    print("创建生成器的内存开销:%d"%sys.getsizeof(g))
    
    1. 方式二:在函数中使用关键字yield,函数在调用时候,不再是接收函数的返回值,而是接收一个生成器。
    			############# 方式二:#############
    def test():
        for x in range(5)
        	yield x
    
    f = test()
    print(type(f))
    
    # 访问生成器的元素
    print(next(f))
    
    1. 生成器的元素访问方式及注意事项:

      • next(g)
      • for 循环遍历
      • g.__ next __()
      • g.send()(使用send的时候首个元素必须给None参数,后续元素,可以传任意参数)
    2. 廖雪峰官网【生成器】:https://www.liaoxuefeng.com/wiki/897692888725344/923029685138624

2. 迭代器

  • 可迭代性:Iterable

  • 迭代器:Iterator;能被next()访问,并不断返回下一个值的对象

  • 判断是否是可以迭代:insinstance(对象,类)

from collection import Iterable
num = 100
if isinstance(num,Iterable):
    for i in num:
        print(i)
else:
    print('num不具备可迭代性')
  • 可迭代性有
    1. 集合类元素:list;tuple;string;dict
    2. 生成器
from collection import Iterable

# 列表
list = [1,2,3]
print(isinstance(list,Iterable))
# 字符串
str = "abcdef"
print(isinstance(str,Iterable))
# 生成器
g = (i for i in range(5))
print(type(g))
print(isinstance(g,Iterable))
  1. 具备可迭代性的元素,就一定是迭代器吗?
  • 答案:不一定!!!
from collection import Iterable,Iterator

# 列表不是迭代器!!!
list = [1,2,3]
if isinstance(list,Iterator):
    print('list是迭代器')
    print(next(list))
else:
    print('list不是迭代器')
  1. iter()函数:让具备可迭代性的元素变成迭代器next()
from collection import Iterable,Iterator

# 使用1iter()函数把list变成迭代器
list = iter(list)

list = [1,2,3]
if isinstance(list,Iterator):
    print('list是迭代器')
    print(next(list))
else:
    print('list不是迭代器')

3. 闭包

  1. 定义:就是一个函数;在函数式编程中呗广泛使用。
  2. 创建闭包:(三个条件)
    1. 嵌套函数(外部函数,内部函数)
    2. 内部函数使用外部函数中定义的变量(参数)
    3. 外部函数一定要有返回值,返回内部函数名
  • 例如:使用闭包完成求两个数字的和
def funcOut(num1):
    def funcIn(num2):
        # num1 += 1  # 不可以修改外部函数的值
        nonlocal num1
        # 如果想在内部函数中修改外部函数的变量,需要使用nonlocal声明
        num1 += 1
        return num2 + num1  # 满足条件2
    return funcIn  # 满足条件3

a = 10
b = 20
funcIn = funcOut(a)  # 返回了函数funcIn
print(type(funcIn)) # funcIn是个函数

result = funcIn(b)
result = funcIn(100)
print(result)
  • 注意:

    • 闭包中的外部函数的局部变量不会因为函数调用而消失!

    • 如果想在内部函数中修改外部函数的变量,需要使用nonlocal声明!

  1. 例子:求两个点之间的距离
		############# 方式一:函数 #############
import math
def getDis(x1,y1,x2,y2):
    return math.sqrt((x1-x2)**2 + (y1-y2)**2)
    
    
    	############# 方式二:闭包 #############
def getDisOut(x1,y1):
    def getDisIn(x2,y2):
        return math.sqrt((x1-x2)**2 + (y1-y2)**2)
    return getDisIn

# 分别求点(10,10),(20,20)距离原点的距离
# 函数
dis = getDis(0,0,10,10)
print("(10,10)距离原点的距离为:%g"%dis)

dis = getDis(0,0,20,20)
print("(20,20)距离原点的距离为%g"%dis)

print("--------------------------------------")

# 闭包
getDisIn = getDisOut(0,0)

dis1 = getDisIn(10,10)
print("(10,10)距离原点的距离为:%g"%dis1)
dis1 = getDisIn(20,20)
print("(20,20)距离原点的距离为%g"%dis1)
  1. 闭包的特殊用途:

    1. 可以在不修改现有功能源码的前提下,增加新的功能

      • 日志功能(统计访问时间,访问功能,写到日志文件中)

      • 权限验证(下载之前会验证当前账户是否为会员)

      • 开闭原则:

        开放:添加功能

        关闭:修改源代码

    		############# 日志:源码 #############
    # 定义一个记录日志的函数:将访问事件以及访问的函数名写入到文件中(log.text)
    import time
    def writeLog(func):
        try:
        	file = open('log.text','a',encoding='utf-8')
            # 写入相关数据信息(访问函数名,访问的时间)
            file.write(func.__name__)
            file.write('\t')
            # 写入访问时间
            strTime = time.asctime()
            file.write(strTime)
            file.write('\t')
        except Exception as e:
    		print(e.args)
        finally:
        	file.close()
    
    # 闭包
    def funcOut(func):
        def funcIn():
            # 新增功能
            writeLog(func)
            func()
        return funcIn
    
    def func1():
        print('我是功能1')
    def func2():
        print('我是功能2')
    
    # 闭包的调用
    func1 = funcOut(func1)
    func2 = funcOut(func2)
        
    func1()
    func2()
    

4. 装饰器

  1. 装饰器与闭包关系紧密,很多时候,二者结合使用:
    装饰器使一个函数或方法包装在另一个函数里面,可以在被包装的函数添加一些额外的功能,比如日志,还可以对参数,返回结果进行修改。
import time
def writeLog(func):
    try:
    	file = open('log.text','a',encoding='utf-8')
    	file.write(func.__name__)
        file.write('\t')
        file.write(time.asctime())
        file.write('\n')       
    except Exception as e:
    	print(e.args)
    finally:
        file.close()

def funcOut(func):
    def funcIn():
        writeLog(func)
        func()
    return funcIn

@funcOut
# 等价于:func1 = funcOut(func1)
def func1():
    print('我是功能1')
@funcOut
# 等价于:func2 = funcOut(func2)
def func2():
    print('我是功能2')

# func1 = funcOut(func1)
# func2 = funcOut(func2)

func1()
func2()
  • 装饰器的例子:使用装饰器,不修改一个函数源码的前提下,增加新的功能。
# 给bookName()函数的返回值‘西游记’两侧添加‘《 》’
# 1.使用闭包来完成
def funcOut(func):
    def funcIn():
        return '《' + func() + '》'
    return funcIn

def bookName():
    return '西游记'

bookName = funcOut(bookName)
print(bookName())


# 2.使用装饰器来完成
def funcOut(func):
    print('闭包1开始装饰')
    def funcIn():
        return '《' + func() + '》'
    return funcIn

def funcOut2(func):
    print('闭包2开始装饰')
    def funcIn():
        return '$' + func() + '$'
    return funcIn

@funcOut2
# bookName = funcOut2(bookName)
@funcOut
# bookName = funcOut(bookNmae)
def bookName():
    return '西游记'

print(bookName())


  • 注意:在使用装饰器时,靠近函数的装饰器先执行!
  1. 指定参数个数的装饰器
def funcOut(func):
    def funcIn(x,y):
        func(x,y)
    return funcIn

@funcOut
# test = funcOut(test)
def test(a,b):
    print('a = %g b= %g'%(a,b))

test(1,2)

  1. 通用装饰器
# def funcOut1(func):
#     def funcIn1(a):
#         print('新增功能1')
#         func(a)
#     return funcIn1

# def funcOut2(func):
#     def funcIn2(a,b):
#         print('新增功能2')
#         func(a,b)
#     return funcIn2

def funcOut(func):
    # 可变参数
    def funcIn(*args,**kwargs):
        print('新增功能')
        return func(*args,**kwargs)
    return funcIn

@funcOut
def func1(a):
    print('a = %g'%a)
    
@funcOut
def func2(a, b, name='www'):
    print('a = %g b = %g c = %s' % (a, b, name))

func1(10)
func2(20, 30, name = 'WYZ')

【类装饰器】https://blog.csdn.net/weixin_42375099/article/details/94859193#2__48

5. Python动态添加属性方法

  • python是动态语言:可以在运行是改变类的结构(添加属性,添加方法,删除函数)
  1. 动态添加属性

    1. 添加对象属性

      1. 对象名.属性名 = 值
      2. `setattr(对象, 属性, 值)
    2. 添加类属性类名.属性名 = 值

  2. 动态添加方法

    1. 添加对象方法:(import types)

      p1.study = types.MethodType(study,p1)

    2. 添加静态方法

      @staticmethod

      类名.静态方法名 = 定义的函数名 注意这里定义的函数不加括号!

    3. 添加类方法

      @classmethod

      类名.类方法名 = 定义的函数名注意这里定义的函数不加括号!

  3. python是强类型语言:变量的类型运行时决定;变量类型在运行之后,可以任意改变,不需要强制转换。

  • 动态添加属性:添加类属性;成员属性
class Person()
	def __init__(self,name,age):
        self.name = name
        self.age = age
        
p1 = Person('学生',18)
p2 = Person('学生',20)

				########## 动态添加属性 ###########
    
					# 1.添加类对象属性 #
# 1. 直接通过对象添加
p1.address = '北京'
# 2. 通过setattr()添加gender属性
setattr(p1, 'gender', '男')

					# 2.添加类属性 #
# print(p2.gender)  # 会报错!没有gender这个属性
Person.CLS.ID = 100
print(p1.CLS.ID)
print(p2.CLS.ID)

  • 动态添加方法:对象方法;类方法;静态方法
				########## 添加方法 ###########
import types
class Person()
	def __init__(self,name,age):
        self.name = name
        self.age = age
        
def study(self):
    print('学习使我快乐!')
    
p1 = Person('学生',18)
p2 = Person('学生',20)

			### 添加对象方法 ###
# 通过typesMethodType添加对象方法,只能p1来调用
p1.study = types.MethodType(study,p1)
p1.study

			### 添加静态方法 ###
@staticmethod
def testStaticMethod():
    print('我是静态方法')
    
# 给类添加静态方法
Person.method1 = testStaticMethod
# 1.对象访问
p1.method1()
# 2.类名访问
Person.method1()
    
    
    		### 添加类方法 ###
@classmethod
def testClsMethod(cls):
    print('我是类方法')

# 添加类方法
Person.method2 = testClsMethod
# 1.对象访问
p1.method2()
# 2.类名访问
Person.method()

6. __ slots __的作用

  1. __ slots __可以对动态添加成员属性做限制,对类属性没有限制。
  2. __ slots __可以对动态添加对象方法做限制;对静态方法,类方法没有限制。
  3. __ slots __对子类没有任何限制。
import types
class Person():
    __slots__ = ('name','age')
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def eat(self):
        print("人要吃饭")
    
    def study(self):
        print('学习使我快乐')
# 动态添加属性
p1 = Person('张三',19)
# p1.gender = '男' # 会报错!
Person.CLS_id = 102 # 没有报错!

# 动态添加类方法
# p1.study = types.MethodType(study,p1) # 会报错!

# 动态添加静态方法
@staticmethod
def testStatic():
    print('我是静态方法')
Person.testStatic = testStatic

# 子类动态添加属性
class Student(Person):
    pass
stu1 = Student('李四',26)
stu1.addr = '北京'
print(stu1.addr) # 没有报错!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值