1. 程式人生 > 其它 >Python學習-函式名的應用、格式化輸出、可迭代物件與迭代器

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)+'\t'
        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