从入门到入狱-------装饰器、迭代器/生成器和模块

入门 N day

  • 有参装饰器

    在给函数添加功能的时候,可以通过参数控制具体的操作(操作不固定)

    '''
    格式:
    def 函数名0(装饰器的形参列表):
    	def 函数名1(func):
    		def 函数名2(*agrs,**kwargs):
    			result=func(*args,**kwargs)
    			添加的功能
    			return result
    		return 函数名2
    	return 函数名1
    有参装饰器的用法:
    @函数名0(装饰器实参列表)
    '''
    

    写一个装饰器可以在函数结束后打印指定的任意提示信息

    def end_message(x):
        def end(func):
            def new_func(*args,**kwargs):
                result = func(*args,**kwargs)
                print(x)
                return result
            return new_func
        return end
    @end_message('程序结束咯')
    def func1(x,y):
        print(x+y)
     
    func1(1,2)
    

    练习:在原函数返回值的基础上减去指定的值

    def end_(x):
        def end(func):
            def new_func(*args,**kwargs):
                result=func(*args,**kwargs)
                if type(result) in (int, float, bool, complex):
                    return result-x
                return result
            return new_func
        return end
    @end_(15)
    def _():
        return 10
    print(_())
    
    
  • 迭代器

    迭代器是容器型数据类型(序列)

    特点:

    不能同时查看多个元素(直接打印看不到元素)

    不能统计个数

    不能查看长度

    获取元素的时候只能一个一个取,每次取最上层的一个元素,取一个少一个

    —创建迭代器—

    • 通过iter将其他序列转换成迭代器

    • 创建生成器

    iter1=iter([10,20,30,40])
    print(iter1)   # # <list_iterator object at 0x000000000069CF88> 看不到里面的元素
    '''
    print(len(iter1))  #TypeError: object of type 'list_iterator' has no len() 不能统计个数(查看长度)
    
    '''
    

    从迭代器获取到元素,元素便不存在于迭代器里面了

    每次只能取单个元素或者转换为其他序列 next(迭代器)和遍历

    # 方法一  next
    iter1 = iter([10, 20, 30, 40])
    print(next(iter1))  # 10
    print(next(iter1))  # 20
    next(iter1)  # 取出来没有打印
    print(next(iter1))  # 40  这是最后一个元素,此时迭代器为空
    '''
    print(next(iter1)) # StopIteration  对空的迭代器取元素,会报错
    '''
    # 方法二 遍历
    iter2 = iter([10, 20, 30, 40])
    for i in iter2:
        print(i)  # 遍历iter2 依次将元素取出来直到迭代器为空
     
    '''
    iter3=iter('python!')
    list1=list(iter3)
    print(next(iter3)) # StopIteration
    报错的原因是因为迭代器iter3转换成为了列表
    那么原来iter3里面就没有元素了,所以再获取就会报错
    '''
    # 方法三 转换成列表
    iters = iter((10, 20, 30, 40))
    print(list(iters))  # [10, 20, 30, 40]
    
  • 生成器

    生成器的本质是一个迭代器,但是生成器数据来源和迭代器不同

    如果迭代器看做是将鸡蛋(数据)一个叠一个放到容器里面的话

    那么生成器就是放了一只母鸡(算法),需要多少个鸡蛋(鸡蛋)就提供多少

  • 创建生成器

    调用一个带有yield关键字的函数,就可以创建一个生成器对象

    如果被调用的函数里面有yield,就不会执行函数体,也不会获取函数返回值

    def func1():
        print('+++++')
        print('====')
        yield
        return 100
    result=func1()
    print(result)
    
  • 怎么确定生成器中产生的数据

    产生数据的个数:看执行生成器对应的函数会遇到几次yield

    产生数据的值:看每次遇到的yield后面的数据是什么,没有数据就是None

    def func2():
        yield
        yield 'abc'
        for i in range(3):
            yield i
    
    
    gen1 = func2()
    print(gen1)
    list1 = list(gen1)
    print(list1, len(list1))  # [None, 'abc', 0, 1, 2] 5
    
    def func3(x):
        yield
        yield 'abc'
        if x & 1:
            yield 100
        return 20
        yield 10  # 遇不到
    
    
    print(list(func3(3)))
    # [None, 'abc', 100] 这里不会遇到20,因为前面有return函数体已经结束了
    
    
  • 生成器产生数据的原理

    调用函数创建生成器对象的时候不会执行函数体,获取生成器中的元素的时候才会执行,第一次获取元素会从函数体开始的位置开始执行,执行到第一次yield就停下来,并且将yield后的的数据作为这次获取的到的元素,后面每次获取元素的时候都是从上次结束的位置接着往后执行,执行到下一次yield又会停下来,如果从当前位置开始执行到函数结束没有遇到yield,是next获取就会报错

    # 练习:写一个产生学号的生成器,能够产生指定学科001~999的学生学号
    
    def subject(subject):
        def create_num():
            for i in range(1, 1000):
                yield f'{subject}{i:0>3}'
    
        gen5 = create_num()
        for i in range(999):
            print(next(gen5))
    
    
    subject('java')
    # 写一个能够产生所有正偶数的
    def num():
        x = 0
        while True:
            x+=2
            yield x
    nums=num()
    print(next(nums))
    print(next(nums))
    print(next(nums))
    
  • 生成式 —生成器的推导式

    将列表推导式的 [ ] 变为(),就是生成器的推导式—生成式

    list1=[i**2 for i in range(10)]
    print(list1)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    # 生成式
    gens=(i**2 for i in range(10))
    print(next(gens)) # 0
    print(next(gens)) # 1
    print(next(gens)) # 4
    

  • 模块

python中一个py文件就是一个模块,文件名就是模块名

可以在一个模块中去使用另外一个模块中的内容(没有在函数和类里面 的函数、类、变量)但是需要提前导入模块

假如存在一个模块,里面有如下代码:

  print('.......')
  A = 100

  def func1():
      print('test1中的函数')

  for i in range(10):
      pass
  print('+++++++')
  • 导入模块

    在一个工程里面导入
    import 模块名
    导入后能够使用指定模块中的全局变量
    以‘模块名.变量’的形式使用

    import test1
    print(test1.A)  #100
    test1.func1()
    print(test1.i)
    
    
    

    form 模块名 import 变量名1,变量名2…
    导入模块,使用指定的全局变量
    可以直接使用对应变量不需要以‘模块名.变量’的方式使用

    from test1 import A,func1
    print(A)  # 100
    func1() #test1中的函数
    print(i)  # 会报错,因为没有导入i这个变量
    
    
  • 模块重命名
    import 模块名 as 新模块名
    导入模块的时候对模块重新命名
    重命名后需要使用新模块名来是用被导入的模块

    import test1 as new_test1
    print(new_test1.A)  # 100
    new_test1.func1()  # test1中的函数
    print(new_test1.i) # 9
    
    
  • 对指定变量进行重命名
    form 模块名 import 变量名1 as 新变量名,变量名2,…

    from test1 import A as a,func1
    print(a)  # 100
    func1() #test1中的函数
    
    
  • 导入全部变量

    from 模块名 import *

  • 导入模块的原理

    在导入模块的时候,系统会自动将被导入的模块中所有的代码都执行一遍
    注意:
    import 导入模块的时候自带查重功能
    如果被导入的模块已经被导入了,不会重复导入

    from test1 import A as a,func1   # .......  ++++++++
     '''
    
  • 阻止导入 if name == ‘main’:

  • name 系统用来保存模块名字的变量

    print(__name__) # __main__
    

    每次运行当前py文件系统 name == main 会执行if后面的语句
    如果导入模块,name != main 不会执行if后面的语句
    因此会把不需要导入的部分放入if后面,就是阻止导入

    def func1():
      pass
    
    def func2():
      pass
    def main():
      func1()
      func2()
    if __name__ == '__main__':
        main()
    

    if语句外面放全局变量,里面进行函数调用

    别人导入模块的时候就只会执行if外面的代码,而不会执行if里面的代码

猜你喜欢

转载自blog.csdn.net/weixin_44628421/article/details/109081448
今日推荐