python3 陌生的角落(3):條件、迭代、模塊、文件輸入輸出

1.print() sep 參數使用

>>> a=10;b=388;c=98
>>> print(a,b,c,sep='@')
10@388@98

2.while 循環使用 else 語句

在 while … else 在條件語句爲 false 時執行 else 的語句塊:

實例
#!/usr/bin/python3

count = 0
while count < 5:
   print (count, " 小於 5")
   count = count + 1
else:
   print (count, " 大於或等於 5")

執行以上腳本,輸出結果如下:

0  小於 5
1  小於 5
2  小於 5
3  小於 5
4  小於 5
5  大於或等於 5

3.使用內置 enumerate 函數進行遍歷:

for index, item in enumerate(sequence):
    process(index, item)
實例
>>> sequence = [12, 34, 34, 23, 45, 76, 89]
>>> for i, j in enumerate(sequence):
...     print(i, j)
... 
0 12
1 34
2 34
3 23
4 45
5 76
6 89

4.迭代器

迭代器有兩個基本的方法:iter() 和 next()。
字符串,列表或元組對象都可用於創建迭代器:
實例(Python 3.0+)

>>>list=[1,2,3,4]
>>> it = iter(list)    # 創建迭代器對象
>>> print (next(it))   # 輸出迭代器的下一個元素
1
>>> print (next(it))
2
>>>

5.生成器

在 Python 中,使用了 yield 的函數被稱爲生成器(generator)。
跟普通函數不同的是,生成器是一個返回迭代器的函數,只能用於迭代操作,更簡單點理解生成器就是一個迭代器。
在調用生成器運行的過程中,每次遇到 yield 時函數會暫停並保存當前所有的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行。
調用一個生成器函數,返回的是一個迭代器對象。
以下實例使用 yield 實現斐波那契數列:

實例(Python 3.0+)
#!/usr/bin/python3

import sys

def fibonacci(n): # 生成器函數 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一個迭代器,由生成器返回生成

while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()

執行以上程序,輸出結果如下:

0 1 1 2 3 5 8 13 21 34 55

下一個代碼更有利於你理解代碼:

import sys

    def fibonacci(n):  # 生成器函數 - 斐波那契
        a, b, counter = 0, 1, 0
        while True:
            if (counter > n):
                return
            # yield a
            a, b = b, a + b
            print(a,"=====",b)
            counter += 1

    f = fibonacci(10)  # f 是一個迭代器,由生成器返回生成

    # while True:
    #     try:
    #         print(next(f), end=" ")
    #     except StopIteration:
    #         sys.exit()

結果如下:

1 ===== 1
1 ===== 2
2 ===== 3
3 ===== 5
5 ===== 8
8 ===== 13
13 ===== 21
21 ===== 34
34 ===== 55
55 ===== 89
89 ===== 144
  • 打個比方的話,yield有點像斷點。 加了yield的函數,每次執行到有yield的時候,會返回yield後面的值 並且函數會暫停,直到下次調用或迭代終止;
  • yield後面可以加多個數值(可以是任意類型),但返回的值是元組類型的。
    我們可以得出以下結論:
    一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用 next()(在 for 循環中會自動調用 next())纔開始執行。雖然執行流程仍按函數的流程執行,但每執行到一個 yield 語句就會中斷,並返回一個迭代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函數在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。
    yield 的好處是顯而易見的,把一個函數改寫爲一個 generator 就獲得了迭代能力,比起用類的實例保存狀態來計算下一個 next() 的值,不僅代碼簡潔,而且執行流程異常清晰。
    如何判斷一個函數是否是一個特殊的 generator 函數?可以利用 isgeneratorfunction 判斷:
>>>from inspect import isgeneratorfunction 
>>> isgeneratorfunction(fab) 
True

return 的作用
在一個 generator function 中,如果沒有 return,則默認執行至函數完畢,如果在執行過程中 return,則直接拋出 StopIteration 終止迭代。

6.可更改(mutable)與不可更改(immutable)對象-可看可不看

在 python 中,strings, tuples, 和 numbers 是不可更改的對象,而 list,dict 等則是可以修改的對象。
不可變類型:變量賦值 a=5 後再賦值 a=10,這裏實際是新生成一個 int 值對象 10,再讓 a 指向它,而 5 被丟棄,不是改變a的值,相當於新生成了a。
可變類型:變量賦值 la=[1,2,3,4] 後再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了。
python 函數的參數傳遞:
不可變類型:類似 c++ 的值傳遞,如 整數、字符串、元組。如fun(a),傳遞的只是a的值,沒有影響a對象本身。比如在 fun(a)內部修改 a 的值,只是修改另一個複製的對象,不會影響 a 本身。
可變類型:類似 c++ 的引用傳遞,如 列表,字典。如 fun(la),則是將 la 真正的傳過去,修改後fun外部的la也會受影響

python 中一切都是對象,嚴格意義我們不能說值傳遞還是引用傳遞,我們應該說傳不可變對象和傳可變對象。

7.不定長參數

加了星號(*)的變量名會存放所有未命名的變量參數。如果在函數調用時沒有指定參數,它就是一個空元組。我們也可以不向函數傳遞未命名的變量。如下實例:

# 可寫函數說明
def printinfo( age=35,name):   # 默認參數不在最後,會報錯
    "打印任何傳入的字符串"
    print("名字: ", name);
    print("年齡: ", age);
    return;
#!/usr/bin/python3

# 可寫函數說明
def printinfo( arg1, *vartuple ):
   "打印任何傳入的參數"
   print ("輸出: ")
   print (arg1)
   for var in vartuple:
      print (var)
   return;

# 調用printinfo 函數
printinfo( 10 );
printinfo( 70, 60, 50 );
#以上實例輸出結果:
輸出:
10
輸出:
70
60
50

8.變量作用域

以 L –> E –> G –>B 的規則查找,即:在局部找不到,便會去局部外的局部找(例如閉包),再找不到就會去全局找,再者去內建中找。

x = int(2.9)  # 內建作用域

g_count = 0  # 全局作用域
def outer():
    o_count = 1  # 閉包函數外的函數中
    def inner():
        i_count = 2  # 局部作用域

全局變量global 和局部變量nonlocal

  • 當內部作用域想修改外部作用域的變量時,就要用到global和nonlocal關鍵字了。
    以下實例修改全局變量 num:
num = 1

def fun1():
    #global num  # 需要使用 global 關鍵字聲明
    num =123 
    print(num)   # 123
    f = 123 + num 
    print(f)  # 124

fun1()
print(num)  # 1

添加後global 關鍵字後。

num = 1

def fun1():
    global num  # 需要使用 global 關鍵字聲明
    num =123
    print(num)   # 123
    f = 123 + num
    print(f)  # 124

fun1()
print(num)  # 123
  • 如果要修改嵌套作用域(enclosing 作用域,外層非全局作用域)中的變量則需要 nonlocal 關鍵字了,如下實例:
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal關鍵字聲明
        num = 100
        print(num)
    inner()
    print(num)
outer()

輸出結果:

100
100

屏蔽nonlocal關鍵字後,看一下效果。

def outer():
    num = 10
    def inner():
        #nonlocal num   # nonlocal關鍵字聲明
        num = 100
        print(num)
    inner()
    print(num)
outer()

結果如下:

100
10
  • 特殊情況
a = 10
def test():
    c = a + 1
    print(c)
test()

結果:11。


a = 10
def test():
    a = a + 1
    print(a)
test()

報錯:

Traceback (most recent call last):
  File "D:/depthStudyWorks/18FirstYear/code/test.py", line 75, in <module>
    test()
  File "D:/depthStudyWorks/18FirstYear/code/test.py", line 73, in test
    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

錯誤信息爲局部作用域引用錯誤,因爲 test 函數中的 a 使用的是局部,未定義,無法修改。(等號右邊的a沒有定義)

9.列表推導式

列表推導式提供了從序列創建列表的簡單途徑。通常應用程序將一些操作應用於某個序列的每個元素,用其獲得的結果作爲生成新列表的元素,或者根據確定的判定條件創建子序列。

>>> vec = [2, 4, 6]
>>> [3*x for x in vec]
[6, 12, 18]
#現在我們玩一點小花樣:
>>> [[x, x**2] for x in vec]
[[2, 4], [4, 16], [6, 36]]

我們可以用 if 子句作爲過濾器:

>>> [3*x for x in vec if x > 3]
[12, 18]
>>> [3*x for x in vec if x < 2]
[]

以下是一些關於循環和其它技巧的演示:

>>> vec1 = [2, 4, 6]
>>> vec2 = [4, 3, -9]
>>> [x*y for x in vec1 for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>>> [x+y for x in vec1 for y in vec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
>>> [vec1[i]*vec2[i] for i in range(len(vec1))]
[8, 12, -54]
  • 嵌套列表解析
>>> matrix = [
...     [1, 2, 3, 4],
...     [5, 6, 7, 8],
...     [9, 10, 11, 12],
... ]
以下實例將3X4的矩陣列表轉換爲4X3列表:
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

層疊式循環推導式:

l = []
    for x in range(1, 5):
        if x > 2:
            for y in range(1, 4):
                if y < 3:
                    l.append(x * y)
    print(l)
    print([x * y for x in range(1, 5) if x > 2 for y in range(1, 4) if y < 3])

結果:

[3, 6, 4, 8]
[3, 6, 4, 8]
  • 關於嵌套列表解析
    從左到右的for語句順序對應的是從外到裏的層次關係。上面有些筆記是用優先級來解析,這樣是不太合理的,不便於理解。
    最左側的表達式可以直接使用後面出現的變量,而不是只限於相連的for,所以結合上面的結論。例子還可以寫 [row[i] for i in range(4) for row in matrix],效果一樣。
    例子爲何不用()來改變嵌套的層次關係而用 [],因爲 python 解析器會把 (row[i] for row in matrix) 解析爲一個 生成器 generator。這裏舉一個例子
>>> (i for i in range(4))
<generator object <genexpr> at 0x110114360>
>>> [i for i in range(4)]
[0, 1, 2, 3]
>>> a = (i for i in range(4))
>>> next(a)
0
>>> next(a)
1
>>>

10.遍歷技巧

在序列中遍歷時,索引位置和對應值可以使用 enumerate() 函數同時得到:

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print(i, v)
...
0 tic
1 tac
2 toe

在字典中遍歷時,關鍵字和對應的值可以使用 items() 方法同時解讀出來:

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
...
gallahad the pure
robin the brave

同時遍歷兩個或更多的序列,可以使用 zip() 組合:

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('what is your %s? it is %s' % (q, a))
        print('--------------------------')
        print('what is your {0}? it is {1}'.format(q, a))
...
what is your name? it is qinshihuang
--------------------------
what is your name? it is qinshihuang
what is your quest? it is the holy
--------------------------
what is your quest? it is the holy
what is your favorite color? it is blue
--------------------------
what is your favorite color? it is blue

11.輸出格式美化

如果你希望輸出的形式更加多樣,可以使用 str.format() 函數來格式化輸出值。
如果你希望將輸出的值轉成字符串,可以使用 repr() 或 str() 函數來實現。

>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # 注意前一行 'end' 的使用
...     print(repr(x*x*x).rjust(4))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

這個例子展示了字符串對象的 rjust() 方法, 它可以將字符串靠右, 並在左邊填充空格。
還有類似的方法, 如 ljust() 和 center()。

>>> print('{0} 和 {1}'.format('Google', 'Runoob'))
Google 和 Runoob
>>> print('{1} 和 {0}'.format('Google', 'Runoob'))
Runoob 和 Google
#如果在 format() 中使用了關鍵字參數, 那麼它們的值會指向使用該名字的參數。
>>> print('{name}網址: {site}'.format(name='菜鳥教程', site='www.runoob.com'))
菜鳥教程網址: www.runoob.com
#位置及關鍵字參數可以任意的結合:
>>> print('站點列表 {0}, {1}, 和 {other}。'.format('Google', 'Runoob',
                                                       other='Taobao'))
站點列表 Google, Runoob, 和 Taobao。

12.pickle 模塊

python的pickle模塊實現了基本的數據序列和反序列化。
通過pickle模塊的序列化操作我們能夠將程序中運行的對象信息保存到文件中去,永久存儲。
通過pickle模塊的反序列化操作,我們能夠從文件中創建上一次程序保存的對象。
基本接口:

pickle.dump(obj, file, [,protocol])
#有了 pickle 這個對象, 就能對 file 以讀取的形式打開:
x = pickle.load(file)

這裏不詳細,以後添加。。。

13.File writelines() 方法

writelines() 方法用於向文件中寫入一序列的字符串。
這一序列字符串可以是由迭代對象產生的,如一個字符串列表。
換行需要制定換行符 \n。
語法
writelines() 方法語法如下:

fileObject.writelines( [ str ])

參數
str – 要寫入文件的字符串序列。

##實例
##以下實例演示了 writelines() 方法的使用:
#!/usr/bin/python3

# 打開文件
fo = open("test.txt", "w")
print ("文件名爲: ", fo.name)
seq = ["菜鳥教程 1\n", "菜鳥教程 2"]
fo.writelines( seq )

# 關閉文件
fo.close()

#以上實例輸出結果爲:

#文件名爲:  test.txt
發佈了67 篇原創文章 · 獲贊 22 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章