Python基礎

第二章 變量和簡單數據類型

運行py文件時發生的情況
運行hello_world.py文件時,末尾的.py指出這是一個Python程序,因此編輯器將使用Python解釋器來運行它。Python解釋器讀取整個程序,確定每個單詞的含義。例如print,解釋器就將括號里的內容打印到屏幕上。

變量名只能包含字母、數字和下劃線,不能以數字開頭,而且應該全部小寫。

字符串拼接
first_name = 'ada'
last_name = 'lovelace'
full_name = first_name + " " + full_name

使用制表符或換行符來添加空白
print("Languages:\n\tPython\n\tJavaScript")

刪除空白
favorite_language = 'python '
favorite_language.rstrip()
strip()和lstrip()是刪除開頭的空格
rstrip()是刪除結尾的空格

第三章 列表

列表簡介
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
列表是有序集合,因此要訪問列表的任何元素,只需要將元素的位置或者索引告訴Python即可。
索引是從0開始
索引的最后一個是-1,倒數第二個是-2,以此類推。
修改列表元素
motocycles = ['honda', 'yamaha', 'suzuki']
mococycles[0]='ducati'

添加元素
1、在末尾添加
motocycles = [] #先創建空的列表
motocycles.append('ducati')

2、在列表中插入元素
motocycles = ['honda', 'yamaha', 'suzuki']
motocycles.insert(1, 'ducati')
方法insert()在索引1處添加空間,并將值'ducati'存儲到這個地方。這種操作將列表中排序1之后的每個元素都右移一個位置。

3、從列表中刪除元素
motocycles = ['honda', 'yamaha', 'suzuki']
del motocycles[0]

pop刪除
motocycles.pop()
彈出列表最后一個元素
彈出特定位置元素
motocycles.pop(1) #彈出第二個元素
被彈出的元素可以繼續復制使用
比如first_owned = motocycles.pop(0)
雖然列表中沒有該元素,但是該元素值可以繼續使用

4、根據值刪除元素
motocycles = ['honda', 'yamaha', 'suzuki']
motocycles.remove('honda')

組織列表
sort()對列表進行永久排序
sort(reverse=True)倒序排序

sorted()對列表進行臨時排序,原來的列表的順序并沒有變

reverse()反轉列表,這里的反轉是指元素的排列順序反轉

len()確定列表的長度

第四章 操作列表

遍歷列表list
motocycles = ['honda', 'yamaha', 'suzuki']
for moto in motocycles:
print(moto)

創建數字列表
使用函數range(),range()讓你能夠生成一系列的數字。
for value in range(1,5):
print(value)
打印不包括5

要創建數字列表,可以使用函數list()將range()的結果直接轉換為列表。
numbers = list(range(1,5))
print(numbers)

[1,2,3,4]

range()還可以指定步長,如range(2,11,2),從2開始,不斷的加2,直到11(不包括11)

數字列表的簡單計算
min(numbers)
max(numbers)
sum(numbers)

使用列表的一部分
切片
列表的部分元素-Python稱之為切片
players = ['charles', 'martina', 'michael, 'florence', 'eli']
提取第2-4個元素。
players[1:4]
如果沒有指定第一個索引,那就是從開頭開始
players[:4]
如果沒有指定第二個索引,那就直接到末尾
players[2:]
負數索引能夠讓你輸出特定位置到列表末尾的所有元素
players[-2:]
將輸出-1,-2兩個元素

遍歷切片
for player in players[1:3]:
print player

復制列表
假如我喜歡的食物,有一個朋友也喜歡,然后我喜歡的列表多了一樣,朋友喜歡的也多了一樣。
剛開始三樣一樣,如何復制列表?
my_foods =['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods

my_foods.append('cannoli')
friend_foods.append('ice cream')

print(my_foods)
print(friend_foods)
你會發現,這兩個列表輸出的一模一樣,而且cannoli和ice cream都在列表里面。為什么呢,因為friend_foods = my_foods并沒有復制列表,而只是新建了一個friend_foods變量,關聯到原來的my_foods上。所以,改動其實是在一個列表上。
那如何正確復制?利用切片。
my_foods =['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]

my_foods.append('cannoli')
friend_foods.append('ice cream')

print(my_foods)
print(friend_foods)

元組tuple
列表可以動態調整,使得滿足各種需求,如果你有不變的列表,那這樣的列表可以被稱為元組。

定義元組
元組看起來和列表類似,區別在于元組是圓括號,列表是方括號。

dimensions = (200, 50)
dimensions[0] = 250
這里復制會報錯,因為tuple不能被改變

遍歷元組
for dimension in dimensions:
print(dimension)
雖然不能更改單個元組某個元素的值,但是可以更改整個元組的值。
dimensions = (200, 50)
dimensions = (400, 100)
這里并不會報錯。

第五章 if語句

判斷相等 ==
判斷不等 !=
檢查特定值是否包含在列表中
request_topping=['mushrooms', 'onions', 'pineapple']
'mushrooms' in request_toppings

判斷特定值是否不包含在列表中
if 'mushrooms' not in request_toppings:

if else
if elif else
if

第六章 字典

字典:包含key-value鍵值對的數據結構。
alien={'color':'green', 'points':5}
可將任何字段用作key,包括數字、字符串、列表乃至字典。

訪問字典中的值
alien['color']

添加鍵值對
alien['x_position']=0
alien['y_position']=250

空字段
alien={}

修改字典中的值
alien['color']=‘yellow'

刪除鍵值對
del alien['points']

遍歷字典
for key,value in alien:
print(key,value)
注意,鍵值對返回的順序和存儲順序不同,Python不關心鍵值對的存儲順序,而只關心鍵值對之間的關聯關系。

遍歷字典中的所有鍵
for key in alien.keys():#for key in alien效果一樣

按順序遍歷字典中所有鍵
要以特定的順序返回元素,一種方法是在for循環中對返回的鍵進行排序,為此,可以用sorted()來排序
for key in sorted(alien.keys()):

遍歷字典中所有值
for value in alien.values():

如果值有重復,那輸出重復的值沒有意義,如何去重:可以使用集合
for value in set(alien.values()):

嵌套
字典列表
alien_0={'color':'green', 'points':5}
alien_1={'color':'yellow', 'points':10}

aliens = [alien_0, alien_1]

在字典中存儲列表
pizza = {'crust':'thick', 'topping': ['mushroom','extra cheese'],}

在字典中存儲字典

用戶輸入和while循環

name = input("Please enter your name:")
print(name)
input()將用戶輸入解讀為字符串
如果輸入的是數字字符串,可以通過int()將其轉化成數字

求模運算符
4%3
求模運算符,將兩個數相除并符合余數。

active = True
while active:
message=input()
if message == 'quit':
active = False
else:
print(message)

另一種寫法:break
使用break退出循環
while True:
message=input()
if message == 'quit':
break
else:
print(message)

continue:繼續使用循環,從頭開始執行
打印10以內的奇數
current_number = 0
while current_number < 10:
current_number += 1
if current_number % 2 == 0:
continue
print(current_number)

for循環是一種遍歷列表的有效方式,但在for循環中不應該修改列表,否則將導致python難以跟蹤其中元素。如果要在遍歷列表的同時對其修改,可以使用while循環。

unconfirmed_users = ['alice','brain', 'candace']

while unconfirmed_users:
current_user = unconfirmed_users.pop()

刪除包含特定值的所有列表元素
pets = ['dog','cat','dog','goldfish','cat','rabbit','cat']

while 'cat' inpets:
pets.remove('cat')

函數

def greet_user(username):
print("hello!," + username.title() + "!")

greet_user('sarah')
實參和形參
username是一個形參,'sarah'是一個實參。將實參'sarah'傳遞給函數的形參username,值被存儲在形參username中。

位置實參
def describe_pet(animal_type, pet_name):
print("\nI have a " + animal_type +".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('dog', 'willie')
調用函數時,Python必須將函數調用中的每個實參都關聯到函數定義中的一個形參,最簡單的關聯方式就是基于實參的順序。這種關聯方式稱為位置實參。

關鍵字實參
關鍵字實參是傳遞給函數的名稱-值對。你直接在實參中將名稱和值關聯起來。因此向函數傳遞實參時不會混淆。關鍵字實參讓你無需考慮函數調用中的實參順序,還清楚的指出了函數調用中各值的用途。
describe_pet(animal_type = 'dog', pet_name = 'willie')

默認值
def describe_pet(pet_name, animal_type='dog'):
print("\nI have a " + animal_type +".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet(pet_name='willie')
也可以通過位置實參調用
describe_pet('willie')
使用默認值時,在形參列表中必須先列出沒有默認值的形參,再列出有默認值的形參。這讓Python依然能夠正確解讀位置參數。

返回值
def get_formatted_name(first_name, last_name):
full_name = first_name + ' ' + last_name
return full_name.title()

返回字典
def build_person(first_name,last_name):
person = {'first_name':first_name,'last_name':last_name}
return person

禁止函數修改列表
有時候,我們需要禁止修改列表。為了解決這個問題,可以向函數傳遞列表的副本,而不是列表本身,這樣對列表的修改只是在副本上。不會影響列表本身。也就是傳遞列表的切片
function(last_name(:))

傳遞任意數量的實參
一個制作披薩的函數,它需要接受很多配料,但你無法預先確定顧客要多少種配料。
def make_pizza(*toppings):
for topping in toppings:
print("- " + topping)

make_pizza('pepperoni')
make_pizza('mushrooms','green peppers','extra cheese')
形參名*toppings中的星號讓Python創建一個名為toppings的空元組,并將收到的所有值都封裝到這個元組中。

結合使用位置實參和任意數量實參
如果要讓函數接受不同類型的實參,必須在函數定義中將接納任意數量實參的形參放在最后。Python先匹配位置實參和關鍵字實參,再將余下的實參都收集到最后一個形參中。
def make_pizza(size, *toppings):
print("\nMaking a "+ str(size) + "-inch pizza with following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza(16,'pepperoni')
基于函數定義,Python將第一個值存儲在形參中,并將其他所有值存儲在元組toppings中。

使用任意數量的關鍵字實參
def build_profile(first, last, **user_info):
profile={}
profile['first_name'] = first
profile['last_name'] = last
for key,value in user_info:
profile[key] = value
return profile

build_profile('albert', 'einstein', location='princeton', field='physics')
函數的定義要求提供名和姓,同時允許用戶根據需要提供任意數量的名稱-鍵值對,形參*user_inmfo中的兩個號讓Python創建一個名為user_info的空字典。并將收到的所有鍵值對都封裝到這個字典中。可以像訪問其他字典那樣訪問user_info鍵值對

將函數存儲在模塊中,可以通過import來使用模塊中的函數
導入整個模塊

pizza.py
def make_pizza(size, *toppings):
print("\nMaking a "+ str(size) + "-inch pizza with following toppings:")
for topping in toppings:
print("- " + topping)

我們在pizza.py目錄創建另一個making_pizzas.py文件,導入pizzs模塊,再調用make_pizza()兩次
making_pizzas.py
import pizza

pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms','green peppers','extra cheese')

Python讀取這個文件時,代碼行import pizza讓Python打開文件pizza.py,并將其中的所有的函數都復制到這個程序中。調用方法就是模塊名,后面加.,最后再加函數名
module_name.fuction_name()

導入特定函數
from module_name import fuction_name0, fuction_name1
通過這種方式導入的函數,可以直接用fuction_name0()進行調用

使用as給指定函數指定別名
如果要導入的函數的名稱可能與程序中的現有名稱沖突,或者函數名稱太長,可指定簡短且獨一無二的別名。
from module_name import function_name as fn

from pizza import make_pizza as mp

mp(16, 'pepperoni')
mp(12, 'mushrooms','green peppers','extra cheese')

使用as給模塊指定別名
import module_name as mn

import pizza as p

p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms','green peppers','extra cheese')

導入模塊中所有函數
from pizza import *

make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms','green peppers','extra cheese')

import語句中的*讓Python將模塊pizza中的每個函數都復制到這個程序文件中。由于導入了每個函數,可通過名稱來調用每個函數,而無需使用句點表示法。然而,使用并非自己編寫的大型模塊時,最好不要采用這種導入方法:如果模塊中有函數的名稱與你的項目中使用的名稱相同,可能導致意想不到的結果:Python可能遇到多個名稱相同的函數活變量,進而覆蓋函數,而不是分別導入所有的函數。
最佳的做法是,要么只導入你需要用的函數,要么導入整個模塊并使用句點法

函數編寫指南
1、函數名稱只用小寫字母和下劃線
2、函數都應包含簡要闡述期功能的注釋
3、參數的意義的注釋

第九章 類

創建dog類

class Dog():
    """一次模擬小狗的簡單嘗試"""
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def sit(self):
        print(self.name.title() + " is now sitting.")
        
    def roll_over(self):
        print(self.name.title() + " rolled over.")

方法 init()
類中的函數稱為方法,init()是一個特殊的方法,每當你根據Dog類創建新實例時,Python就會自動運行它。在這個方法的名稱中,開頭和結尾各有兩個下劃線,這是一種約定,旨在避免Python默認方法與普通方法發生沖突。

init()包含三個形參,self、name和age。在這個方法的定義中,形參self必不可少,還必須位于其他形參的前面。因為Python調用init()方法創建Dog實例時,將自動傳入實參self。每個與類相關聯的方法調用都自動傳遞實參self,它是指向實例本身的引用,讓實例能夠訪問類中的屬性和方法。我們創建Dog實例時,Python將調用Dog類的方法,init(),我們將通過實參向Dog()傳遞名字和年齡,self會自動傳遞。

init方法里面兩個變量都有前綴self,以self為前綴的變量都可供類中的所有方法使用,我們還可以通過類的任何實例訪問這些變量。self.name=name獲取存儲在形參name中的值,并將其存儲到變量name中,然后將該變量關聯到當前創建的實例。像這樣可通過實例訪問的變量稱為屬性。

Dog類還定義了另外兩個方法:sit()和roll_over()。由于這些方法不需要額外的參數,因此他們只有一個形參self。

根據類創建實例
my_dog = Dog('willie', 6)###調用init()創建特定小狗實例

print("My dog's name is " + my_dog.name.title() + ".")
print("My dog's is " + str(my_dog.age) + " years old.")

訪問屬性
要訪問實例的屬性,可使用句點法表示。my_dog.name

調用方法
my_dog.sit()

使用類和實例

class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

my_new_car = Car("audi", "a4", 2016)

給屬性指定默認值

class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer = 0
        
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
        
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")

修改屬性的值
my_new_car.odometer = 23
my_new_car.read_odometer()

通過方法修改屬性的值

class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer = 0
        
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
        
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")
    def update_odometer(self, mileage):
        self.odomter = mileage

my_new_car.update_odometer(23)

通過方法對屬性的值進行遞增
def increment_odometer(self, miles):
self.odometer += miles

my_new_car.increment_odometer(50)

class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer = 0
        
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
        
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")
    def update_odometer(self, mileage):
        self.odomter = mileage
        
    def increment_odometer(self, miles):
        self.odometer += miles
        
class  ElectricCar(Car):
    """電動汽車的獨特之處"""
    
    def __init__(self, make, model, year):
        super().__init__(make, model, year)

my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())

創建子類時,父類必須包含在當前文件中,且位于子類之前。
super()函數是一個特殊函數,幫助Python將父類和子類關聯起來。

給子類定義屬性和方法

class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer = 0
        
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
        
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")
    def update_odometer(self, mileage):
        self.odomter = mileage
        
    def increment_odometer(self, miles):
        self.odometer += miles
        
class  ElectricCar(Car):
    """電動汽車的獨特之處"""
    
    def __init__(self, make, model, year):
        super().__init__(make, model, year)
        self.battery_size = 70
        
    def describe_battery(self):
        print("This car has a " + str(self.battery_size) + "-kwh battery.")

my_tesla.describe_battery()

重寫父類方法
假設Car類有一個名為fill_gas_tank()的方法,它對電動汽車毫無意義,因此可以重寫他

class  ElectricCar(Car):
    --snip--
    
    def fill_gas_tank(self):
        print("This car doesn't need a gas tank!")

將實例用作屬性
可能需要將類的一部分作為一個獨立的類提取出來。可以將大型類拆分成多個協同工作的小類。

class  Car():
    --snip--
  
class  Battery():
    def __init__(self,battery_size=70):
        self.battery_size = battery_size
        
    def describe_battery(self):
        print("This car has a " + str(self.battery_size) + "-kwh battery.")
        
class  ElectricCar(Car):
    def __init__(self,make, model, year):
        super().__init__(make, model, year)
        self.battery = Battery()

my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()

導入類
由于類不斷的添加功能,文件變的很長,為了讓文件盡可能整潔,Python允許你將類存儲在模塊中,然后在主程序中導入所需模塊

導入單個類
car.py

"""一個可用于表示汽車的類"""

class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer = 0
        
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
        
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")
    def update_odometer(self, mileage):
        self.odomter = mileage
        
    def increment_odometer(self, miles):
        self.odometer += miles

my_car.py

from car import Car##從文件中導入類,可用利用逗號,一次引入多個類

my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())

my_new_car.odometer  = 23
my_new_car.read_odometer()

導入整個模塊
可用import car導入整個模塊。接下來,我們使用module_name.class_name訪問需要的類

導入模塊所有類
from car import *
不推薦這種導入方式,其原因有二:
1、如果只要看一下文件開頭的import語句,就能清楚知道程序使用了哪些類,將大有裨益。但這種方式并沒有明確你使用了模塊中哪些類
2、這種導入方式還可能引發名稱方面的困惑。如果你不小心導入了一個與程序文件中其他同名的類,可能引發錯誤。

在一個模塊中引入另一個模塊
這個用法和普通的模塊引入沒有任何區別,比如把Car類和ElectricCar分成兩個模塊文件,任何在ElectricCar里面from car import Car
后面如果需要導入Car和ElectricCar類的時候,不能以為ElectricCar類里面導入了Car就不需要再導入了。所以,Car類和ElectricCar類都需要單獨導入。

類編碼風格
1、類名應采取駝峰命名法,將類名中的每個首字母大寫,而不使用下劃線。實例名和模塊名都是小寫格式,并在單詞之間加上下劃線。
2、對于每個類,都應緊跟在類定義后面包含一個文檔字符串。描述累的功能。每個模塊也都要包含一個文檔字符串,對其中的類的行為進行描述
3、在類中,可使用一個空行來分隔方法;而在模塊中,可使用兩個空行來分隔類。
4、需要同時導入標準庫中的模塊和你自己編寫的模塊時,先導入標準庫模塊的import語句,再添加一個空行,然后再編寫導入你自己編寫的模塊的import語句。這種做法讓人更容易明白程序使用的各個模塊來自何方。

總結:
除了類名是駝峰命名法,首字母大寫,其他比如實例、模塊名、函數名、方法名、變量名都是小寫加下劃線,導入變量名還可以加數字。

第十章 文件和異常

with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)

這里有調用open(),但是沒有調用close()。用with打開文件,Python會自動在合適的時候調用close()關閉文件。
這個輸出會多一行,原因在于read()到達文件末尾時返回一個空字符串,而將這個空字符串顯示出來就是一個空行。要刪除空行,可以在print里面使用rstrip()
print(contents.rstrip())

上面的open的文件沒有帶路徑,Python會自動搜索程序文本所在的當前文件夾。

文件路徑
相對路徑
linux和os x系統
with open('text_files/filename.txt') as file_object

windows系統
with open('text_files\filename.txt') as file_object

絕對路徑
linux和os x系統
file_path = '/home/ehmatthes/text_files/filename.txt'
with open(file_path) as file_object

windows系統
file_path = 'C:\Users\ethmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object

逐行讀取
filename = 'pi_digits.txt'

with open(filename) as file_object:
for line in file_object:
print(line.rstrip())

調用open后,將一個表示文件及其內容的對象存儲到變量file_object中。

創建一個包含文件各行內容的列表
filename = 'pi_digits.txt'

with open(filename) as file_object:
for line in file_object:
lines = file_object.readlines()

for line in lines:
print(line.strip())

lines列表中的每個元素就是file_object的每一行內容。

filename = 'pi_millon_digits.txt'

with open(filename) as file_object:
lines = file_object.readlines()

pi_string = ''
for line in lines:
pi_string += line.strip()

print(pi_string[:52] + "...")

圓周率是否包含你的生日

filename = 'pi_millon_digits.txt'

with open(filename) as file_object:
lines = file_object.readlines()

pi_string = ''
for line in lines:
pi_string += line.strip()

birthday = input("Enter your birthday, in the form mmddyy:")
if birthday in pi_string:
print("Your birthday appears in the first millon digits of pi!")
else:
print("Your birthday does not appears in the first millon digits of pi!")

寫入文件
filename = 'programming.txt'

with open(filename,'w') as file_object:
file_object.write("I love programming.")

調用open時,提供了兩個參數,第一個參數是要打開的文件的名稱,第二個參數'w'告訴Python,我們要以寫入的方式打開文件。
打開文件有幾種模式
w-寫入模式
r-只讀模式
a-附加模式
r+-讀取和寫入模式
如果省略模式實參,那Python默認以只讀打開

如果要寫入的文件不存在,函數open()自動創建它。以'w'模式打開文件要小心,如果文件以及存在,Python將返回對象前清空該文件。

Python只能將字符串寫入文本文件。要將數值數據存儲到文本文件,必須先試用str()函數將其轉換為字符串格式。

寫入多行
file_object.write("I love programming.\n")
file_object.write("I love creating new game.\n")
如果不加換行符,則會連成一行

附加到文件
如果你想給文件添加內容,而不是覆蓋原有的內容,可以附加模式打開文件。你以附加模式打開文件時,Python不會再返回文件對象前清空文件,而你寫入到文件的行都將添加到文件末尾。如果你指定的文件不存在,Python將為你創建一個空文件。

異常
filename = 'alice.txt'

try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
else:
words = contents.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) + " words.")

存儲數據
使用json.dump()和json.load()
函數json.dump()接受兩個實參,要存儲的數據以及可用于存儲數據的文件對象。

import json

filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except: FileNotFoundError:
username = input("What is your name?")
with open(filename,'w') as f_obj:
json.dump(username, f_obj)
print("We'll remeber you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")

第十一章 測試代碼

name_function.py
def get_formatted_name(first_name, last_name):
full_name = first_name + ' ' + last_name
return full_name.title()

names.py

from name_function import get_formatted

print("Enter 'q' at any time to quit.")
while True:
    first = input("\nPlease give me a first name:")
    if first == 'q':
        break
    last = input("\nPlease give me a last name:")
    if last == 'q':
        break
        
    formatted_name = get_formatted_name(first,last)
    print("\tNeatly formatted name:" + formatted_name + '.')

單元測試
test_name_function.py

import unittest
from name_function import get_formatted_name

class NameTestCase(unittest.TestCase):
    """測試name_function.py"""
    
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')
        
unittest.main()

首先我們創建了一個名為NameTestCase的類,用于包含一系列針對get_formatted_name()的單元測試。你可以隨便給這個類命名,但最好讓它看起來與測試的函數相關,并包含Test字樣。這個類必須繼承unittest.TestCase類,這樣Python才知道如何運行你編寫的測試。
NameTestCase只包含一個方法,用于測試get_formatted_name()的一個方面。我們將這個方法命名為test_first_last_name()。
我們運行test_name_function.py時,所有以test_打頭的方法都將自動運行。

方法里,我們使用了unittest類最常用的功能之一:一個斷言方法。斷言方法用來合適得到的結果是否與期望的結果一致。
unittest斷言方法

方法 用途
assertEqual(a,b) 核實a==b
assertNotEqual(a,b) 核實a!=b
assertTrue(x) 核實x為True
assertFalse(x) 核實x為False
assertIn(item, list) 核實item在list中
assertNotIn(item, list) 核實item不在list中

測試類
survey.py

class AnonymousSurvey():
    """收集匿名調查問卷答案"""

    def __init__(self, question):
        self.question = question
        self.responses = []

    def show_question(self):
        print(self.question)

    def store_response(self, new_response):
        self.responses.append(new_response)

    def show_results(self):
        print("Survey results:")
        for response in self.responses:
            print('- ' + response)

測試AnonymousSurvey類
test_survey.py

import unittest
from survey import AnonymousSurvey


class TestAnonymousSurvey(unittest.TestCase):
    """針對AnonymousSurvey類的測試"""

    def setUp(self):
        question = "What language did you first leanr to speak?"
        self.my_survey = AnonymousSurvey(question)
        self.responses = ['English', 'Spanish', 'Mandarin']

    def test_store_single_response(self):
        self.my_survey.store_response(self.responses[0])
        self.assertIn(self.responses[0], self.my_survey.responses)

    def test_store_three_response(self):
        for response in self.responses:
            self.my_survey.store_response(response)

        for response in self.responses:
            self.assertIn(response, self.my_survey.responses)

unittest.main()

方法setUp()
在前面的測試代碼中,我們在測試方法中都單獨創建了AnonymousSurvey的實例。
有沒有辦法進行優化?
可以使用setUp(),讓我們只需創建這些對象一次,并在每個測試方法中運用它們。
如果你在TestCase類中包含方法setUp(),Python將先運行它,再運行各個以test_打頭的方法。

import unittest
from survery import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """針對AnonymousSurvey類的測試"""
    
    def setUp(self):
        question = "What language did you first leanr to speak?"
        self.survey = AnonymousSurvey(question)
        self.responses = ['English', 'Spanish', 'Mandarin']
    
    def test_store_single_response(self):
        my_survey.store_response(self.responses[0]) 
        self.assertIn(self.responses[0], my_survey.response)
        
    def test_store_three_response(self):
        for response in responses:
            my_survey.store_response(response)
            
        for response in responses:
            self.assertIn(response, my_survey.responses)
unittest.main()
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。