• Python学习-函数名的应用、格式化输出、可迭代对象与迭代器


    记录下python中函数名的应用、格式化输出的其他写法、可迭代对象和迭代器的内容。

    函数名的应用

    在Python中,函数名有以下的用途:

    • 函数名指向的是内存地址,使用函数名+()就可以执行函数
    • 函数名就是变量,可以像基本数据类型一样进行赋值
    • 函数名可以作为容器型数据类型的元素
    • 函数名可以做为函数的参数
    • 函数名可以作为函数的返回值

    (1)函数名指向内存地址。

    def func():
        print('我是函数')
    
    print(func,type(func)) # <function func at 0x106ecb268> <class 'function'>
    

    (2)函数名是变量,可以赋值。

    def func():
        print('我是函数')
    
    # 函数名是变量
    f1=func
    f2=f1
    f3=f2
    # f3是可以执行的
    f3() # 我是函数
    

    (3)函数名可以作为容器型数据类型的元素,如列表、元祖、集合和字典就是容器型数据类型。

    def func1():
        print('I am func1')
    
    def func2():
        print('I am func2')
    
    def func3():
        print('I am func3')
    
    li=[func1,func2,func3]
    print(li) # [<function func1 at 0x106f89378>, <function func2 at 0x106f892f0>, <function func3 at 0x106f891e0>]
    

    (4)函数名可以作为函数的参数。

    def func(fn):
        fn()
    
    def print_circle():
        print('你特别喜欢画饼,可惜我吃不下')
    
    func(print_circle) # 你特别喜欢画饼,可惜我吃不下
    

    (5)函数名可以作为函数的返回值。

    def func1():
        print('这是func1')
        def func2():
            print('这是func2')
        print('这是func1')
        return func2
    
    fn=func1()
    fn()
    
    这是func1
    这是func1
    这是func2
    

    格式化输出

    前面学过,可使用%s占位符替换字符串、%d占位符替换数字、format进行格式化输出。

    favor=input('你的爱好是:')
    age=input('你的年龄是:')
    
    print('我的爱好是%s,今年我%s'%(favor,age))
    print('我的爱好是{},今年我{}'.format(favor,age))
    

    在python3.6之后,可以使用如下方式进行格式化输出,但! , : 等符号不能出现在大括号{}中,以后可结合lamda表达式使用。

    favor=input('你的爱好是:') 
    age=input('你的年龄是:') 
    
    print(f'我的爱好是{favor},今年我{age}')
    
    你的爱好是:football
    你的年龄是:18
    我的爱好是football,今年我18
    

    {}里可以加表达式、函数。

    # 1 可以加表达式
    dic={'favor':'football','age':18}
    print(f'我的爱好是{dic["favor"]},今年我{dic["age"]}') # 我的爱好是football,今年我18
    
    li=['football',18]
    print(f'我的爱好是{li[0]},今年我{li[1]}') # 我的爱好是football,今年我18
    
    print(f'我的爱好是{favor.upper()},今年我{age}') # 我的爱好是FOOTBALL,今年我18
    
    # 2 可以结合函数来写
    def my_sum(a,b):
        return  a+b
    
    print(f'和为:{my_sum(200,100)}') # 和为:300
    

    这种写法结构简单,一目了然,执行效率也更高。

    可迭代对象&迭代器

    包含基本概念说明、for循环机制、可迭代对象和迭代器优缺点总结。

    基本概念

    可迭代对象遵循可迭代协议,如str、list、tuple、dict、set都遵循均为可迭代对象,先看下面例子,str执行for循环没有报错,但是int类型的提示“TypeError: 'int' object is not iterable”,表明int不遵循可迭代协议。

    # 可迭代协议
    s='abc'
    for c in s:
        print(c)
    
    s=123
    for i in s:
        print(i)
        
    执行结果如下:
    Traceback (most recent call last):
      File "/Users/yangchaolin/pythonCode/day11/05 迭代器01.py", line 30, in <module>
        for i in s:
    TypeError: 'int' object is not iterable
    a
    b
    c
    

    内部含有'iter'方法的对象,就是可迭代对象,可以通过dir函数来查看,从下面代码可以看出str类型的对象含有此方法。

    # 查看一个对象的所有方法
    s1='messi'
    print(s1.__dir__())
    # 判断是否存在这个方法
    print('__iter__' in s1.__dir__())
    print('__iter__' in dir(s1))
    
    执行结果:
    ['__repr__', '__hash__', '__str__', '__getattribute__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__iter__', '__mod__', '__rmod__', '__len__', '__getitem__', '__add__', '__mul__', '__rmul__', '__contains__', '__new__', 'encode', 'replace', 'split', 'rsplit', 'join', 'capitalize', 'casefold', 'title', 'center', 'count', 'expandtabs', 'find', 'partition', 'index', 'ljust', 'lower', 'lstrip', 'rfind', 'rindex', 'rjust', 'rstrip', 'rpartition', 'splitlines', 'strip', 'swapcase', 'translate', 'upper', 'startswith', 'endswith', 'isascii', 'islower', 'isupper', 'istitle', 'isspace', 'isdecimal', 'isdigit', 'isnumeric', 'isalpha', 'isalnum', 'isidentifier', 'isprintable', 'zfill', 'format', 'format_map', '__format__', 'maketrans', '__sizeof__', '__getnewargs__', '__doc__', '__setattr__', '__delattr__', '__init__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__dir__', '__class__']
    True
    True
    

    此外,还可以通过isinstance()函数查看对象是什么类型,可以看出str是可迭代对象,但是不是迭代器。

    # 查看对象类型,python3.8之前可以这么导入
    from collections import Iterable 
    from collections import Iterator
    s='messi'
    print(isinstance(s,Iterable))
    print(isinstance(s,Iterator))
    
    执行结果:
    True
    False
    

    什么是迭代器呢,将可迭代对象通过iter()函数进行转换,内部除了含有'iter'方法,还含有'next'方法,就是迭代器,也可以通过以上两种方式判断是否是迭代器。

    # 可迭代对象转换为迭代器,并判断类型
    s='messi'
    # 以下两种写法都可以
    s_iter=s.__iter__()
    # s_iter=iter(s) 
    print('__iter__' in s_iter.__dir__()) # True
    print('__next__' in s_iter.__dir__()) # True
    

    通过'next'方法,可以获取到迭代器中的元素。

    # 列表转换为迭代器,然后对迭代器循环打印
    li=['messi','ronald','herry']
    it=iter(li)
    # 循环控制次数
    for index in range(len(li)):
        print(next(it))
        
     执行结果:
     messi
     ronald
     herry
    

    for循环机制

    可迭代对象是不能直接取值的,但列表通过for循环可以获取到值,这其实是内部进行了转换,将列表转化成了一个迭代器。

    li=[1,2,3,4]
    print('__iter__' in li.__dir__()) # True,说明列表就是可迭代对象
    print('__next__' in dir(li)) # False,说明不是迭代器
    for num in li:
        print(num)
    

    可以使用while循环+迭代器来模拟for循环。

    li=[1,2,3,4]
    li_iter=iter(li)
    while True:
        try:
            i=li_iter.__next__()
            print(i)
        except StopIteration:
            break
    

    获取元素特点

    迭代器的next函数执行是不走回头路的,执行一次,就走到下一个元素。next一次只取一个元素,这就是迭代器的惰性机制。从下面的例子可以看出,迭代器it执行7次next取值后,后面再执行3次,发现不从开头取值,而是接着从下个元素开始取值。

    # 不走回头路
    li=[0,1,2,3,4,5,6,77,88,99]
    it=iter(li)
    for i in range(7):
        print(it.__next__())
    
    print('----分割线----')
    
    for i in range(3):
        print(next(it))
        
    执行结果:
    0
    1
    2
    3
    4
    5
    6
    ----分割线----
    77
    88
    99
    

    然而,可迭代对象是可以走回头路的。

    count=0
    for item in li:
        if count==7:
            break
        else:
            print(item)
        count+=1
    print('----分割线----')
    count=0
    for item in li:
        if count==3:
            break
        else:
            print(item)
        count+=1
        
     执行结果:
     0
     1
     2
     3
     4
     5
     6
     ----分割线----
     0
     1
     2
    

    两者特点

    • 可迭代对象优点:存储数据相对较少,操作方法比较多,看上去比较具体。
    • 可迭代对象缺点:当内存足够多,侧重于对数据的灵活处理,可以使用它。
    • 迭代器优点:当数据量太大可能撑爆内存时,就可以考虑使用迭代器了,它的惰性机制可以有效的规避撑爆风险。
    • 迭代器缺点:通过next方法取值,可以记录位置,但是操作方法比较单一。

    相关练习

    (1)看代码写结果,主要理解函数名的使用。

    def func1():
        print('I am func1')
    
    def func2(x):
        print('I am func2')
        return x
    
    def func3(y):
        print('I am func3')
        return y
    
    ret=func2(func1)
    ret()
    ret2=func3(func2)
    ret3=ret2(func1)
    ret3()
    
    执行结果:
    I am func2
    I am func1
    I am func3
    I am func2
    I am func1
    

    (2)看代码写结果,理解列表为全局命名空间的,方法操作的都是这个li。

    li=[]
    def func(args):
        li.append(args)
        return li
    print(func(1))
    print(func(2))
    print(func(3))
    
    执行结果:
    [1]
    [1, 2]
    [1, 2, 3]
    

    (3)看代码写结果,这里主要理解方法的默认参数,l1和l3,其实指向的都是默认参数里的列表,而l2指向的是一个新的列表,所以最后结果会是l1和l3一样。

    def magic_list(s,li=[]):
        li.append(s)
        return li
    
    l1=magic_list(100,)
    l2=magic_list('messi',[])
    l3=magic_list('ronald',)
    
    print(f'l1的结果是{l1}')
    print(f'l2的结果是{l2}')
    print(f'l3的结果是{l3}')
    
    执行结果:
    l1的结果是[100, 'ronald']
    l2的结果是['messi']
    l3的结果是[100, 'ronald']
    

    (4)写一个函数,返回除大小王之外的52张扑克牌,每一项是一个字典[{'红心':2},{'黑桃':1},…],这个主要是体会迭代器的使用。

    shape=['红心','黑桃','梅花','方块']
    number=[1,2,3,4,5,6,7,8,9,10,'j','Q','K']
    shape_it=iter(shape)
    li=[]
    for i in range(len(shape)):
        s=shape_it.__next__()
        # 下面for循环完后,不能回头,因此需要临时再新建对象
        number_it = iter(number)
        for j in range(len(number)):
            dic={}
            dic[s]=next(number_it)
            li.append(dic)
    print(li)
    
    执行结果:
    [{'红心': 1}, {'红心': 2}, {'红心': 3}, {'红心': 4}, {'红心': 5}, {'红心': 6}, {'红心': 7}, {'红心': 8}, {'红心': 9}, {'红心': 10}, {'红心': 'j'}, {'红心': 'Q'}, {'红心': 'K'}, {'黑桃': 1}, {'黑桃': 2}, {'黑桃': 3}, {'黑桃': 4}, {'黑桃': 5}, {'黑桃': 6}, {'黑桃': 7}, {'黑桃': 8}, {'黑桃': 9}, {'黑桃': 10}, {'黑桃': 'j'}, {'黑桃': 'Q'}, {'黑桃': 'K'}, {'梅花': 1}, {'梅花': 2}, {'梅花': 3}, {'梅花': 4}, {'梅花': 5}, {'梅花': 6}, {'梅花': 7}, {'梅花': 8}, {'梅花': 9}, {'梅花': 10}, {'梅花': 'j'}, {'梅花': 'Q'}, {'梅花': 'K'}, {'方块': 1}, {'方块': 2}, {'方块': 3}, {'方块': 4}, {'方块': 5}, {'方块': 6}, {'方块': 7}, {'方块': 8}, {'方块': 9}, {'方块': 10}, {'方块': 'j'}, {'方块': 'Q'}, {'方块': 'K'}]
    

    (5)python版本的九九乘法表。

    for i in range(1,10,1):
        s=''
        for j in range(1,i+1,1):
            if j!=i:
                # 不到最后,需要用分隔符隔开
                s+=str(i)+'*'+str(j)+'='+str(i*j)+'	'
            else:
                # 到了最后,不需要用分隔符隔开
                s+=str(i)+'*'+str(j)+'='+str(i*j)
        # 打印
        print(s)
        
     执行结果:
     1*1=1
     2*1=2	2*2=4
     3*1=3	3*2=6	3*3=9
     4*1=4	4*2=8	4*3=12	4*4=16
     5*1=5	5*2=10	5*3=15	5*4=20	5*5=25
     6*1=6	6*2=12	6*3=18	6*4=24	6*5=30	6*6=36
     7*1=7	7*2=14	7*3=21	7*4=28	7*5=35	7*6=42	7*7=49
     8*1=8	8*2=16	8*3=24	8*4=32	8*5=40	8*6=48	8*7=56	8*8=64
     9*1=9	9*2=18	9*3=27	9*4=36	9*5=45	9*6=54	9*7=63	9*8=72	9*9=81
    

    PS:以上,理解不一定正确,学习就是一个不断认识和纠错的过程,如果有误还请批评指正。

    参考博文:

    (1)https://www.cnblogs.com/pingwen/p/12634614.html 容器型数据类型

    (2)https://www.cnblogs.com/youngchaolin/p/12323797.html#_label2_10 format格式化

    (3)https://www.cnblogs.com/youngchaolin/p/10963219.html#_label1 %s %d

  • 相关阅读:
    Python面试
    PyCharm快捷键
    PyCharm安装及使用
    Python环境搭建
    MYSQL的cmake编译单实例安装
    lamp和lnmp环境的搭建
    模拟解决DOS攻击的shell脚本
    责任链模式
    迭代器模式
    备忘录设计模式
  • 原文地址:https://www.cnblogs.com/youngchaolin/p/15196219.html
Copyright © 2020-2023  润新知