python3學習筆記(二)

一、Python3 編程第一步

在前面的教程中咱們已經學習了一些 Python3 的基本語法知識,下面咱們嘗試來寫一個斐波納契數列。html

實例(Python 3.0+)python

# Fibonacci series: 斐波納契數列
# 兩個元素的總和肯定了下一個數
a, b = 0, 1
while b < 10:
    print(b)
    a, b = b, a+b複製代碼

其中代碼 a, b = b, a+b 的計算方式爲先計算右邊表達式,而後同時賦值給左邊,等價於:linux

n=b
m=a+b
a=n
b=m複製代碼

執行以上程序,輸出結果爲:c++

1
1
2
3
5
8複製代碼

這個例子介紹了幾個新特徵。程序員

第一行包含了一個複合賦值:變量 a 和 b 同時獲得新值 0 和 1。最後一行再次使用了一樣的方法,能夠看到,右邊的表達式會在賦值變更以前執行。右邊表達式的執行順序是從左往右的。express

輸出變量值:編程

>>> i = 256*256
>>> print('i 的值爲:', i)
i 的值爲: 65536複製代碼

1. end 關鍵字

關鍵字end能夠用於將結果輸出到同一行,或者在輸出的末尾添加不一樣的字符,實例以下:api

實例(Python 3.0+)bash

# Fibonacci series: 斐波納契數列
# 兩個元素的總和肯定了下一個數
a, b = 0, 1
while b < 1000:
    print(b, end=',')
    a, b = b, a+b複製代碼

執行以上程序,輸出結果爲:服務器

1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,複製代碼

二、Python3 條件控制

Python 條件語句是經過一條或多條語句的執行結果(True 或者 False)來決定執行的代碼塊。

1. if 語句

Python中if語句的通常形式以下所示:

if condition_1: statement_block_1 elif condition_2: statement_block_2 else: statement_block_3
  • 若是 "condition_1" 爲 True 將執行 "statement_block_1" 塊語句
  • 若是 "condition_1" 爲False,將判斷 "condition_2"
  • 若是"condition_2" 爲 True 將執行 "statement_block_2" 塊語句
  • 若是 "condition_2" 爲False,將執行"statement_block_3"塊語句

Python 中用 elif 代替了 else if,因此if語句的關鍵字爲:if – elif – else

注意:

  • 一、每一個條件後面要使用冒號 :,表示接下來是知足條件後要執行的語句塊。
  • 二、使用縮進來劃分語句塊,相同縮進數的語句在一塊兒組成一個語句塊。
  • 三、在Python中沒有switch – case語句。

實例

var1 = 100
if var1:
    print ("1 - if 表達式條件爲 true")
    print (var1)
 
var2 = 0
if var2:
    print ("2 - if 表達式條件爲 true")
    print (var2)
print ("Good bye!")複製代碼

執行以上代碼,輸出結果爲:

1 - if 表達式條件爲 true
100
Good bye!
複製代碼

從結果能夠看到因爲變量 var2 爲 0,因此對應的 if 內的語句沒有執行。

如下實例演示了狗的年齡計算判斷:

實例

age = int(input("請輸入你家狗狗的年齡: "))
print("")
if age <= 0:
    print("你是在逗我吧!")
elif age == 1:
    print("至關於 14 歲的人。")
elif age == 2:
    print("至關於 22 歲的人。")
elif age > 2:
    human = 22 + (age -2)*5
    print("對應人類年齡: ", human)
 
### 退出提示
input("點擊 enter 鍵退出")複製代碼

將以上腳本保存在dog.py文件中,並執行該腳本:

$ python3 dog.py 
請輸入你家狗狗的年齡: 1

至關於 14 歲的人。
點擊 enter 鍵退出
複製代碼

如下爲if中經常使用的操做運算符:

操做符 描述
< 小於
<= 小於或等於
> 大於
>= 大於或等於
== 等於,比較兩個值是否相等
!= 不等於

實例

# 程序演示了 == 操做符
# 使用數字
print(5 == 6)
# 使用變量
x = 5
y = 8
print(x == y)複製代碼

以上實例輸出結果:

False
False
複製代碼

high_low.py文件演示了數字的比較運算:

實例

# 該實例演示了數字猜謎遊戲
number = 7
guess = -1
print("數字猜謎遊戲!")
while guess != number:
    guess = int(input("請輸入你猜的數字:"))
 
    if guess == number:
        print("恭喜,你猜對了!")
    elif guess < number:
        print("猜的數字小了...")
    elif guess > number:
        print("猜的數字大了...")複製代碼

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

$ python3 high_low.py 
數字猜謎遊戲!
請輸入你猜的數字:1
猜的數字小了...
請輸入你猜的數字:9
猜的數字大了...
請輸入你猜的數字:7
恭喜,你猜對了!
複製代碼

2. if 嵌套

在嵌套 if 語句中,能夠把 if...elif...else 結構放在另一個 if...elif...else 結構中。

if 表達式1:
    語句
    if 表達式2:
        語句
    elif 表達式3:
        語句
    else:
        語句
elif 表達式4:
    語句
else:
    語句
複製代碼

實例

num=int(input("輸入一個數字:"))
if num%2==0:
    if num%3==0:
        print ("你輸入的數字能夠整除 2 和 3")
    else:
        print ("你輸入的數字能夠整除 2,但不能整除 3")
else:
    if num%3==0:
        print ("你輸入的數字能夠整除 3,但不能整除 2")
    else:
        print  ("你輸入的數字不能整除 2 和 3")複製代碼

將以上程序保存到 test_if.py 文件中,執行後輸出結果爲:

$ python3 test.py 
輸入一個數字:6
你輸入的數字能夠整除 2 和 3複製代碼

三、Python3 循環語句

本章節將爲你們介紹 Python 循環語句的使用。

Python 中的循環語句有 for 和 while。

1. while 循環

Python 中 while 語句的通常形式:

while 判斷條件(condition):
    執行語句(statements)……複製代碼

一樣須要注意冒號和縮進。另外,在 Python 中沒有 do..while 循環。

如下實例使用了 while 來計算 1 到 100 的總和:

實例

n = 100
 
sum = 0
counter = 1
while counter <= n:
    sum = sum + counter
    counter += 1
 
print("1 到 %d 之和爲: %d" % (n,sum))複製代碼

執行結果以下:

1 到 100 之和爲: 5050複製代碼

無限循環

咱們能夠經過設置條件表達式永遠不爲 false 來實現無限循環,實例以下:

實例

var = 1
while var == 1 :  # 表達式永遠爲 true
   num = int(input("輸入一個數字 :"))
   print ("你輸入的數字是: ", num)
 
print ("Good bye!")複製代碼

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

輸入一個數字  :5
你輸入的數字是:  5
輸入一個數字  :複製代碼

你可使用 CTRL+C 來退出當前的無限循環。

無限循環在服務器上客戶端的實時請求很是有用。

2. while 循環使用 else 語句

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

語法格式以下:

while <expr>:
    <statement(s)>
else:
    <additional_statement(s)>複製代碼

循環輸出數字,並判斷大小:

實例

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複製代碼

簡單語句組

相似if語句的語法,若是你的while循環體中只有一條語句,你能夠將該語句與while寫在同一行中, 以下所示:

實例

flag = 1
 
while (flag): print ('歡迎訪問菜鳥教程!')
 
print ("Good bye!")複製代碼

注意:以上的無限循環你可使用 CTRL+C 來中斷循環。

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

歡迎訪問菜鳥教程!
歡迎訪問菜鳥教程!
歡迎訪問菜鳥教程!
歡迎訪問菜鳥教程!
歡迎訪問菜鳥教程!
……複製代碼

2. for 語句

Python for循環能夠遍歷任何序列的項目,如一個列表或者一個字符串。

for循環的通常格式以下:

for <variable> in <sequence>:
    <statements>
else:
    <statements>複製代碼

Python for 循環實例:

實例

>>>languages = ["C", "C++", "Perl", "Python"] 
>>> for x in languages:
...     print (x)
... 
C
C++
Perl
Python
>>>複製代碼

如下 for 實例中使用了 break 語句,break 語句用於跳出當前循環體:

實例

sites = ["Baidu", "Google","Runoob","Taobao"]
for site in sites:
    if site == "Runoob":
        print("菜鳥教程!")
        break
    print("循環數據 " + site)
else:
    print("沒有循環數據!")
print("完成循環!")複製代碼

執行腳本後,在循環到 "Runoob"時會跳出循環體:

循環數據 Baidu
循環數據 Google
菜鳥教程!
完成循環!複製代碼

4. range()函數

若是你須要遍歷數字序列,可使用內置range()函數。它會生成數列,例如:

實例

>>>for i in range(5):
...     print(i)
...
0
1
2
3
4複製代碼

你也可使用range指定區間的值:

實例

>>>for i in range(5,9) :
    print(i)
 
    
5
6
7
8
>>>複製代碼

也可使range以指定數字開始並指定不一樣的增量(甚至能夠是負數,有時這也叫作'步長'):

實例

>>>for i in range(0, 10, 3) :
    print(i)
 
    
0
3
6
9
>>>複製代碼

負數:

實例

>>>for i in range(-10, -100, -30) :
    print(i)
 
    
-10
-40
-70
>>>複製代碼

您能夠結合range()和len()函數以遍歷一個序列的索引,以下所示:

實例

>>>a = ['Google', 'Baidu', 'Runoob', 'Taobao', 'QQ']
>>> for i in range(len(a)):
...     print(i, a[i])
... 
0 Google
1 Baidu
2 Runoob
3 Taobao
4 QQ
>>>複製代碼

還可使用range()函數來建立一個列表:

實例

>>>list(range(5))
[0, 1, 2, 3, 4]
>>>複製代碼

5. break 和 continue 語句及循環中的 else 子句

break 執行流程圖:

continue 執行流程圖:

代碼執行過程:

break 語句能夠跳出 for 和 while 的循環體。若是你從 for 或 while 循環中終止,任何對應的循環 else 塊將不執行。

continue 語句被用來告訴 Python 跳過當前循環塊中的剩餘語句,而後繼續進行下一輪循環。

實例

while 中使用 break:

實例

n = 5
while n > 0:    
    n -= 1    
    if n == 2:        
        break    
    print(n)
print('循環結束。')複製代碼

輸出結果爲:

4
3
循環結束。複製代碼

while 中使用 continue:

實例

n = 5
while n > 0:    
    n -= 1    
    if n == 2:        
        continue    
    print(n)
print('循環結束。')複製代碼

輸出結果爲:

4
3
1
0
循環結束。複製代碼

更多實例以下:

實例

for letter in 'Runoob':     # 第一個實例
   if letter == 'b':
      break
   print ('當前字母爲 :', letter)
  
var = 10                    # 第二個實例
while var > 0:              
   print ('當期變量值爲 :', var)
   var = var -1
   if var == 5:
      break
 
print ("Good bye!")複製代碼

執行以上腳本輸出結果爲:

當前字母爲 : R
當前字母爲 : u
當前字母爲 : n
當前字母爲 : o
當前字母爲 : o
當期變量值爲 : 10
當期變量值爲 : 9
當期變量值爲 : 8
當期變量值爲 : 7
當期變量值爲 : 6
Good bye!複製代碼

如下實例循環字符串 Runoob,碰到字母 o 跳過輸出:

實例

for letter in 'Runoob':     # 第一個實例
   if letter == 'o':        # 字母爲 o 時跳過輸出
      continue
   print ('當前字母 :', letter)
 
var = 10                    # 第二個實例
while var > 0:              
   var = var -1
   if var == 5:             # 變量爲 5 時跳過輸出
      continue
   print ('當前變量值 :', var)
print ("Good bye!")複製代碼

執行以上腳本輸出結果爲:

當前字母 : R
當前字母 : u
當前字母 : n
當前字母 : b
當前變量值 : 9
當前變量值 : 8
當前變量值 : 7
當前變量值 : 6
當前變量值 : 4
當前變量值 : 3
當前變量值 : 2
當前變量值 : 1
當前變量值 : 0
Good bye!複製代碼

循環語句能夠有 else 子句,它在窮盡列表(以for循環)或條件變爲 false (以while循環)致使循環終止時被執行,但循環被 break 終止時不執行。

以下實例用於查詢質數的循環例子:

實例

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, '等於', x, '*', n//x)
            break
    else:
        # 循環中沒有找到元素
        print(n, ' 是質數')複製代碼

執行以上腳本輸出結果爲:

2  是質數
3  是質數
4 等於 2 * 2
5  是質數
6 等於 2 * 3
7  是質數
8 等於 2 * 4
9 等於 3 * 3複製代碼

6. pass 語句

Python pass是空語句,是爲了保持程序結構的完整性。

pass 不作任何事情,通常用作佔位語句,以下實例

實例

>>>while True:
...     pass  # 等待鍵盤中斷 (Ctrl+C)複製代碼

最小的類:

實例

>>>class MyEmptyClass:
...     pass複製代碼

如下實例在字母爲 o 時 執行 pass 語句塊:

實例

for letter in 'Runoob': 
   if letter == 'o':
      pass
      print ('執行 pass 塊')
   print ('當前字母 :', letter)
 
print ("Good bye!")複製代碼

執行以上腳本輸出結果爲:

當前字母 : R
當前字母 : u
當前字母 : n
執行 pass 塊
當前字母 : o
執行 pass 塊
當前字母 : o
當前字母 : b
Good bye!複製代碼

四、Python3 迭代器與生成器

1. 迭代器

迭代是Python最強大的功能之一,是訪問集合元素的一種方式。

迭代器是一個能夠記住遍歷的位置的對象。

迭代器對象從集合的第一個元素開始訪問,直到全部的元素被訪問完結束。迭代器只能往前不會後退。

迭代器有兩個基本的方法:iter()next()

字符串,列表或元組對象均可用於建立迭代器:

實例(Python 3.0+)

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

迭代器對象可使用常規for語句進行遍歷:

實例(Python 3.0+)

list=[1,2,3,4]
it = iter(list)    # 建立迭代器對象
for x in it:
    print (x, end=" ")複製代碼

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

1 2 3 4複製代碼

也可使用 next() 函數:

實例(Python 3.0+)

import sys         # 引入 sys 模塊
 
list=[1,2,3,4]
it = iter(list)    # 建立迭代器對象
 
while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()複製代碼

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

1
2
3
4複製代碼

2. 建立一個迭代器

把一個類做爲一個迭代器使用須要在類中實現兩個方法 __iter__() 與 __next__() 。

若是你已經瞭解的面向對象編程,就知道類都有一個構造函數,Python 的構造函數爲 __init__(), 它會在對象初始化的時候執行。

更多內容查閱:Python3 面向對象

__iter__() 方法返回一個特殊的迭代器對象, 這個迭代器對象實現了 __next__() 方法並經過 StopIteration 異常標識迭代的完成。

__next__() 方法(Python 2 裏是 next())會返回下一個迭代器對象。

建立一個返回數字的迭代器,初始值爲 1,逐步遞增 1:

實例(Python 3.0+)

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass)
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))複製代碼

執行輸出結果爲:

1
2
3
4
5複製代碼

3. StopIteration

StopIteration 異經常使用於標識迭代的完成,防止出現無限循環的狀況,在 __next__() 方法中咱們能夠設置在完成指定循環次數後觸發 StopIteration 異常來結束迭代。

在 20 次迭代後中止執行:

實例(Python 3.0+)

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)複製代碼

執行輸出結果爲:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20複製代碼

4. 生成器

在 Python 中,使用了 yield 的函數被稱爲生成器(generator)。

跟普通函數不一樣的是,生成器是一個返回迭代器的函數,只能用於迭代操做,更簡單點理解生成器就是一個迭代器。

在調用生成器運行的過程當中,每次遇到 yield 時函數會暫停並保存當前全部的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行。

調用一個生成器函數,返回的是一個迭代器對象。

如下實例使用 yield 實現斐波那契數列:

實例(Python 3.0+)

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複製代碼

五、Python3 函數

函數是組織好的,可重複使用的,用來實現單一,或相關聯功能的代碼段。

函數能提升應用的模塊性,和代碼的重複利用率。你已經知道Python提供了許多內建函數,好比print()。但你也能夠本身建立函數,這被叫作用戶自定義函數。

1. 定義一個函數

你能夠定義一個由本身想要功能的函數,如下是簡單的規則:

  • 函數代碼塊以 def 關鍵詞開頭,後接函數標識符名稱和圓括號 ()
  • 任何傳入參數和自變量必須放在圓括號中間,圓括號之間能夠用於定義參數。
  • 函數的第一行語句能夠選擇性地使用文檔字符串—用於存放函數說明。
  • 函數內容以冒號起始,而且縮進。
  • return [表達式] 結束函數,選擇性地返回一個值給調用方。不帶表達式的return至關於返回 None。

語法

Python 定義函數使用 def 關鍵字,通常格式以下:

def 函數名(參數列表):
    函數體複製代碼

默認狀況下,參數值和參數名稱是按函數聲明中定義的順序匹配起來的。

實例

讓咱們使用函數來輸出"Hello World!":

>>>def hello() :
   print("Hello World!")
 
   
>>> hello()
Hello World!
>>>複製代碼

更復雜點的應用,函數中帶上參數變量:

實例(Python 3.0+)

# 計算面積函數
def area(width, height):
    return width * height
 
def print_welcome(name):
    print("Welcome", name)
 
print_welcome("Runoob")
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))複製代碼

以上實例輸出結果:

Welcome Runoob
width = 4  height = 5  area = 20複製代碼

2. 函數調用

定義一個函數:給了函數一個名稱,指定了函數裏包含的參數,和代碼塊結構。

這個函數的基本結構完成之後,你能夠經過另外一個函數調用執行,也能夠直接從 Python 命令提示符執行。

以下實例調用了 printme() 函數:

實例(Python 3.0+)

# 定義函數
def printme( str ):
   # 打印任何傳入的字符串
   print (str)
   return
 
# 調用函數
printme("我要調用用戶自定義函數!")
printme("再次調用同一函數")複製代碼

以上實例輸出結果:

我要調用用戶自定義函數!
再次調用同一函數複製代碼

3. 參數傳遞

在 python 中,類型屬於對象,變量是沒有類型的:

a=[1,2,3]

a="Runoob"複製代碼

以上代碼中,[1,2,3] 是 List 類型,"Runoob" 是 String 類型,而變量 a 是沒有類型,她僅僅是一個對象的引用(一個指針),能夠是指向 List 類型對象,也能夠是指向 String 類型對象。

可更改(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 中一切都是對象,嚴格意義咱們不能說值傳遞仍是引用傳遞,咱們應該說傳不可變對象和傳可變對象。

python 傳不可變對象實例

實例(Python 3.0+)

def ChangeInt( a ):
    a = 10
 
b = 2
ChangeInt(b)
print( b ) 
# 結果是 2實例中有 int 對象 2,指向它的變量是 b,在傳遞給 ChangeInt 函數時,
#按傳值的方式複製了變量 b,a 和 b 都指向了同一個 Int 對象,在 a=10 時,則新生
#成一個 int 值對象 10,並讓 a 指向它。複製代碼

傳可變對象實例

可變對象在函數裏修改了參數,那麼在調用這個函數的函數裏,原始的參數也被改變了。例如:

實例(Python 3.0+)

# 可寫函數說明
def changeme( mylist ):
   "修改傳入的列表"
   mylist.append([1,2,3,4])
   print ("函數內取值: ", mylist)
   return
 
# 調用changeme函數
mylist = [10,20,30]
changeme( mylist )
print ("函數外取值: ", mylist)複製代碼

傳入函數的和在末尾添加新內容的對象用的是同一個引用。故輸出結果以下:

函數內取值:  [10, 20, 30, [1, 2, 3, 4]]
函數外取值:  [10, 20, 30, [1, 2, 3, 4]]複製代碼

4. 參數

如下是調用函數時可以使用的正式參數類型:

  • 必需參數
  • 關鍵字參數
  • 默認參數
  • 不定長參數

必需參數

必需參數須以正確的順序傳入函數。調用時的數量必須和聲明時的同樣。

調用 printme() 函數,你必須傳入一個參數,否則會出現語法錯誤:

實例(Python 3.0+)

#可寫函數說明
def printme( str ):
   "打印任何傳入的字符串"
   print (str)
   return
 
# 調用 printme 函數,不加參數會報錯
printme()複製代碼

以上實例輸出結果:

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    printme()
TypeError: printme() missing 1 required positional argument: 'str'複製代碼

關鍵字參數

關鍵字參數和函數調用關係緊密,函數調用使用關鍵字參數來肯定傳入的參數值。

使用關鍵字參數容許函數調用時參數的順序與聲明時不一致,由於 Python 解釋器可以用參數名匹配參數值。

如下實例在函數 printme() 調用時使用參數名:

實例(Python 3.0+)

#可寫函數說明
def printme( str ):
   "打印任何傳入的字符串"
   print (str)
   return
 
#調用printme函數
printme( str = "菜鳥教程")複製代碼

以上實例輸出結果:

菜鳥教程複製代碼

如下實例中演示了函數參數的使用不須要使用指定順序:

實例(Python 3.0+)

#可寫函數說明
def printinfo( name, age ):
   "打印任何傳入的字符串"
   print ("名字: ", name)
   print ("年齡: ", age)
   return
 
#調用printinfo函數
printinfo( age=50, name="runoob" )複製代碼

以上實例輸出結果:

名字:  runoob
年齡:  50複製代碼

默認參數

調用函數時,若是沒有傳遞參數,則會使用默認參數。如下實例中若是沒有傳入 age 參數,則使用默認值:

實例(Python 3.0+)

#可寫函數說明
def printinfo( name, age = 35 ):
   "打印任何傳入的字符串"
   print ("名字: ", name)
   print ("年齡: ", age)
   return
 
#調用printinfo函數
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )複製代碼

以上實例輸出結果:

名字:  runoob
年齡:  50
------------------------
名字:  runoob
年齡:  35複製代碼

不定長參數

你可能須要一個函數能處理比當初聲明時更多的參數。這些參數叫作不定長參數,和上述 2 種參數不一樣,聲明時不會命名。基本語法以下:

def functionname([formal_args,] *var_args_tuple ):
   "函數_文檔字符串"
   function_suite
   return [expression]複製代碼

加了星號 * 的參數會以元組(tuple)的形式導入,存放全部未命名的變量參數。

實例(Python 3.0+)

# 可寫函數說明
def printinfo( arg1, *vartuple ):
   "打印任何傳入的參數"
   print ("輸出: ")
   print (arg1)
   print (vartuple)
 
# 調用printinfo 函數
printinfo( 70, 60, 50) 複製代碼

以上實例輸出結果:

輸出: 
70
(60, 50)複製代碼

若是在函數調用時沒有指定參數,它就是一個空元組。咱們也能夠不向函數傳遞未命名的變量。以下實例:

實例(Python 3.0+)

#!/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複製代碼

還有一種就是參數帶兩個星號 **基本語法以下:

def functionname([formal_args,] **var_args_dict ):
   "函數_文檔字符串"
   function_suite
   return [expression]複製代碼

加了兩個星號 ** 的參數會以字典的形式導入。

實例(Python 3.0+)

# 可寫函數說明
def printinfo( arg1, **vardict ):
   "打印任何傳入的參數"
   print ("輸出: ")
   print (arg1)
   print (vardict)
 
# 調用printinfo 函數
printinfo(1, a=2,b=3)複製代碼

以上實例輸出結果:

輸出: 
1
{'a': 2, 'b': 3}複製代碼

聲明函數時,參數中星號 * 能夠單獨出現,例如:

def f(a,b,*,c):
    return a+b+c複製代碼

若是單獨出現星號 * 後的參數必須用關鍵字傳入。

>>> def f(a,b,*,c):
...     return a+b+c
... 
>>> f(1,2,3)   # 報錯
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1,2,c=3) # 正常
6
>>>複製代碼

5. 匿名函數

python 使用 lambda 來建立匿名函數。

所謂匿名,意即再也不使用 def 語句這樣標準的形式定義一個函數。

  • lambda 只是一個表達式,函數體比 def 簡單不少。
  • lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
  • lambda 函數擁有本身的命名空間,且不能訪問本身參數列表以外或全局命名空間裏的參數。
  • 雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不佔用棧內存從而增長運行效率。

語法

lambda 函數的語法只包含一個語句,以下:

lambda [arg1 [,arg2,.....argn]]:expression複製代碼

以下實例:

實例(Python 3.0+)

# 可寫函數說明
sum = lambda arg1, arg2: arg1 + arg2
 
# 調用sum函數
print ("相加後的值爲 : ", sum( 10, 20 ))
print ("相加後的值爲 : ", sum( 20, 20 ))複製代碼

以上實例輸出結果:

相加後的值爲 :  30
相加後的值爲 :  40複製代碼

6. return語句

return [表達式] 語句用於退出函數,選擇性地向調用方返回一個表達式。不帶參數值的return語句返回None。以前的例子都沒有示範如何返回數值,如下實例演示了 return 語句的用法:

實例(Python 3.0+)

# 可寫函數說明
def sum( arg1, arg2 ):
   # 返回2個參數的和."
   total = arg1 + arg2
   print ("函數內 : ", total)
   return total
 
# 調用sum函數
total = sum( 10, 20 )
print ("函數外 : ", total)複製代碼

以上實例輸出結果:

函數內 :  30
函數外 :  30複製代碼

7. 強制位置參數

Python3.8 新增了一個函數形參語法 / 用來指明函數形參必須使用指定位置參數,不能使用關鍵字參數的形式。

在如下的例子中,形參 a 和 b 必須使用指定位置參數,c 或 d 能夠是位置形參或關鍵字形參,而 e 或 f 要求爲關鍵字形參:

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)複製代碼

如下使用方法是正確的:

f(10, 20, 30, d=40, e=50, f=60)複製代碼

如下使用方法會發生錯誤:

f(10, b=20, c=30, d=40, e=50, f=60)   # b 不能使用關鍵字參數的形式
f(10, 20, 30, 40, 50, f=60)           # e 必須使用關鍵字參數的形式複製代碼

六、Python3 數據結構

本章節咱們主要結合前面所學的知識點來介紹Python數據結構。

1. 列表

Python中列表是可變的,這是它區別於字符串和元組的最重要的特色,一句話歸納即:列表能夠修改,而字符串和元組不能。

如下是 Python 中列表的方法:

方法 描述
list.append(x) 把一個元素添加到列表的結尾,至關於 a[len(a):] = [x]。
list.extend(L) 經過添加指定列表的全部元素來擴充列表,至關於 a[len(a):] = L。
list.insert(i, x) 在指定位置插入一個元素。第一個參數是準備插入到其前面的那個元素的索引,例如 a.insert(0, x) 會插入到整個列表以前,而 a.insert(len(a), x) 至關於 a.append(x) 。
list.remove(x) 刪除列表中值爲 x 的第一個元素。若是沒有這樣的元素,就會返回一個錯誤。
list.pop([i]) 從列表的指定位置移除元素,並將其返回。若是沒有指定索引,a.pop()返回最後一個元素。元素隨即從列表中被移除。(方法中 i 兩邊的方括號表示這個參數是可選的,而不是要求你輸入一對方括號,你會常常在 Python 庫參考手冊中遇到這樣的標記。)
list.clear() 移除列表中的全部項,等於del a[:]。
list.index(x) 返回列表中第一個值爲 x 的元素的索引。若是沒有匹配的元素就會返回一個錯誤。
list.count(x) 返回 x 在列表中出現的次數。
list.sort() 對列表中的元素進行排序。
list.reverse() 倒排列表中的元素。
list.copy() 返回列表的淺複製,等於a[:]。

下面示例演示了列表的大部分方法:

實例

>>> a = [66.25, 333, 333, 1, 1234.5]
>>> print(a.count(333), a.count(66.25), a.count('x'))
2 1 0
>>> a.insert(2, -1)
>>> a.append(333)
>>> a
[66.25, 333, -1, 333, 1, 1234.5, 333]
>>> a.index(333)
1
>>> a.remove(333)
>>> a
[66.25, -1, 333, 1, 1234.5, 333]
>>> a.reverse()
>>> a
[333, 1234.5, 1, 333, -1, 66.25]
>>> a.sort()
>>> a
[-1, 1, 66.25, 333, 333, 1234.5]複製代碼

注意:相似 insert, remove 或 sort 等修改列表的方法沒有返回值。

2. 將列表當作堆棧使用

列表方法使得列表能夠很方便的做爲一個堆棧來使用,堆棧做爲特定的數據結構,最早進入的元素最後一個被釋放(後進先出)。用 append() 方法能夠把一個元素添加到堆棧頂。用不指定索引的 pop() 方法能夠把一個元素從堆棧頂釋放出來。例如:

實例

>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]複製代碼

3. 將列表看成隊列使用

也能夠把列表當作隊列用,只是在隊列裏第一加入的元素,第一個取出來;可是拿列表用做這樣的目的效率不高。在列表的最後添加或者彈出元素速度快,然而在列表裏插入或者從頭部彈出速度卻不快(由於全部其餘的元素都得一個一個地移動)。

實例

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")           # Terry arrives
>>> queue.append("Graham")          # Graham arrives
>>> queue.popleft()                 # The first to arrive now leaves'Eric'
>>> queue.popleft()                 # The second to arrive now leaves'John'
>>> queue                           # Remaining queue in order of arrivaldeque(['Michael', 'Terry', 'Graham'])複製代碼

4. 列表推導式

列表推導式提供了從序列建立列表的簡單途徑。一般應用程序將一些操做應用於某個序列的每一個元素,用其得到的結果做爲生成新列表的元素,或者根據肯定的斷定條件建立子序列。

每一個列表推導式都在 for 以後跟一個表達式,而後有零到多個 for 或 if 子句。返回結果是一個根據表達從其後的 for 和 if 上下文環境中生成出來的列表。若是但願表達式推導出一個元組,就必須使用括號。

這裏咱們將列表中每一個數值乘三,得到一個新的列表:

>>> 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]]複製代碼

這裏咱們對序列裏每個元素逐個調用某方法:

實例

>>> freshfruit = [' banana', ' loganberry ', 'passion fruit ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']複製代碼

咱們能夠用 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]複製代碼

列表推導式可使用複雜表達式或嵌套函數:

>>> [str(round(355/113, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']複製代碼

5. 嵌套列表解析

Python的列表還能夠嵌套。

如下實例展現了3X4的矩陣列表:

>>> 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]]複製代碼

如下實例也可使用如下方法來實現:

>>> transposed = []
>>> for i in range(4):
...     transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]複製代碼

另一種實現方法:

>>> transposed = []
>>> for i in range(4):
...     # the following 3 lines implement the nested listcomp
...     transposed_row = []
...     for row in matrix:
...         transposed_row.append(row[i])
...     transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]複製代碼

6. del 語句

使用 del 語句能夠從一個列表中依索引而不是值來刪除一個元素。這與使用 pop() 返回一個值不一樣。能夠用 del 語句從列表中刪除一個切割,或清空整個列表(咱們之前介紹的方法是給該切割賦一個空列表)。例如:

>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]複製代碼

也能夠用 del 刪除實體變量:

>>> del a複製代碼

7. 元組和序列

元組由若干逗號分隔的值組成,例如:

>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Tuples may be nested:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))複製代碼

如你所見,元組在輸出時老是有括號的,以便於正確表達嵌套結構。在輸入時可能有或沒有括號, 不過括號一般是必須的(若是元組是更大的表達式的一部分)。

8. 集合

集合是一個無序不重複元素的集。基本功能包括關係測試和消除重複元素。

能夠用大括號({})建立集合。注意:若是要建立一個空集合,你必須用 set() 而不是 {} ;後者建立一個空的字典,下一節咱們會介紹這個數據結構。

如下是一個簡單的演示:

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # 刪除重複的{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # 檢測成員
True
>>> 'crabgrass' in basket
False
>>> # 如下演示了兩個集合的操做...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # a 中惟一的字母
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # 在 a 中的字母,但不在 b 中
{'r', 'd', 'b'}
>>> a | b                              # 在 a 或 b 中的字母
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # 在 a 和 b 中都有的字母
{'a', 'c'}
>>> a ^ b                              # 在 a 或 b 中的字母,但不一樣時在 a 和 b 中
{'r', 'd', 'b', 'm', 'z', 'l'}複製代碼

集合也支持推導式:

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}複製代碼

9. 字典

另外一個很是有用的 Python 內建數據類型是字典。

序列是以連續的整數爲索引,與此不一樣的是,字典以關鍵字爲索引,關鍵字能夠是任意不可變類型,一般用字符串或數值。

理解字典的最佳方式是把它看作無序的鍵=>值對集合。在同一個字典以內,關鍵字必須是互不相同。

一對大括號建立一個空的字典:{}。

這是一個字典運用的簡單例子:

>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> list(tel.keys())
['irv', 'guido', 'jack']
>>> sorted(tel.keys())
['guido', 'irv', 'jack']
>>> 'guido' in telTrue
>>> 'jack' not in telFalse複製代碼

構造函數 dict() 直接從鍵值對元組列表中構建字典。若是有固定的模式,列表推導式指定特定的鍵值對:

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}複製代碼

此外,字典推導能夠用來建立任意鍵和值的表達式詞典:

>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}複製代碼

若是關鍵字只是簡單的字符串,使用關鍵字參數指定鍵值對有時候更方便:

>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}複製代碼

10. 遍歷技巧

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

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

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

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

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

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name?  It is lancelot.
What is your quest?  It is the holy grail.
What is your favorite color?  It is blue.複製代碼

要反向遍歷一個序列,首先指定這個序列,而後調用 reversed() 函數:

>>> for i in reversed(range(1, 10, 2)):
...     print(i)
...
9
7
5
3
1複製代碼

要按順序遍歷一個序列,使用 sorted() 函數返回一個已排序的序列,並不修改原值:

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
...     print(f)
...
apple
banana
orange
pear複製代碼

參閱文檔

七、Python3 模塊

在前面的幾個章節中咱們腳本上是用 python 解釋器來編程,若是你從 Python 解釋器退出再進入,那麼你定義的全部的方法和變量就都消失了。

爲此 Python 提供了一個辦法,把這些定義存放在文件中,爲一些腳本或者交互式的解釋器實例使用,這個文件被稱爲模塊。

模塊是一個包含全部你定義的函數和變量的文件,其後綴名是.py。模塊能夠被別的程序引入,以使用該模塊中的函數等功能。這也是使用 python 標準庫的方法。

下面是一個使用 python 標準庫中模塊的例子。

實例(Python 3.0+)

# 文件名: using_sys.py
 
import sys
 
print('命令行參數以下:')
for i in sys.argv:
   print(i)
 
print('\n\nPython 路徑爲:', sys.path, '\n')複製代碼

執行結果以下所示:

$ python using_sys.py 參數1 參數2
命令行參數以下:
using_sys.py
參數1
參數2


Python 路徑爲: ['/root', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages'] 
複製代碼
  • 一、import sys 引入 python 標準庫中的 sys.py 模塊;這是引入某一模塊的方法。
  • 二、sys.argv 是一個包含命令行參數的列表。
  • 三、sys.path 包含了一個 Python 解釋器自動查找所需模塊的路徑的列表。

1. import 語句

想使用 Python 源文件,只需在另外一個源文件裏執行 import 語句,語法以下:

import module1[, module2[,... moduleN]複製代碼

當解釋器遇到 import 語句,若是模塊在當前的搜索路徑就會被導入。

搜索路徑是一個解釋器會先進行搜索的全部目錄的列表。如想要導入模塊 support,須要把命令放在腳本的頂端:

2. support.py 文件代碼

# Filename: support.py
 
def print_func( par ):
    print ("Hello : ", par)
    returntest.py 引入 support 模塊:複製代碼

3. test.py 文件代碼

# Filename: test.py
 
# 導入模塊
import support
 
# 如今能夠調用模塊裏包含的函數了
support.print_func("Runoob")複製代碼

以上實例輸出結果:

$ python3 test.py 
Hello :  Runoob複製代碼

一個模塊只會被導入一次,無論你執行了多少次import。這樣能夠防止導入模塊被一遍又一遍地執行。

當咱們使用import語句的時候,Python解釋器是怎樣找到對應的文件的呢?

這就涉及到Python的搜索路徑,搜索路徑是由一系列目錄名組成的,Python解釋器就依次從這些目錄中去尋找所引入的模塊。

這看起來很像環境變量,事實上,也能夠經過定義環境變量的方式來肯定搜索路徑。

搜索路徑是在Python編譯或安裝的時候肯定的,安裝新的庫應該也會修改。搜索路徑被存儲在sys模塊中的path變量,作一個簡單的實驗,在交互式解釋器中,輸入如下代碼:

>>> import sys
>>> sys.path
['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']
>>> 複製代碼

sys.path 輸出是一個列表,其中第一項是空串'',表明當前目錄(如果從一個腳本中打印出來的話,能夠更清楚地看出是哪一個目錄),亦即咱們執行python解釋器的目錄(對於腳本的話就是運行的腳本所在的目錄)。

所以若像我同樣在當前目錄下存在與要引入模塊同名的文件,就會把要引入的模塊屏蔽掉。

瞭解了搜索路徑的概念,就能夠在腳本中修改sys.path來引入一些不在搜索路徑中的模塊。

如今,在解釋器的當前目錄或者 sys.path 中的一個目錄裏面來建立一個fibo.py的文件,代碼以下:

實例

def fib(n):    # 定義到 n 的斐波那契數列
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()
 
def fib2(n): # 返回到 n 的斐波那契數列
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result複製代碼

而後進入Python解釋器,使用下面的命令導入這個模塊:

>>> import fibo複製代碼

這樣作並無把直接定義在fibo中的函數名稱寫入到當前符號表裏,只是把模塊fibo的名字寫到了那裏。

可使用模塊名稱來訪問函數:

實例

>>>fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'複製代碼

若是你打算常用一個函數,你能夠把它賦給一個本地的名稱:

>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377複製代碼


4. from … import 語句

Python 的 from 語句讓你從模塊中導入一個指定的部分到當前命名空間中,語法以下:

from modname import name1[, name2[, ... nameN]]複製代碼

例如,要導入模塊 fibo 的 fib 函數,使用以下語句:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377複製代碼

這個聲明不會把整個fibo模塊導入到當前的命名空間中,它只會將fibo裏的fib函數引入進來。


5. from … import * 語句

把一個模塊的全部內容全都導入到當前的命名空間也是可行的,只需使用以下聲明:

from modname import *複製代碼

這提供了一個簡單的方法來導入一個模塊中的全部項目。然而這種聲明不應被過多地使用。

6. 深刻模塊

模塊除了方法定義,還能夠包括可執行的代碼。這些代碼通常用來初始化這個模塊。這些代碼只有在第一次被導入時纔會被執行。

每一個模塊有各自獨立的符號表,在模塊內部爲全部的函數看成全局符號表來使用。

因此,模塊的做者能夠放心大膽的在模塊內部使用這些全局變量,而不用擔憂把其餘用戶的全局變量搞混。

從另外一個方面,當你確實知道你在作什麼的話,你也能夠經過 modname.itemname 這樣的表示法來訪問模塊內的函數。

模塊是能夠導入其餘模塊的。在一個模塊(或者腳本,或者其餘地方)的最前面使用 import 來導入一個模塊,固然這只是一個慣例,而不是強制的。被導入的模塊的名稱將被放入當前操做的模塊的符號表中。

還有一種導入的方法,可使用 import 直接把模塊內(函數,變量的)名稱導入到當前操做模塊。好比:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377複製代碼

這種導入的方法不會把被導入的模塊的名稱放在當前的字符表中(因此在這個例子裏面,fibo 這個名稱是沒有定義的)。

這還有一種方法,能夠一次性的把模塊中的全部(函數,變量)名稱都導入到當前模塊的字符表:

>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377複製代碼

這將把全部的名字都導入進來,可是那些由單一下劃線(_)開頭的名字不在此例。大多數狀況, Python程序員不使用這種方法,由於引入的其它來源的命名,極可能覆蓋了已有的定義。

7. __name__屬性

一個模塊被另外一個程序第一次引入時,其主程序將運行。若是咱們想在模塊被引入時,模塊中的某一程序塊不執行,咱們能夠用__name__屬性來使該程序塊僅在該模塊自身運行時執行。

#!/usr/bin/python3
# Filename: using_name.py

if __name__ == '__main__':
   print('程序自身在運行')
else:
   print('我來自另外一模塊')複製代碼

運行輸出以下:

$ python using_name.py
程序自身在運行複製代碼
$ python
>>> import using_name
我來自另外一模塊
>>>複製代碼

說明: 每一個模塊都有一個__name__屬性,當其值是'__main__'時,代表該模塊自身在運行,不然是被引入。

說明:__name____main__ 底下是雙下劃線, _ _ 是這樣去掉中間的那個空格。

8. dir() 函數

內置的函數 dir() 能夠找到模塊內定義的全部名稱。以一個字符串列表的形式返回:

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)  
['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__',
 '__package__', '__stderr__', '__stdin__', '__stdout__',
 '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe',
 '_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv',
 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder',
 'call_tracing', 'callstats', 'copyright', 'displayhook',
 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix',
 'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags',
 'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit',
 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettotalrefcount',
 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
 'intern', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path',
 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1',
 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit',
 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout',
 'thread_info', 'version', 'version_info', 'warnoptions']複製代碼

若是沒有給定參數,那麼 dir() 函數會羅列出當前定義的全部名稱:

>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir() # 獲得一個當前模塊中定義的屬性列表
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
>>> a = 5 # 創建一個新的變量 'a'
>>> dir()
['__builtins__', '__doc__', '__name__', 'a', 'sys']
>>>
>>> del a # 刪除變量名a
>>>
>>> dir()
['__builtins__', '__doc__', '__name__', 'sys']
>>>複製代碼

9. 標準模塊

Python 自己帶着一些標準的模塊庫,在 Python 庫參考文檔中將會介紹到(就是後面的"庫參考文檔")。

有些模塊直接被構建在解析器裏,這些雖然不是一些語言內置的功能,可是他卻能很高效的使用,甚至是系統級調用也沒問題。

這些組件會根據不一樣的操做系統進行不一樣形式的配置,好比 winreg 這個模塊就只會提供給 Windows 系統。

應該注意到這有一個特別的模塊 sys ,它內置在每個 Python 解析器中。變量 sys.ps1 和 sys.ps2 定義了主提示符和副提示符所對應的字符串:

>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Runoob!')
Runoob!
C> 複製代碼

10. 包

包是一種管理 Python 模塊命名空間的形式,採用"點模塊名稱"。

好比一個模塊的名稱是 A.B, 那麼他表示一個包 A中的子模塊 B 。

就好像使用模塊的時候,你不用擔憂不一樣模塊之間的全局變量相互影響同樣,採用點模塊名稱這種形式也不用擔憂不一樣庫之間的模塊重名的狀況。

這樣不一樣的做者均可以提供 NumPy 模塊,或者是 Python 圖形庫。

不妨假設你想設計一套統一處理聲音文件和數據的模塊(或者稱之爲一個"包")。

現存不少種不一樣的音頻文件格式(基本上都是經過後綴名區分的,例如: .wav,:file:.aiff,:file:.au,),因此你須要有一組不斷增長的模塊,用來在不一樣的格式之間轉換。

而且針對這些音頻數據,還有不少不一樣的操做(好比混音,添加回聲,增長均衡器功能,建立人造立體聲效果),因此你還須要一組怎麼也寫不完的模塊來處理這些操做。

這裏給出了一種可能的包結構(在分層的文件系統中):

sound/                          頂層包
      __init__.py               初始化 sound 包
      formats/                  文件格式轉換子包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  聲音效果子包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  filters 子包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...複製代碼

在導入一個包的時候,Python 會根據 sys.path 中的目錄來尋找這個包中包含的子目錄。

目錄只有包含一個叫作 __init__.py 的文件纔會被認做是一個包,主要是爲了不一些濫俗的名字(好比叫作 string)不當心的影響搜索路徑中的有效模塊。

最簡單的狀況,放一個空的 :file:__init__.py就能夠了。固然這個文件中也能夠包含一些初始化代碼或者爲(將在後面介紹的) __all__變量賦值。

用戶能夠每次只導入一個包裏面的特定模塊,好比:

import sound.effects.echo複製代碼

這將會導入子模塊:sound.effects.echo。 他必須使用全名去訪問:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)複製代碼

還有一種導入子模塊的方法是:

from sound.effects import echo複製代碼

這一樣會導入子模塊: echo,而且他不須要那些冗長的前綴,因此他能夠這樣使用:

echo.echofilter(input, output, delay=0.7, atten=4)複製代碼

還有一種變化就是直接導入一個函數或者變量:

from sound.effects.echo import echofilter複製代碼

一樣的,這種方法會導入子模塊: echo,而且能夠直接使用他的 echofilter() 函數:

echofilter(input, output, delay=0.7, atten=4)複製代碼

注意當使用 from package import item 這種形式的時候,對應的 item 既能夠是包裏面的子模塊(子包),或者包裏面定義的其餘名稱,好比函數,類或者變量。

import 語法會首先把 item 看成一個包定義的名稱,若是沒找到,再試圖按照一個模塊去導入。若是還沒找到,拋出一個 :exc:ImportError 異常。

反之,若是使用形如 import item.subitem.subsubitem 這種導入形式,除了最後一項,都必須是包,而最後一項則能夠是模塊或者是包,可是不能夠是類,函數或者變量的名字。

11. 從一個包中導入*

設想一下,若是咱們使用 from sound.effects import *會發生什麼?

Python 會進入文件系統,找到這個包裏面全部的子模塊,一個一個的把它們都導入進來。

可是很不幸,這個方法在 Windows平臺上工做的就不是很是好,由於Windows是一個大小寫不區分的系統。

在這類平臺上,沒有人敢擔保一個叫作 ECHO.py 的文件導入爲模塊 echo 仍是 Echo 甚至 ECHO。

(例如,Windows 95就很討厭的把每個文件的首字母大寫顯示)並且 DOS 的 8+3 命名規則對長模塊名稱的處理會把問題搞得更糾結。

爲了解決這個問題,只能煩勞包做者提供一個精確的包的索引了。

導入語句遵循以下規則:若是包定義文件 __init__.py 存在一個叫作 __all__ 的列表變量,那麼在使用 from package import * 的時候就把這個列表中的全部名字做爲包內容導入。

做爲包的做者,可別忘了在更新包以後保證 __all__ 也更新了啊。你說我就不這麼作,我就不使用導入*這種用法,好吧,沒問題,誰讓你是老闆呢。這裏有一個例子,在:file:sounds/effects/__init__.py中包含以下代碼:

__all__ = ["echo", "surround", "reverse"]複製代碼

這表示當你使用from sound.effects import *這種用法時,你只會導入包裏面這三個子模塊。

若是 __all__ 真的沒有定義,那麼使用from sound.effects import *這種語法的時候,就不會導入包 sound.effects 裏的任何子模塊。他只是把包sound.effects和它裏面定義的全部內容導入進來(可能運行__init__.py裏定義的初始化代碼)。

這會把 __init__.py 裏面定義的全部名字導入進來。而且他不會破壞掉咱們在這句話以前導入的全部明確指定的模塊。看下這部分代碼:

import sound.effects.echo
import sound.effects.surround
from sound.effects import *複製代碼

這個例子中,在執行 from...import 前,包 sound.effects 中的 echo 和 surround 模塊都被導入到當前的命名空間中了。(固然若是定義了 __all__ 就更沒問題了)

一般咱們並不主張使用 * 這種方法來導入模塊,由於這種方法常常會致使代碼的可讀性下降。不過這樣倒的確是能夠省去很多敲鍵的功夫,並且一些模塊都設計成了只能經過特定的方法導入。

記住,使用 from Package import specific_submodule 這種方法永遠不會有錯。事實上,這也是推薦的方法。除非是你要導入的子模塊有可能和其餘包的子模塊重名。

若是在結構中包是一個子包(好比這個例子中對於包sound來講),而你又想導入兄弟包(同級別的包)你就得使用導入絕對的路徑來導入。好比,若是模塊sound.filters.vocoder 要使用包 sound.effects 中的模塊 echo,你就要寫成 from sound.effects import echo。

from . import echo
from .. import formats
from ..filters import equalizer複製代碼

不管是隱式的仍是顯式的相對導入都是從當前模塊開始的。主模塊的名字永遠是"__main__",一個Python應用程序的主模塊,應當老是使用絕對路徑引用。

包還提供一個額外的屬性__path__。這是一個目錄列表,裏面每個包含的目錄都有爲這個包服務的__init__.py,你得在其餘__init__.py被執行前定義哦。能夠修改這個變量,用來影響包含在包裏面的模塊和子包。

這個功能並不經常使用,通常用來擴展包裏面的模塊。

八、Python3 輸入和輸出

在前面幾個章節中,咱們其實已經接觸了 Python 的輸入輸出的功能。本章節咱們將具體介紹 Python 的輸入輸出。

1. 輸出格式美化

Python兩種輸出值的方式: 表達式語句和 print() 函數。

第三種方式是使用文件對象的 write() 方法,標準輸出文件能夠用 sys.stdout 引用。

若是你但願輸出的形式更加多樣,可使用 str.format() 函數來格式化輸出值。

若是你但願將輸出的值轉成字符串,可使用 repr() 或 str() 函數來實現。

  • str(): 函數返回一個用戶易讀的表達形式。
  • repr(): 產生一個解釋器易讀的表達形式。

例如

>>> s = 'Hello, Runoob'
>>> str(s)
'Hello, Runoob'
>>> repr(s)" 'Hello, Runoob'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'x 的值爲: ' + repr(x) + ', y 的值爲:' + repr(y) + '...'
>>> print(s)
x 的值爲: 32.5,  y 的值爲:40000...
>>> # repr() 函數能夠轉義字符串中的特殊字符
... hello = 'hello, runoob\n'
>>> hellos = repr(hello)>>> print(hellos)
'hello, runoob\n'
>>> # repr() 的參數能夠是 Python 的任何對象
... repr((x, y, ('Google', 'Runoob')))" (32.5, 40000, ('Google', 'Runoob'))"複製代碼

這裏有兩種方式輸出一個平方與立方的表:

>>> 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複製代碼

注意:在第一個例子中, 每列間的空格由 print() 添加。

這個例子展現了字符串對象的 rjust() 方法, 它能夠將字符串靠右, 並在左邊填充空格。

還有相似的方法, 如 ljust() 和 center()。 這些方法並不會寫任何東西, 它們僅僅返回新的字符串。

另外一個方法 zfill(), 它會在數字的左邊填充 0,以下所示:

>>> '12'.zfill(5)'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'複製代碼

str.format() 的基本使用以下:

>>> print('{}網址: "{}!"'.format('菜鳥教程', 'www.runoob.com'))複製代碼

括號及其裏面的字符 (稱做格式化字段) 將會被 format() 中的參數替換。

在括號中的數字用於指向傳入對象在 format() 中的位置,以下所示:

>>> 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'))複製代碼

位置及關鍵字參數能夠任意的結合:

>>> print('站點列表 {0}, {1}, 和 {other}。'.format('Google', 'Runoob', other='Taobao'))
站點列表 Google, Runoob, 和 Taobao。複製代碼

!a (使用 ascii()), !s (使用 str()) 和 !r (使用 repr()) 能夠用於在格式化某個值以前對其進行轉化:

>>> import math
>>> print('常量 PI 的值近似爲: {}。'.format(math.pi))
常量 PI 的值近似爲: 3.141592653589793。
>>> print('常量 PI 的值近似爲: {!r}。'.format(math.pi))
常量 PI 的值近似爲: 3.141592653589793。複製代碼

可選項 : 和格式標識符能夠跟着字段名。 這就容許對值進行更好的格式化。 下面的例子將 Pi 保留到小數點後三位:

>>> import math
>>> print('常量 PI 的值近似爲 {0:.3f}。'.format(math.pi))
常量 PI 的值近似爲 3.142。複製代碼

在 : 後傳入一個整數, 能夠保證該域至少有這麼多的寬度。 用於美化表格時頗有用。

>>> table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
>>> for name, number in table.items():
...     print('{0:10} ==> {1:10d}'.format(name, number))
...
Google     ==>          1
Runoob     ==>          2
Taobao     ==>          3複製代碼

若是你有一個很長的格式化字符串, 而你不想將它們分開, 那麼在格式化時經過變量名而非位置會是很好的事情。

最簡單的就是傳入一個字典, 而後使用方括號 [] 來訪問鍵值 :

>>> table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
>>> print('Runoob: {0[Runoob]:d}; Google: {0[Google]:d}; Taobao: {0[Taobao]:d}'.format(table))
Runoob: 2; Google: 1; Taobao: 3複製代碼

也能夠經過在 table 變量前使用 ** 來實現相同的功能:

>>> table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
>>> print('Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}'.format(**table))
Runoob: 2; Google: 1; Taobao: 3複製代碼

2. 舊式字符串格式化

% 操做符也能夠實現字符串格式化。 它將左邊的參數做爲相似 sprintf() 式的格式化字符串, 而將右邊的代入, 而後返回格式化後的字符串. 例如:

>>> import math
>>> print('常量 PI 的值近似爲:%5.3f。' % math.pi)
常量 PI 的值近似爲:3.142。

由於 str.format() 比較新的函數, 大多數的 Python 代碼仍然使用 % 操做符。可是由於這種舊式的格式化最終會從該語言中移除, 應該更多的使用 str.format().

3. 讀取鍵盤輸入

Python提供了 input() 內置函數從標準輸入讀入一行文本,默認的標準輸入是鍵盤。

input 能夠接收一個Python表達式做爲輸入,並將運算結果返回。

實例

str = input("請輸入:");
print ("你輸入的內容是: ", str)複製代碼

這會產生以下的對應着輸入的結果:

請輸入:菜鳥教程
你輸入的內容是:  菜鳥教程複製代碼

4. 讀和寫文件

open() 將會返回一個 file 對象,基本語法格式以下:

open(filename, mode)複製代碼
  • filename:包含了你要訪問的文件名稱的字符串值。
  • mode:決定了打開文件的模式:只讀,寫入,追加等。全部可取值見以下的徹底列表。這個參數是非強制的,默認文件訪問模式爲只讀(r)。

不一樣模式打開文件的徹底列表:

模式 描述
r 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。
rb 以二進制格式打開一個文件用於只讀。文件指針將會放在文件的開頭。
r+ 打開一個文件用於讀寫。文件指針將會放在文件的開頭。
rb+ 以二進制格式打開一個文件用於讀寫。文件指針將會放在文件的開頭。
w 打開一個文件只用於寫入。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。
wb 以二進制格式打開一個文件只用於寫入。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。
w+ 打開一個文件用於讀寫。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。
wb+ 以二進制格式打開一個文件用於讀寫。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。
a 打開一個文件用於追加。若是該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容以後。若是該文件不存在,建立新文件進行寫入。
ab 以二進制格式打開一個文件用於追加。若是該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容以後。若是該文件不存在,建立新文件進行寫入。
a+ 打開一個文件用於讀寫。若是該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。若是該文件不存在,建立新文件用於讀寫。
ab+ 以二進制格式打開一個文件用於追加。若是該文件已存在,文件指針將會放在文件的結尾。若是該文件不存在,建立新文件用於讀寫。

下圖很好的總結了這幾種模式:

模式 r r+ w w+ a a+
+ + + +
+ + + + +
建立 + + + +
覆蓋 + +
指針在開始 + + + +
指針在結尾 + +

如下實例將字符串寫入到文件 foo.txt 中:

實例

# 打開一個文件
f = open("/tmp/foo.txt", "w")
f.write( "Python 是一個很是好的語言。\n是的,的確很是好!!\n" )
# 關閉打開的文件
f.close()複製代碼
  • 第一個參數爲要打開的文件名。
  • 第二個參數描述文件如何使用的字符。 mode 能夠是 'r' 若是文件只讀, 'w' 只用於寫 (若是存在同名文件則將被刪除), 和 'a' 用於追加文件內容; 所寫的任何數據都會被自動增長到末尾. 'r+' 同時用於讀寫。 mode 參數是可選的; 'r' 將是默認值。

此時打開文件 foo.txt,顯示以下:

$ cat /tmp/foo.txt 
Python 是一個很是好的語言。
是的,的確很是好!!複製代碼

5. 文件對象的方法

本節中剩下的例子假設已經建立了一個稱爲 f 的文件對象。

f.read()

爲了讀取一個文件的內容,調用 f.read(size), 這將讀取必定數目的數據, 而後做爲字符串或字節對象返回。

size 是一個可選的數字類型的參數。 當 size 被忽略了或者爲負, 那麼該文件的全部內容都將被讀取而且返回。

如下實例假定文件 foo.txt 已存在(上面實例中已建立):

實例

# 打開一個文件
f = open("/tmp/foo.txt", "r")
str = f.read()
print(str)
# 關閉打開的文件
f.close()複製代碼

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

Python 是一個很是好的語言。
是的,的確很是好!!複製代碼

f.readline()

f.readline() 會從文件中讀取單獨的一行。換行符爲 '\n'。f.readline() 若是返回一個空字符串, 說明已經已經讀取到最後一行。

實例

# 打開一個文件
f = open("/tmp/foo.txt", "r")

str = f.readline()print(str)

# 關閉打開的文件
f.close()複製代碼

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

Python 是一個很是好的語言。複製代碼

f.readlines()

f.readlines() 將返回該文件中包含的全部行。

若是設置可選參數 sizehint, 則讀取指定長度的字節, 而且將這些字節按行分割。

實例

# 打開一個文件
f = open("/tmp/foo.txt", "r")

str = f.readlines()
print(str)

# 關閉打開的文件
f.close()複製代碼

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

['Python 是一個很是好的語言。\n', '是的,的確很是好!!\n']複製代碼

另外一種方式是迭代一個文件對象而後讀取每行:

實例

# 打開一個文件
f = open("/tmp/foo.txt", "r")

for line in f:    
    print(line, end='')

# 關閉打開的文件
f.close()複製代碼

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

Python 是一個很是好的語言。
是的,的確很是好!!複製代碼

這個方法很簡單, 可是並無提供一個很好的控制。 由於二者的處理機制不一樣, 最好不要混用。

f.write()

f.write(string)string 寫入到文件中, 而後返回寫入的字符數。

實例

# 打開一個文件
f = open("/tmp/foo.txt", "w")

num = f.write( "Python 是一個很是好的語言。\n是的,的確很是好!!\n" )
print(num)
# 關閉打開的文件
f.close()複製代碼

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

29複製代碼

若是要寫入一些不是字符串的東西, 那麼將須要先進行轉換:

實例

# 打開一個文件
f = open("/tmp/foo1.txt", "w")

value = ('www.runoob.com', 14)
s = str(value)
f.write(s)

# 關閉打開的文件
f.close()複製代碼

執行以上程序,打開 foo1.txt 文件:

$ cat /tmp/foo1.txt 
('www.runoob.com', 14)複製代碼

f.tell()

f.tell() 返回文件對象當前所處的位置, 它是從文件開頭開始算起的字節數。

f.seek()

若是要改變文件當前的位置, 可使用 f.seek(offset, from_what) 函數。

from_what 的值, 若是是 0 表示開頭, 若是是 1 表示當前位置, 2 表示文件的結尾,例如:

  • seek(x,0) : 從起始位置即文件首行首字符開始移動 x 個字符
  • seek(x,1) : 表示從當前位置日後移動x個字符
  • seek(-x,2):表示從文件的結尾往前移動x個字符

from_what 值爲默認爲0,即文件開頭。下面給出一個完整的例子:

>>> f = open('/tmp/foo.txt', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)     # 移動到文件的第六個字節
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2) # 移動到文件的倒數第三字節13
>>> f.read(1)
b'd'複製代碼

f.close()

在文本文件中 (那些打開文件的模式下沒有 b 的), 只會相對於文件起始位置進行定位。

當你處理完一個文件後, 調用 f.close() 來關閉文件並釋放系統的資源,若是嘗試再調用該文件,則會拋出異常。

>>> f.close()
>>> f.read()Traceback (most recent call last):  
File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file複製代碼

當處理一個文件對象時, 使用 with 關鍵字是很是好的方式。在結束後, 它會幫你正確的關閉文件。 並且寫起來也比 try - finally 語句塊要簡短:

>>> with open('/tmp/foo.txt', 'r') as f:
...     read_data = f.read()
>>> f.closed
True複製代碼

文件對象還有其餘方法, 如 isatty() 和 trucate(), 但這些一般比較少用。

6. pickle 模塊

python的pickle模塊實現了基本的數據序列和反序列化。

經過pickle模塊的序列化操做咱們可以將程序中運行的對象信息保存到文件中去,永久存儲。

經過pickle模塊的反序列化操做,咱們可以從文件中建立上一次程序保存的對象。

基本接口:

pickle.dump(obj, file, [,protocol])複製代碼

有了 pickle 這個對象, 就能對 file 以讀取的形式打開:

x = pickle.load(file)複製代碼

註解:從 file 中讀取一個字符串,並將它重構爲原來的python對象。

file: 類文件對象,有read()和readline()接口。

實例 1

#!/usr/bin/python3import pickle

# 使用pickle模塊將數據對象保存到文件
data1 = {'a': [1, 2.0, 3, 4+6j],'b': ('string', u'Unicode string'),'c': None}

selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)

output = open('data.pkl', 'wb')

# Pickle dictionary using protocol 0.pickle.dump(data1, output)

# Pickle the list using the highest protocol available.
pickle.dump(selfref_list, output, -1)
output.close()複製代碼

實例 2

import pprint, pickle

#使用pickle模塊從文件中重構python對象
pkl_file = open('data.pkl', 'rb')

data1 = pickle.load(pkl_file)pprint.pprint(data1)

data2 = pickle.load(pkl_file)pprint.pprint(data2)

pkl_file.close()
複製代碼

9. Python3 File(文件) 方法

1. open() 方法

Python open() 方法用於打開一個文件,並返回文件對象,在對文件進行處理過程都須要使用到這個函數,若是該文件沒法被打開,會拋出 OSError。

注意:使用 open() 方法必定要保證關閉文件對象,即調用 close() 方法。

open() 函數經常使用形式是接收兩個參數:文件名(file)和模式(mode)。

open(file, mode='r')複製代碼

完整的語法格式爲:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)複製代碼

參數說明:

  • file: 必需,文件路徑(相對或者絕對路徑)。
  • mode: 可選,文件打開模式
  • buffering: 設置緩衝
  • encoding: 通常使用utf8
  • errors: 報錯級別
  • newline: 區分換行符
  • closefd: 傳入的file參數類型
  • opener:

mode 參數有:

模式 描述
t 文本模式 (默認)。
x 寫模式,新建一個文件,若是該文件已存在則會報錯。
b 二進制模式。
+ 打開一個文件進行更新(可讀可寫)。
U 通用換行模式(Python 3 不支持)。
r 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。
rb 以二進制格式打開一個文件用於只讀。文件指針將會放在文件的開頭。這是默認模式。通常用於非文本文件如圖片等。
r+ 打開一個文件用於讀寫。文件指針將會放在文件的開頭。
rb+ 以二進制格式打開一個文件用於讀寫。文件指針將會放在文件的開頭。通常用於非文本文件如圖片等。
w 打開一個文件只用於寫入。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。
wb 以二進制格式打開一個文件只用於寫入。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。通常用於非文本文件如圖片等。
w+ 打開一個文件用於讀寫。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。
wb+ 以二進制格式打開一個文件用於讀寫。若是該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。若是該文件不存在,建立新文件。通常用於非文本文件如圖片等。
a 打開一個文件用於追加。若是該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容以後。若是該文件不存在,建立新文件進行寫入。
ab 以二進制格式打開一個文件用於追加。若是該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容以後。若是該文件不存在,建立新文件進行寫入。
a+ 打開一個文件用於讀寫。若是該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。若是該文件不存在,建立新文件用於讀寫。
ab+ 以二進制格式打開一個文件用於追加。若是該文件已存在,文件指針將會放在文件的結尾。若是該文件不存在,建立新文件用於讀寫。

默認爲文本模式,若是要以二進制模式打開,加上 b 。

2. file 對象

file 對象使用 open 函數來建立,下表列出了 file 對象經常使用的函數:

序號 方法及描述
1

file.close()

關閉文件。關閉後文件不能再進行讀寫操做。

2

file.flush()

刷新文件內部緩衝,直接把內部緩衝區的數據馬上寫入文件, 而不是被動的等待輸出緩衝區寫入。

3

file.fileno()

返回一個整型的文件描述符(file descriptor FD 整型), 能夠用在如os模塊的read方法等一些底層操做上。

4

file.isatty()

若是文件鏈接到一個終端設備返回 True,不然返回 False。

5

file.next()

Python 3 中的 File 對象不支持 next() 方法。

返回文件下一行。

6

file.read([size])

從文件讀取指定的字節數,若是未給定或爲負則讀取全部。

7

file.readline([size])

讀取整行,包括 "\n" 字符。

8

file.readlines([sizeint])

讀取全部行並返回列表,若給定sizeint>0,返回總和大約爲sizeint字節的行, 實際讀取值可能比 sizeint 較大, 由於須要填充緩衝區。

9

file.seek(offset[, whence])

移動文件讀取指針到指定位置

10

file.tell()

返回文件當前位置。

11

file.truncate([size])

從文件的首行首字符開始截斷,截斷文件爲 size 個字符,無 size 表示從當前位置截斷;截斷以後後面的全部字符被刪除,其中 Widnows 系統下的換行表明2個字符大小。

12

file.write(str)

將字符串寫入文件,返回的是寫入的字符長度。

13

file.writelines(sequence)

向文件寫入一個序列字符串列表,若是須要換行則要本身加入每行的換行符。


十、Python3 OS 文件/目錄方法

os 模塊提供了很是豐富的方法用來處理文件和目錄。經常使用的方法以下表所示:

序號 方法及描述
1

os.access(path, mode)


檢驗權限模式
2

os.chdir(path)


改變當前工做目錄
3

os.chflags(path, flags)


設置路徑的標記爲數字標記。
4

os.chmod(path, mode)


更改權限
5

os.chown(path, uid, gid)


更改文件全部者
6

os.chroot(path)


改變當前進程的根目錄
7

os.close(fd)


關閉文件描述符 fd
8

os.closerange(fd_low, fd_high)


關閉全部文件描述符,從 fd_low (包含) 到 fd_high (不包含), 錯誤會忽略
9

os.dup(fd)


複製文件描述符 fd
10

os.dup2(fd, fd2)


將一個文件描述符 fd 複製到另外一個 fd2
11

os.fchdir(fd)


經過文件描述符改變當前工做目錄
12

os.fchmod(fd, mode)


改變一個文件的訪問權限,該文件由參數fd指定,參數mode是Unix下的文件訪問權限。
13

os.fchown(fd, uid, gid)


修改一個文件的全部權,這個函數修改一個文件的用戶ID和用戶組ID,該文件由文件描述符fd指定。
14

os.fdatasync(fd)


強制將文件寫入磁盤,該文件由文件描述符fd指定,可是不強制更新文件的狀態信息。
15

os.fdopen(fd[, mode[, bufsize]])


經過文件描述符 fd 建立一個文件對象,並返回這個文件對象
16

os.fpathconf(fd, name)


返回一個打開的文件的系統配置信息。name爲檢索的系統配置的值,它也許是一個定義系統值的字符串,這些名字在不少標準中指定(POSIX.1, Unix 95, Unix 98, 和其它)。
17

os.fstat(fd)


返回文件描述符fd的狀態,像stat()。
18

os.fstatvfs(fd)


返回包含文件描述符fd的文件的文件系統的信息,Python 3.3 相等於 statvfs()。
19

os.fsync(fd)


強制將文件描述符爲fd的文件寫入硬盤。
20

os.ftruncate(fd, length)


裁剪文件描述符fd對應的文件, 因此它最大不能超過文件大小。
21

os.getcwd()


返回當前工做目錄
22

os.getcwdu()


返回一個當前工做目錄的Unicode對象
23

os.isatty(fd)


若是文件描述符fd是打開的,同時與tty(-like)設備相連,則返回true, 不然False。
24

os.lchflags(path, flags)


設置路徑的標記爲數字標記,相似 chflags(),可是沒有軟連接
25

os.lchmod(path, mode)


修改鏈接文件權限
26

os.lchown(path, uid, gid)


更改文件全部者,相似 chown,可是不追蹤連接。
27

os.link(src, dst)


建立硬連接,名爲參數 dst,指向參數 src
28

os.listdir(path)


返回path指定的文件夾包含的文件或文件夾的名字的列表。
29

os.lseek(fd, pos, how)


設置文件描述符 fd當前位置爲pos, how方式修改: SEEK_SET 或者 0 設置從文件開始的計算的pos; SEEK_CUR或者 1 則從當前位置計算; os.SEEK_END或者2則從文件尾部開始. 在unix,Windows中有效
30

os.lstat(path)


像stat(),可是沒有軟連接
31

os.major(device)


從原始的設備號中提取設備major號碼 (使用stat中的st_dev或者st_rdev field)。
32

os.makedev(major, minor)


以major和minor設備號組成一個原始設備號
33

os.makedirs(path[, mode])


遞歸文件夾建立函數。像mkdir(), 但建立的全部intermediate-level文件夾須要包含子文件夾。
34

os.minor(device)


從原始的設備號中提取設備minor號碼 (使用stat中的st_dev或者st_rdev field )。
35

os.mkdir(path[, mode])


以數字mode的mode建立一個名爲path的文件夾.默認的 mode 是 0777 (八進制)。
36

os.mkfifo(path[, mode])


建立命名管道,mode 爲數字,默認爲 0666 (八進制)
37

os.mknod(filename[, mode=0600, device])
建立一個名爲filename文件系統節點(文件,設備特別文件或者命名pipe)。

38

os.open(file, flags[, mode])


打開一個文件,而且設置須要的打開選項,mode參數是可選的
39

os.openpty()


打開一個新的僞終端對。返回 pty 和 tty的文件描述符。
40

os.pathconf(path, name)


返回相關文件的系統配置信息。
41

os.pipe()


建立一個管道. 返回一對文件描述符(r, w) 分別爲讀和寫
42

os.popen(command[, mode[, bufsize]])


從一個 command 打開一個管道
43

os.read(fd, n)


從文件描述符 fd 中讀取最多 n 個字節,返回包含讀取字節的字符串,文件描述符 fd對應文件已達到結尾, 返回一個空字符串。
44

os.readlink(path)


返回軟連接所指向的文件
45

os.remove(path)


刪除路徑爲path的文件。若是path 是一個文件夾,將拋出OSError; 查看下面的rmdir()刪除一個 directory。
46

os.removedirs(path)


遞歸刪除目錄。
47

os.rename(src, dst)


重命名文件或目錄,從 src 到 dst
48

os.renames(old, new)


遞歸地對目錄進行改名,也能夠對文件進行改名。
49

os.rmdir(path)


刪除path指定的空目錄,若是目錄非空,則拋出一個OSError異常。
50

os.stat(path)


獲取path指定的路徑的信息,功能等同於C API中的stat()系統調用。
51

os.stat_float_times([newvalue])
決定stat_result是否以float對象顯示時間戳

52

os.statvfs(path)


獲取指定路徑的文件系通通計信息
53

os.symlink(src, dst)


建立一個軟連接
54

os.tcgetpgrp(fd)


返回與終端fd(一個由os.open()返回的打開的文件描述符)關聯的進程組
55

os.tcsetpgrp(fd, pg)


設置與終端fd(一個由os.open()返回的打開的文件描述符)關聯的進程組爲pg。
56

os.tempnam([dir[, prefix]])


Python3 中已刪除。返回惟一的路徑名用於建立臨時文件。
57

os.tmpfile()


Python3 中已刪除。返回一個打開的模式爲(w+b)的文件對象 .這文件對象沒有文件夾入口,沒有文件描述符,將會自動刪除。
58

os.tmpnam()


Python3 中已刪除。爲建立一個臨時文件返回一個惟一的路徑
59

os.ttyname(fd)


返回一個字符串,它表示與文件描述符fd 關聯的終端設備。若是fd 沒有與終端設備關聯,則引起一個異常。
60

os.unlink(path)


刪除文件路徑
61

os.utime(path, times)


返回指定的path文件的訪問和修改的時間。
62

os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])


輸出在文件夾中的文件名經過在樹中游走,向上或者向下。
63

os.write(fd, str)


寫入字符串到文件描述符 fd中. 返回實際寫入的字符串長度
64

os.path 模塊

獲取文件的屬性信息。
相關文章
相關標籤/搜索