Python基础学习笔记(11)函数的陷阱 函数名的运用 f-string 迭代器

Python基础学习(11)函数的陷阱 函数名的运用 f-string 迭代器

一、今日内容大纲

  • 函数的陷阱

  • 关键字:global、nonlocal

  • 函数名的运用

  • Python 3.6 新特性:f-string

  • 迭代器

二、函数的陷阱

  1. 默认参数的陷阱

    针对默认参数是可变数据类型。无论你调用多少次这个默认参数,所调用的都是同意地址下的数据。

    def func(name, list=[]):
        list.append(name)
        return list
    
    ret = func('alex')
    print(ret, id(ret))  # ['alex'] 2636141462472
    ret2 = func('太白金星')
    print(ret2, id(ret2))  # ['alex', '太白金星'] 2636141462472
    
    # Exercise 1:
    def func(a, list=[]):
        list.append(a)
        return list
    print(func(10, ))  # [10]
    print(func(20, []))  # [20] (This call passes in another list)
    print(func(100, ))  # [10, 100]
    
  2. 局部作用域的陷阱

    count = 1
    def func():
        print(count)  # error: local variable 'count' referenced before assignment
        count = 3
    func()
    
    count = 1
    def func():
        print(count)  # No error, function can find global variable 'count'
    func()
    

二、关键字 global nonlocal

  1. global

    • 功能一:在局部作用域声明一个全局变量。

      # 在局部作用域声明一个全局变量,
      name = 'alex'
      def func():
          global name
          name = '太白金星'
          print(name)
      func()  # 太白金星
      print(name)  # 太白金星
      
      # tip:
      name = 'alex'
      def func():
          global name
          name = '太白金星'
          print(name)
      print(name)  # 'alex', The function has not declared a global variable
      func()  # 太白金星
      
    • 功能二:对已经声明的全局变量进行修改

      # 对已经声明的全局变量进行修改
      count = 1
      def func():
          global count
          count += 1
      print(count)  # 1
      func()
      print(count)  # 2
      
  2. nonlocal(Python 3x)

    用于局部作用域,不能操作全局变量, 支持内层函数对外层函数的局部变量进行修改。

    def wrapper():
        count = 1
        def inner():
            nonlocal count
            count += 1
        print(count)  # 1
        inner()
        print(count)  # 2
    wrapper()
    

四、函数名的运用

  1. 函数名指代的是函数的内存地址

    def func():
        pass
    print(func, type(func))  # <function func at 0x000002B8B3E41F28> <class 'NoneType'>
    
  2. 函数名可以赋值给其他变量

    def func():
        pass
    f = func
    print(f, type(f))  # <function func at 0x000002B8B3E41F28> <class 'function'>
    
  3. 函数名可以作为容器型数据类型的元素

    def func1():
        print('in func1')
    def func2():
        print('in func2')
    def func3():
        print('in func3')
    l1 = [func1, func2, func3]
    for i in l1:
        i()
        
    # result:
    # in func1
    # in func2
    # in func3
    
  4. 函数名可以作为函数的参数

    def func():
        print('in func')
    
    def func1(x):
        x()
    
    func1(func)  # in func
    
  5. 函数名可以作为函数的返回值

    def func():
        print('in func')
    
    def func1(x):
        print('in func1')
        return x
    
    ret = func1(func)  # func1()
    ret()  # func()
    

五、Python 3.6 新特性:f-string

  1. 基本用法

    name = 'taibai'
    age = 18
    msg = f'my name is {name}, {age} years old.'
    print(msg)  # my name is taibai, 18 years old.
    
  2. 加入表达式

    dic = {'name': 'alex', 'age': 73}
    msg = f'my name is {dic["name"]}, {dic["age"]} years old.'
    print(msg) # my name is alex, 73 years old.
    
  3. 结合函数

    def _sum(a, b):
        return a + b
    
    msg = f'result is {_sum(10, 20)}'
    print(msg)  # result is 30
    
    # tips:
    # ! , : { } 不可以出现在{}里面,会出现报错
    
  4. 优点

    • 结构更加简化
    • 可以结合表达式、函数进行使用
    • 效率提升

六、迭代器

  1. 可迭代对象 iterate

    根据字面意思可以理解为:"可以重复取值,更新迭代的对象“。在python中,但凡内部含有“__iter__”方法的对象,都是可迭代对象。str list tuple dic set range file_handler 等都是可迭代对象。

  2. 查看对象内部方法 dic()

    dic() 是 directory 的缩写,会返回一个列表,这个列表中含有该对象的以字符串形式表示的所有方法名称,我们可以通过寻找返回列表内部是否具有'_iter_'来判断该对象是否是可迭代对象。

    s1 = 'asdf'
    s2 = 199
    attributes_s1 = dir(s1)
    attributes_s2 = dir(s2)
    print('__iter__' in attributes_s1)  # True
    print('__iter__' in attributes_s2)  # False
    
  3. iterate 的特点

    • 存储的数据可以直接显示,比较直观
    • 拥有方法比较多
    • 占用内存
    • 不能直接通过for循环,不能直接取值(索引,key除外),日常使用中for循环取值其实是依赖迭代器实现的
  4. 迭代器 iterator

    在python中,内部含有'_iter_'方法并且含有'__next__'方法的对象就是迭代器,现如今学习到的内容中,只有 file_handler 是迭代器。

    with open(r'file_handler.txt', encoding='utf-8', mode='w') as file_handler:
        print(('__iter__' and '__next__') in dir(file_handler))  # True
    
  5. 利用 iter() 将可迭代对象转化为迭代器

    s1 = 'dasd'
    obj = iter(s1)  # s1.__iter__() 是内置函数,两者都可生成迭代器
    # print(obj)  # <str_iterator object at 0x000001E9BA8B8828>
    print(next(obj))  # d 也可写作 print(obj.__next__())
    print(next(obj))  # a
    print(next(obj))  # s
    print(next(obj))  # d
    # print(next(obj))  # 警告: StopIteration
    
    # Exercise:
    l1 = [11, 22, 33, 44, 55, 66]
    obj = iter(l1)
    print(obj)  # <list_iterator object at 0x00000212C17286D8>
    print(next(obj))  # 11
    print(next(obj))  # 22
    print(next(obj))  # 33
    print(next(obj))  # 44
    print(next(obj))  # 55
    print(next(obj))  # 66
    
  6. iterator 的特点

    优点:

    • 节省内存
    • 惰性机制,next()一次只取一个值

    缺点:

    • 不能直观的查看里面的数据
    • 不走回头路,只能想下取值
  7. iterator 和 iterate 的对比

    • 可迭代对象 iterate:可迭代对象是一个操作方法比较多,比较直观,存储数据相对少的一个数据集。

      应用:当你侧重于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。

    • 迭代器 iterator:可迭代器是一个非常节省内存,可以记录取值位置,可以通过循环+next方法取值,但是不直观,操作方法比较单一的数据集(一个迭代器一定是可迭代对象)。

      应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择(可参考为什么Python把文件句柄设置为迭代器)

  8. while 模拟 for 循环

    list = [1, 2, 3, 4]
    # for i in list:
    #     pass
    iterator = iter(list)  # list.__iter__()
    while 1:
        try:
            i = next(iterator)  # iterator.__next__()
        except StopIteration:
            break
    
posted @ 2020-07-09 13:11  Raigor  阅读(98)  评论(0编辑  收藏  举报