python_基礎語法總結

python基礎

1.變量及數據類型

變量

變量命名規範

  • 變量名只能包含字母、數字和下劃線。變量名可以字母或下劃線打頭,但不能以數字打
    頭,例如,可將變量命名爲message_1,但不能將其命名爲1_message。
  • 變量名不能包含空格,但可使用下劃線來分隔其中的單詞。例如,變量名greeting_message
    可行,但變量名greeting message會引發錯誤。
  • 不要將Python關鍵字和函數名用作變量名,即不要使用Python保留用於特殊用途的單詞,
    如print
  • 變量名應既簡短又具有描述性。例如, name比n好, student_name比s_n好, name_length
    比length_of_persons_name好。
  • 慎用小寫字母l和大寫字母O,因爲它們可能被人錯看成數字1和0。

私有變量的定義

在Python中,有以下幾種方式來定義變量:

  • xx:公有變量
  • _xx:單前置下劃線,私有化屬性或方法,類對象和子類可以訪問,from somemodule import *禁止導入
  • __xx:雙前置下劃線,私有化屬性或方法,無法在外部直接訪問(名字重整所以訪問不到)
  • xx:雙前後下劃線,系統定義名字(不要自己發明這樣的名字)
  • xx_:單後置下劃線,用於避免與Python關鍵詞的衝突
# PEP8代碼格式:
1. 縮進
    - PEP 8建議每級縮進都使用四個空格,這既可提高可讀性,又留下了足夠的多級縮進空間
2. 行長
    - 很多Python程序員都建議每行不超過80字符。最初制定這樣的指南時,在大多數計算機中,
終端窗口每行只能容納79字符;
    - 將程序的不同部分分開,可使用空行。
3. 類名
    - 類名應採用駝峯命名法,即將類名中的每個單詞的首字母都大寫,而不使用下劃線。實例名
和模塊名都採用小寫格式,並在單詞之間加上下劃線。
    - 對於每個類,都應緊跟在類定義後面包含一個文檔字符串。這種文檔字符串簡要地描述類的
功能,並遵循編寫函數的文檔字符串時採用的格式約定。每個模塊也都應包含一個文檔字符串,
對其中的類可用於做什麼進行描述。
    - 可使用空行來組織代碼,但不要濫用。在類中,可使用一個空行來分隔方法;而在模塊中,
可使用兩個空行來分隔類。
    - 需要同時導入標準庫中的模塊和你編寫的模塊時,先編寫導入標準庫模塊的import語句,再
添加一個空行,然後編寫導入你自己編寫的模塊的import語句。
5. 函數名
    - 應給函數指定描述性名稱,且只在其中使用小寫字母和下劃線。描述性名稱可幫助你和別人明白代碼想要做什麼。給模塊命名時也應遵循上述約定。
    - 每個函數都應包含簡要地闡述其功能的註釋,該註釋應緊跟在函數定義後面,並採用文檔字
符串格式。文檔良好的函數讓其他程序員只需閱讀文檔字符串中的描述就能夠使用它:他們完全
可以相信代碼如描述的那樣運行;只要知道函數的名稱、需要的實參以及返回值的類型,就能在
自己的程序中使用它。
    - 給形參指定默認值時,等號兩邊不要有空格:
    - 如果程序或模塊包含多個函數,可使用兩個空行將相鄰的函數分開,這樣將更容易知道前一
個函數在什麼地方結束,下一個函數從什麼地方開始。
    - 所有的import語句都應放在文件開頭,唯一例外的情形是,在文件開頭使用了註釋來描述整
個程序。

數據類型

  • 數值
    • 整形: int
    • 浮點型: float
      • 注意:python2中float數據作除法得到的是整數,python3中得到的是小數。
    • 布爾型 :boolTrue/Flase
    • 複數型: complex (在python中用小寫 j ,表示虛部,用其他的字母不行)
  • 字符串(str)
  • 列表(list)
  • 元組(tuple)
  • 集合(set)
  • 字典(dict)

可變數據:list, dict, set
不可變數據:num, str, tuple

序列

  • 字符串 str
  • 列表 list
  • 元組 tuple
  • 可變序列:list
  • 不可變序列:tuple,str

運算符

算術運算符:+-*/%**//
    賦值運算符:=+=-=*=/=%=**=
    比較運算符:==!=><>=<=
    成員運算符:in , not in
    身份運算符:is , is not
        判斷兩個名字是否指向同一個對象,當id相同時返回True(==比較運算是判斷的值)
    邏輯運算符:andornot
        and() 兩個條件都滿足時才返回True
        or()  有一個條件滿足了就返回True
        not() 取反

    計算順序:默認地,運算符優先級表決定了哪個運算符在別的運算符之前計算。然而,如果你想要改變它們的計算順序,你得使用圓括號
    結合規律:運算符通常由左向右結合,即具有相同優先級的運算符按照從左向右的順序計算
'''
**                            #冪運算
+   -  *   /   %              #算術運算符
<  >  <=  >=                  #比較運算符
==  !=                        #比較運算符
=  %=  /=  -=  +=  *=  **=    #賦值運算符
is    is not                  #身份運算符
in    not in                  #成員運算符
not  >  and  > or             #邏輯運算符
'''

2. 字符串

s = ' AsDasA '
s.count(x):返回字符串x在s中出現的次數,帶可選參數
s.endswith(x):如果字符串s以x結尾,返回True
s.startswith(x):如果字符串s以x開頭,返回True
s.find(x) :返回字符串中出現x的最左端字符的索引值,如果不在則返回-1
s.index(x):返回字符串中出現x的最左端的索引值,如果不在則拋出valueError異常
s.isalpha ()  :測試是否全是字母,都是字母則返回 True,否則返回 False.
s.isdigit () :測試是否全是數字,都是數字則返回 True 否則返回 False.
s.islower () :測試是否全是小寫
s.isupper () :測試是否全是大寫
s.lower () :將字符串轉爲小寫
s.upper () :將字符串轉爲大寫 
s.replace (x,y) :子串替換,在字符串s中出現字符串x的任意位置都用y進行替換
s.split():返回一系列用空格分割的字符串列表
s.split(a,b):a,b爲可選參數,a是將要分割的字符串,b是說明最多要分割幾個
s.title() : 返回字符串,首字母大寫,其它字母均小寫´(Asdas)
s.rstrip() : 剔除字符串末尾空白
s.lstrip() : 剔除字符串開頭的空白
s.strip()  : 同時剔除字符串兩端的空白

字符串拼接、格式化輸出

字符串拼接

例: a = 'hello'  ,    b = 'python'   ,   c = '!'     將a,b ,c 中的字符串連成一句話。  
    第一種方法:用  +   號      
       a + b +c    
    第二種方法:格式化字符串  %s   
      '%s %s %s' % (a , b ,c)  
    第三種方法:''.join()方式,注意括號裏是要連接的可以是列表,元祖   
          ' '.join([a,b,c])  (注:''裏面是連接後面各個字符串的字符)
    第四種方法:.format方式
       '{}{}{}'.format(a,b,c)    (注:{}裏面可以填入與後面相對應的符號)
    
    format方法詳解:
    '{}{}{}'.format(a,b,c){}裏面是空的時候,裏面默認索引爲012format括號裏的順序依次填入
    '{1}{2}{0}'.format(a,b,c){}裏面有索引值時,按前面的索引值將後面的每項依次填入
    '{n1}{n2}{n3}'.format(n1=a,n2=b,n3=c)
    {}裏面可以指定對象名稱,後面通過賦值的方式給前面的相應的值,後面是無序的

格式化輸出

%s 格式化字符串
%d 格式化整數
%f 格式化小數 `%1.f~%n.f`
%c 格式化ASCII字符
%o 格式化八進制
%x 格式化十六進制
%e 用科學計數法格式化
    
-  用作左對齊
+ 用在正數前面顯示加號
m.n  m是顯示的最小長度,當m大於格式化位數時才起作用顯示m位,n是代表小數的位數。
            
轉義字符
    \n 換行   \a提示音  \b退格鍵    \t橫向製表符 
    
    自然字符串  r' '   # 在字符串前加上這個修飾,字符串內容將不會轉義

3. 列表/元組

列表

列表由一系列按特定順序排列的元素組成。用方括號([])來表示列表,並用逗號來分隔其中的元素。

L.append(obj) 在列表末尾添加新的對象。
L.clear() 清空整個列表。
L.copy() 複製列表。
L.count(obj) 統計某個元素在列表中出現的次數。
L.extend(obj) 用obj擴展原來的列表。 
L.index(obj) 從列表中找某個值第一個匹配項的索引位置。
L.insert(index,obj) 插入元素,可以指定位置。
L.pop(index) 出棧,可以指定位置。index默認是L[-1]
L.remove(obj) 移除指定元素從左邊開始的第一個。
L.reverse() 反向列表中元素。
L.sort() 對原列表進行排序。列表中的元素要類型相同  (key = len)
L.sort(reverse=True) 由大到小排序
    
內置函數:
sorted(L): 臨時由小到大排序 
sorted(L, reverse=True): 臨時由大到小排序 
reversed():逆序

list增刪改查

查找

當你請求獲取列表元素時, Python只返回該元素,而不包括方括號和引號

bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[0])

Python爲訪問最後一個列表元素提供了一種特殊語法。通過將索引指定爲-1,可讓Python返
回最後一個列表元素:

bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[-1])

例如,索引-2返回倒數第二個列表元素,索引-3返回倒數第三個列表元素,以此類推。

修改

修改列表元素的語法與訪問列表元素的語法類似。要修改列表元素,可指定列表名和要修改
的元素的索引,再指定該元素的新值。
例如,假設有一個摩托車列表,其中的第一個元素爲’honda’,如何修改它的值呢?

motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)

motorcycles[0] = 'ducati'
print(motorcycles)
增加
  1. 在列表末尾添加元素

方法append()將元素添加到列表末尾,而不影響列表中的其他所有元素

motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)

motorcycles.append('ducati')
print(motorcycles)
  1. 在列表中插入元素

使用方法insert()可在列表的任何位置添加新元素。爲此,你需要指定新元素的索引和值。

motorcycles = ['honda', 'yamaha', 'suzuki']

motorcycles.insert(0, 'ducati')
print(motorcycles)
刪除

你經常需要從列表中刪除一個或多個元素。例如,當用戶在你創建的Web應用中註銷其賬戶時,你需要將該用戶從活躍用戶列表中刪除。你可以根據位置或值來刪除列表中的元素。

  1. 使用del語句刪除元素

如果知道要刪除的元素在列表中的位置,可使用del語句。

motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)

del motorcycles[0]
print(motorcycles)

使用del可刪除任何位置處的列表元素,條件是知道其索引。使用del語句將值從列表中刪除後,你就無法再訪問它了。
2. 使用方法pop()刪除元素

你要將元素從列表中刪除,並接着使用它的值。方法pop()可刪除列表末尾的元素,並讓你能夠接着使用它。術語彈出(pop)源自這樣的類比:列表就像一個棧,而刪除列表末尾的元素相當於彈出棧頂元素。

 motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)

popped_motorcycle = motorcycles.pop()
print(motorcycles)
print(popped_motorcycle)
  1. 彈出列表中任何位置處的元素

使用pop()來刪除列表中任何位置的元素,只需在括號中指定要刪除的元素
的索引即可。

motorcycles = ['honda', 'yamaha', 'suzuki']

first_owned = motorcycles.pop(0)
print('The first motorcycle I owned was a ' + first_owned.title() + '.')

注意: 每當你使用pop()時,被彈出的元素就不再在列表中了。
如果你不確定該使用del語句還是pop()方法,下面是一個簡單的判斷標準:如果你要從列表
中刪除一個元素,且不再以任何方式使用它,就使用del語句;如果你要在刪除元素後還能繼續
使用它,就使用方法pop()。

  1. 根據值刪除元素

你不知道要從列表中刪除的值所處的位置。如果你只知道要刪除的元素的值,可使
用方法remove()。

motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
print(motorcycles)

motorcycles.remove('ducati')
print(motorcycles)

使用remove()從列表中刪除元素時,也可接着使用它的值。

motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
print(motorcycles)
too_expensive = 'ducati'
motorcycles.remove(too_expensive)
print(motorcycles)
print("\nA " + too_expensive.title() + " is too expensive for me.")

注意 方法remove()只刪除第一個指定的值。如果要刪除的值可能在列表中出現多次,就需要
使用循環來判斷是否刪除了所有這樣的值。

列表排序

  • li.sort() : 對列表進行永久性正排序
  • li.sort(reverse=True) : 對列表進行永久性逆排序
  • sorted(li): 對列表進行臨時正排序
  • sorted(li,reverse=True): 對列表進行臨時逆排序
  • li.reverse(): 反轉列表元素的排列順序。方法reverse()永久性地修改列表元素的排列順序,但可隨時恢復到原來的排列順序,爲此只需對列表再次調用reverse()即可。
  • len(li)

避免數據索引超出範圍

操作列表

遍歷列表

for 循環遍歷列表

li = []
for i in li:
    print(i)
range()
# 1. range生成列表
li = []
for i in range(1,5):
    li.append(i)
print(li)

# 2. range()生成列表
li1 = list(range(1,5)) # [1, 2, 3, 4]
li2 = list(range(1,5,2)) # [1, 3]

# 3. 列表推到式
li3 = [i*2 for i in range(1,5,2)] 

# 4. 迭代器
li4 = (i*2 for i in range(1,5)) 
# <generator object <genexpr> at 0x00000257FE4ECA20>
切片

可指定要使用的第一個元素和最後一個元素的索引。與函數range()一樣,Python
在到達你指定的第二個索引前面的元素後停止。(左閉右開)

  • li[a,b]:[a,b)
  • li[:b] :[0,b)
  • li[a:]:[a,len(li))/[a,-1]
  • li[-3:]:[-3,-1]

複製列表:
要複製列表,可創建一個包含整個列表的切片,方法是同時省略起始索引和終止索引([:])。
這讓Python創建一個始於第一個元素,終止於最後一個元素的切片,即複製整個列表。

  • li_new = li # 複製的li_new是一個會跟隨原列表li變化而變化的列表。
  • li_new = li[:] # 複製的列表是一個全新的列表,不會受li影響。類似於深複製和淺複製。

元組

元組看起來猶如列表,但使用圓括號而不是方括號來標識。定義元組後,就可以使用索引來
訪問其元素,就像訪問列表元素一樣。

count(obj)統計某個元素在元組中出現的次數
index(obj)從列表中找某個值第一個匹配項的索引位置
注意:聲明只有一個元素的元組時要加逗號
特點:不可變

遍歷

同列表

修改元組變量

這裏是修改元組變量的值,而不是元組的值。

dimensions = (200, 50)
print("Original dimensions:")
    for dimension in dimensions:
        print(dimension)

dimensions = (400, 100)
print("\nModified dimensions:")
    for dimension in dimensions:
        print(dimension)

4. 集合/字典

集合

創建:{} set([])  注意:創建空的集合要用set()
    特點:元素唯一,無序
    運算: & 交集  | 並集  - 差集
    方法: 
    s.add(x)     添加單個元素
    s.update()   添加多個元素
    s.remove()   移除元素
    s.clear()    清空集合

字典

創建: {key:value} (大括號創建字典的鍵時要加引號)
    dict(key=value) (括號裏賦值方式,名字=對象,不要引號)
    字典裏的鍵和值用‘:’隔開,一對鍵和值組成一個項,項和項之間用‘,’隔開
特點:
- 鍵值唯一,重複會被重新複製
- 無序
    
添加和取值
    cidt[key]=value  key存在則修改值,沒有則添加
屬性方法
.clear()      清空字典
.copy()       複製字典
.update({ })  在字典中添加多個項
.items()      返回字典的各個項   
.keys()       返回字典的鍵  
.values()     返回字典的值
.get(k)       如果鍵k在,返回鍵k的值,不存在則返回None
.get(k,x)     如果鍵k在,返回鍵k的值,不存在則返回x
.pop(k)       返回並移除鍵k所對應的元素,不存在則拋出異常
.pop(k,x)     返回並移除鍵k所對應的元素,不存在則返回x
.popitem(k,x) 刪除一個鍵值對,如果沒有返回爲空
.setdefault(self, key, default=None, /) 插入一個鍵,默認值爲空

總結:
    key唯一,故可以是數字,字符串,元組

增刪該查

dic = {‘key1’: ‘value1’, ‘key2’: ‘value2’, ‘key3’: ‘value3’}

  • 添加
    • dic['key4'] = value4
  • 修改
    • dic['key3'] = value5
  • 刪除:
    • del dic['key1']
    • dic.pop(‘key’)
  • 查找
    • dic.get(‘key1’, x) :查是否有key1,沒有就返回x

遍歷字典

def chong():
    """ 寵物信息打印 """
    dog = {'type': 'dog', 'name': 'xiaohua'}
    cat = {'type': 'cat', 'name': 'tangyuan'}
    mouse = {'type': 'mouse', 'name': 'hong'}
    pets = [dog, cat, mouse]
    for i in pets:
        print('寵物:')
        for key, name in i.items():
            print('\t',key,':',name)
 1 `dic.items()`
"""
In [32]: dic = {'a':1, 'b':2}

In [33]: dic.items()
Out[33]: dict_items([('a', 1), ('b', 2)])

In [36]: print(type(a1))
<class 'dict_items'>

In [38]: print (a1)
dict_items([('a', 1), ('b', 2)])
"""
for key, value in dic.items():
    print('key£:',key, 'value£:',value)
    # 打印結果:
    # key£: a value£: 1
    # key£: b value£: 2

# 2 dic.keys()
"""
In [41]: dic.keys()
Out[41]: dict_keys(['a', 'b'])

In [42]: dic.values()
Out[42]: dict_values([1, 2])

In [44]: type(dic.keys())
Out[44]: dict_keys

In [45]: type(dic.values())
Out[45]: dict_values
"""

字典嵌套

def city_dic():
    """城市信息展示"""
    cities = {
        'beijing': {
            'country':'CHINA', 
            'population':'3000w', 
            'fact':"2008年奧運會"
            },
        'wuhan': {
            'country': 'CHINA', 
            'population':'2000w', 
            'fact':'2019年軍運會'
            },
        'hangzhou':{
            'country': 'CHINA', 
            'population':'1000w', 
            'fact':'2016年AEPI峯會'
            },
        }
    for key1,value1 in cities.items():
        print('城市名稱:'+key1)
        for key2,value2 in value1.items():
            print('\t',key2,':',value2)
"""打印結果:
城市名稱:beijing
     country : CHINA
     population : 3000w
     fact : 2008年奧運會
城市名稱:wuhan
     country : CHINA
     population : 2000w
     fact : 2019年軍運會
城市名稱:hangzhou
     country : CHINA
     population : 1000w
     fact : 2016年AEPI峯會
"""

5. if語句

if判斷,依據條件判斷最終返回的值是False或True

條件測試

# 1. 相等 ==
# 2. 不等 !=
# 3. 比較數字 age >= 18
# 4. 多條件檢查
#   4.1 and
#   要檢查是否兩個條件都爲True,可使用關鍵字and將兩個條件測試合而爲一;
#   如果每個測試都通過了,整個表達式就爲True;如果至少有一個測試沒有通過,
#   整個表達式就爲False。
#   4.2 or
#    關鍵字or也能夠讓你檢查多個條件,但只要至少有一個條件滿足,就能通過整個測試。
#    僅當兩個測試都沒有通過時,使用or的表達式才爲False。
# 5. 包含: in
# 6. 不包含: not in
# 7. 變量設置爲bool值判斷

if語句

if 判斷語句 :
    執行語句1
elif 判斷語句2:
    執行語句2
elif 判斷語句3:
    執行語句3
#...
else:
    執行語句4
    
佔位符 pass

if處理數據

# coding=utf8
import random
import json, re 

def if_test1():
    """5-3 if-elif-else練習"""
    alien_color_list = ['red','yellow','green']
    # a = random.random() # 隨機獲得值
    # a = random.uniform(0,2) # 0,2之間的隨機數
    a = random.sample(alien_color_list,1) # 列表中隨機獲得一個列表值    
    alien_color = a[0] # 獲得列表中的元素
    # print(alien_color)
    if alien_color == 'green':
        print('Player acquire 5 point')
    elif alien_color == 'red':
        print('Player acquire 10 point')
    elif alien_color == 'yellow':
        print('Player acquire 15 point')
    else:
        print('Not find the alient')

def if_in():
    """5-7 if in-mot in 練習"""
    favorite_fruits_list = ['banana','apple','tomato','orange']
    favorite_frutis = random.sample(favorite_fruits_list,1)[0]
    if favorite_frutis in favorite_fruits_list:
        print('You relly like :', favorite_frutis)
    else:
        print('請挑選你喜歡的水果!')

def user_name_judge():
    """5-10 用戶註冊的用戶名查重判斷"""
    user_name = ['Ton','Tom','Arm','Json','Achjiang','Jing','Qing','pop']
    new_user = ['ton','Tom','Hit','Pop','Yong','jiin']

    # 方法1:
    user_name_1 = str(user_name).lower()
    print(user_name_1, type(user_name_1),'\n')
    """打印結果:
    ['ton', 'tom', 'arm', 'json', 'achjiang', 'jing', 'qing', 'pop'] <class 'str'> 
    """
    user_name_1 = re.findall(r'\w+', user_name_1) # 返回的是一個列表
    # a = a.split(',') # 不合適再這裏
    print(user_name_1, type(user_name_1),'\n')
    """打印結果:
    ['ton', 'tom', 'arm', 'json', 'achjiang', 'jing', 'qing', 'pop'] <class 'list'>
    """

    # 方法2:
    # user_name_1 = []
    # for j in user_name:
    #   j = j.lower()
    #   user_name_1.append(j)

    # 條件判斷
    for i in new_user:
        i = i.lower()
        if i not in user_name_1:
            print( i,':','is not be used !')
        else:
            print(i, ':', 'is be used !')

def json_test():
    """json 方法測試"""
    user = {'username': 'cch', 'age': 18}
    print(user)
    # {'username': 'cch', 'age': 18}
    a = json.dumps(user)
    print(a)
    # {"username": "cch", "age": 18}

if __name__ == '__main__':
    # if_test1()
    # if_in()
    user_name_judge()
    # json_test()

6. while循環

1.while循環

while 判斷語句A:
    執行語句B
elseprint('程序正常結束,執行else')
注意:循環要有終止條件

2.breakcontinue

while True:
    break   #終止循環
    continue  #跳過本次循環
    
#break 會終止循環,循環不再執行
#continue是跳過本次循環,循環繼續

3. while-else

while True:
    break
else:
    print('OK')

#for   
for item in iterable:
    break
else:
    print('OK')
  
""" 
只有正常結束的循環,非break結束的循環纔會執行else部分
"""

7. 函數

函數定義

'''
function  功能,函數
問題:一個由數字組成的列表,每次取其中兩個判斷大小,最後找出這個列表中最大的數 

函數就是對代碼進行一個封裝。把實現,某一功能的相同代碼,進行封裝到一起。下次需要使用時,就不需要再進行代碼編寫,直接調用即可。
好處:
增加代碼的複用性,增加代碼可讀性,減少代碼的編寫量,降低維護成本 
函數可以看成,解決某類問題的 '工具'
定義方法:
'''
    def function_name(params):
        block
        return expression(表達式)/value
'''   
def 關鍵字表示定義一個函數
function_name 函數名,和變量名的命名要求相同,以字母和_開頭,可以包含字母、數字和_
params 表示參數,可以是零個,一個 或者多個參數,函數參數不用指定參數類型
'''

函數參數

  • 形參
  • 實參
  • 位置參數 def fun(name, age): a = fun('jiang', 16)
  • 關鍵字參數 def fun(name, age): a = fun(name='jiang'),16
  • 默認參數 def fun(name='jiang', age=18)
  • 不定長參數: 可在定義時定義,也可在傳入時傳入
    • 定義方法: def function_name(*args,**kwargs):
    • *args 將傳入參數包裝成元組
    • **kwargs將傳入參數包裝成字典

return

return有兩個作用:1.用來返回函數的運行結果,或者調用另外一個函數。比如max()函數
                 2.函數結束的標誌。只要運行了return,就強制結束了函數。return後面的程序都不會被執行。
                                 
如果函數中沒有寫return,其實函數運行結束時,默認執行了 return None
return語句的位置是可選的,不是固定出現再函數的最後,可以自定義在函數中的任何地方。

匿名函數

沒有函數名的函數
g = lambda x:x+1
lambda簡化了函數定義的書寫形式。是代碼更爲簡潔,但是使用函數的定義方式更爲直觀,易理解 

lambda的應用場景:
1.有些函數如果只是臨時一用,而且它的業務邏輯也很簡單時,就沒必要用def 來定義,這個時候就可以用lambda2.函數都支持函數作爲參數,lambda 函數就可以應用

常見的內置函數

常見的內置函數:
    查看內置函數:
        print(dir(__builtins__))
    常見函數
    len 求長度
    min 求最小值
    max 求最大值
    sorted  排序
    reversed 反向
    sum  求和

進制轉換函數:
    bin()  轉換爲二進制
    oct()  轉換爲八進制
    hex() 轉換爲十六進制
    ord() 將字符轉換成對應的ASCII碼值
    chr() 將ASCII碼值轉換成對應的字符
補充:
1.enumerate()   #返回一個可以枚舉的對象
2.filter() #過濾器
3.map() #加工。對於參數iterable中的每個元素都應用fuction函數,並返回一個map對象
4.zip() #將對象逐一配對

函數內變量的作用域

變量的作用域與其定義的方式有關:
    局部變量: 變量在函數內部定義,則變量的作用域在函數內部
    全局變量:變量在函數外部定義的,則變量的作用域是全局

    global:用來在函數或其他局部作用域中,聲明全局變量。   (作用於全局)
    nonlocal:用來在函數或其他作用域中,聲明外層(非全局)變量。(作用於局部) 
    
使用global情況:
    全局變量可以在函數內部訪問,但是不能改變
    如果在函數內部想修改全局變量,可以用 global 來修飾變量
    
    局部變量只能在局部進行訪問和修改。
    如果在函數外部,想訪問局部變量,也可以用 global,將局部變量聲明爲全局變量
   
使用nonlocal的情況:
    當裏層局部,需要修改外層局部時,需要使用nonlocal(如嵌套函數)
  
  
總結:
    global :函數中,需要修改全局變量時,用global
    nonlocal:當裏層局部,需要修改外層局部時,需要使用nonlocal。
            (局部調用局部,使用nonlocal

內嵌函數和閉包

內嵌函數: 在函數內部定義函數,就是函數裏面嵌套函數

閉包:一個閉包就是你調用了一個函數A,這個函數A返回了一個函數B給你。這個返回的函數B就叫做閉包。(但是B函數,一定要是嵌套在函數A裏面) 。你在調用函數A的時候傳遞的參數就是自由變量。

總結:一個函數裏面嵌套一個函數,調用外面這個函數,就返回裏面嵌套的函數。

8. 類

創建類和實例化

創建類

# 1. python 2.7 創建類
class ClassName(object):
    --snip--
    pass
class Dog(object):
    --snip--
    pass

# 2. python3創建類
class Dog():
    """一次模擬小狗的簡單嘗試"""
    def __init__(self, name, age):
        """初始化屬性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!")

類實例化

  1. 調用屬性
  2. 調用方法
  3. 修改屬性

繼承

如果你要編寫的類是另一個現成類的特殊版本,可使用繼承。一個類繼承另一個類時,它將自動獲得另一個類的所有屬性和方法;原有的類稱爲父類,而新類稱爲子類。子類繼承了其父類的所有屬性和方法,同時還可以定義自己的屬性和方法。

# python2.7 
class Car(object):
    def __init__(self, make, model, year):
        --snip--


class ElectricCar(Car):
    def __init__(self, make, model, year):
        super(ElectricCar, self).__init__(make, model, year)
        --snip--

# python3
class Car():
    """一次模擬汽車的簡單嘗試"""

    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 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):
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        self.odometer_reading += 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()

super()是一個特殊函數,幫助Python將父類和子類關聯起來。這行代碼讓Python調用
ElectricCar的父類的方法__init__(),讓ElectricCar實例包含父類的所有屬性。父類也稱爲超
類(superclass),名稱super因此而得名。

函數super()需要兩個實參:子類名和對象self。爲幫助Python將父類和子類關聯起來,這些
實參必不可少。另外,在Python 2.7中使用繼承時,務必在定義父類時在括號內指定object。

多繼承super()

繼承有三種方法:

  • 類名繼承 # Parent.__init__(self, name)
  • super()繼承 # super().__init__(name, age, gender)
  • super(具體類名, self) # super(Grandson, self).__init__(name, age, gender)

當python3中存在多繼承時,會存在使用super()調用時,不會直接調用父類的情況。主要是因爲python3中在使用super()調用類的時候默認有一個c3算法,這個算法是用來保證每個類只被調用一次的算法。這個算法的體現是當你使用最底層類名.__mro__打印時,會有一個(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>) 類似的元組,super()調用的類按照元組的順序進行依次調用類。

當使用super(Son2, self).__init__(name, age, gender)方法調用時,會直接從Son1開始調用類,然後按照最底層類名.__mro__中元組的順序依次對後執行。如該部分就會跳過Son1直接調用Son2後的Parent

print("******多繼承使用super().__init__ 發生的狀態******")
class Parent(object):
    def __init__(self, name, *args, **kwargs):  # 爲避免多繼承報錯,使用不定長參數,接受參數
        print('parent的init開始被調用')
        self.name = name
        print('parent的init結束被調用')

class Son1(Parent):
    def __init__(self, name, age, *args, **kwargs):  # 爲避免多繼承報錯,使用不定長參數,接受參數
        print('Son1的init開始被調用')
        self.age = age
        super().__init__(name, *args, **kwargs)  # 爲避免多繼承報錯,使用不定長參數,接受參數
        print('Son1的init結束被調用')

class Son2(Parent):
    def __init__(self, name, gender, *args, **kwargs):  # 爲避免多繼承報錯,使用不定長參數,接受參數
        print('Son2的init開始被調用')
        self.gender = gender
        super().__init__(name, *args, **kwargs)  # 爲避免多繼承報錯,使用不定長參數,接受參數
        print('Son2的init結束被調用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被調用')
        # 多繼承時,相對於使用類名.__init__方法,要把每個父類全部寫一遍
        # 而super只用一句話,執行了全部父類的方法,這也是爲何多繼承需要全部傳參的一個原因
        # super(Grandson, self).__init__(name, age, gender)
        super().__init__(name, age, gender)
        print('Grandson的init結束被調用')

print(Grandson.__mro__)

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年齡:', gs.age)
print('性別:', gs.gender)
print("******多繼承使用super().__init__ 發生的狀態******\n\n")

運行結果:

******多繼承使用super().__init__ 發生的狀態******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init開始被調用
Son1的init開始被調用
Son2的init開始被調用
parent的init開始被調用
parent的init結束被調用
Son2的init結束被調用
Son1的init結束被調用
Grandson的init結束被調用
姓名: grandson
年齡: 12
性別: 男
******多繼承使用super().__init__ 發生的狀態******
總結:
  1. super().__init__相對於類名.init,在單繼承上用法基本無差
  2. 但在多繼承上有區別,super方法能保證每個父類的方法只會執行一次,而使用類名的方法會導致方法被執行多次,具體看前面的輸出結果
  3. 多繼承時,使用super方法,對父類的傳參數,應該是由於python中super的算法導致的原因,必須把參數全部傳遞,否則會報錯
  4. 單繼承時,使用super方法,則不能全部傳遞,只能傳父類方法所需的參數,否則會報錯
  5. 多繼承時,相對於使用類名.__init__方法,要把每個父類全部寫一遍, 而使用super方法,只需寫一句話便執行了全部父類的方法,這也是爲何多繼承需要全部傳參的一個原因
面試題
class Parent(object):
    x = 1

class Child1(Parent):
    pass

class Child2(Parent):
    pass

print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
print(Child2.__mro__)

# 打印結果
"""
1 1 1
1 2 1
3 2 3
(<class '__main__.Child2'>, <class '__main__.Parent'>, <class 'object'>)
"""

說明:

使你困惑或是驚奇的是關於最後一行的輸出是 3 2 3 而不是 3 2 1。爲什麼改變了 Parent.x 的值還會改變 Child2.x 的值,但是同時 Child1.x 值卻沒有改變?

這個答案的關鍵是,在 Python 中,類變量在內部是作爲字典處理的。如果一個變量的名字沒有在當前類的字典中發現,將搜索祖先類(比如父類)直到被引用的變量名被找到(如果這個被引用的變量名既沒有在自己所在的類又沒有在祖先類中找到,會引發一個 AttributeError 異常 )。

因此,在父類中設置 x = 1 會使得類變量 x 在引用該類和其任何子類中的值爲 1。這就是因爲第一個 print 語句的輸出是 1 1 1。

隨後,如果任何它的子類重寫了該值(例如,我們執行語句 Child1.x = 2),然後,該值僅僅在子類中被改變。這就是爲什麼第二個 print 語句的輸出是 1 2 1。

最後,如果該值在父類中被改變(例如,我們執行語句 Parent.x = 3),這個改變會影響到任何未重寫該值的子類當中的值(在這個示例中被影響的子類是 Child2)。這就是爲什麼第三個 print 輸出是 3 2 3。

定義子類屬性方法

重寫父類方法

示例屬性化

classmethodstaticmethodproperty方法說明

classmethodstaticmethod方法

方法包括:實例方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不同。

  • 實例方法:由對象調用;至少一個self參數;執行實例方法時,自動將調用該方法的對象賦值給self;

  • 類方法:由類調用; 至少一個cls參數;執行類方法時,自動將調用該方法的類賦值給cls;

  • 靜態方法:由類調用;無默認參數;

    • classmethod:是一個類方法
    • staticmethod
      靜態方法是在定義一個供當前類調用,但是又不想傳遞參數(self-實例參數/cls-類參數)的情況下產生的一種方法,這個方法只能被這個類調用,其它類不能調用。使用示例如下:
class Foo(object):
    # 類屬性
    country = '中國'
    def __init__(self, name):
        # 實例屬性
        self.name = name

    def ord_func(self):
        """ 定義實例方法,至少有一個self參數 """
        # print(self.name)
        print('實例方法')

    @classmethod
    def class_func(cls):
        """ 定義類方法,至少有一個cls參數 """
        print('類方法')

    @staticmethod
    def static_func():
        """ 定義靜態方法 ,無默認參數"""
        print('靜態方法')

# 1.屬性:
# 創建一個實例對象
obj = Foo('山東省')
# 直接訪問實例屬性
print(obj.name)
# 直接訪問類屬性
Foo.country

# 2.方法:
f = Foo("中國")
# 調用實例方法
f.ord_func()

# 調用類方法
Foo.class_func()

# 調用靜態方法
Foo.static_func()

實例屬性和類屬性對比:

  • 類屬性在內存中只保存一份
  • 實例屬性在每個對象中都要保存一份

方法對比:

  • 相同點:對於所有的方法而言,均屬於類,所以 在內存中也只保存一份
  • 不同點:方法調用者不同、調用方法時自動傳入的參數不同。
property方法

Python的property屬性的功能是:property屬性內部進行一系列的邏輯計算,最終將計算結果返回。

property方法有兩種用法,一種是使用裝飾器的方式對函數進行裝飾,一種是使用類屬性的方法。

  • 裝飾器 即:在方法上應用裝飾器
  • 類屬性 即:在類中定義值爲property對象的類屬性

裝飾器
Python中的類有經典類和新式類,新式類的屬性比經典類的屬性豐富。( 如果類繼object,那麼該類是新式類 )

經典類,具有一種@property裝飾器

# ############### 定義 ###############    
class Goods:
    @property
    def price(self):
        return "laowang"
# ############### 調用 ###############
obj = Goods()
result = obj.price  # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值
print(result)

新式類,具有三種@property裝飾器

#coding=utf-8
# ############### 定義 ###############
class Goods:
    """python3中默認繼承object類
        以python2、3執行此程序的結果不同,因爲只有在python3中才有@xxx.setter  @xxx.deleter
    """
    @property
    def price(self):
        print('@property')

    @price.setter
    def price(self, value):
        print('@price.setter')

    @price.deleter
    def price(self):
        print('@price.deleter')

# ############### 調用 ###############
obj = Goods()
obj.price          # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值
obj.price = 123    # 自動執行 @price.setter 修飾的 price 方法,並將  123 賦值給方法的參數
del obj.price      # 自動執行 @price.deleter 修飾的 price 方法

注意

  • 經典類中的屬性只有一種訪問方式,其對應被 @property 修飾的方法
  • 新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法
    由於新式類中具有三種訪問方式,我們可以根據它們幾個屬性的訪問特點,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除

類屬性方式,創建值爲property對象的類屬性
當使用類屬性的方式創建property屬性時,經典類和新式類無區別

class Foo:
    def get_bar(self):
        return 'laowang'

    BAR = property(get_bar)

obj = Foo()
reuslt = obj.BAR  # 自動調用get_bar方法,並獲取方法的返回值
print(reuslt)

property方法中有個四個參數

第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法
第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法
第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法
第四個參數是字符串,調用 對象.屬性.doc ,此參數是該屬性的描述信息

#coding=utf-8
class Foo(object):
    def get_bar(self):
        print("getter...")
        return 'laowang'

    def set_bar(self, value): 
        """必須兩個參數"""
        print("setter...")
        return 'set value' + value

    def del_bar(self):
        print("deleter...")
        return 'laowang'

    BAR = property(get_bar, set_bar, del_bar, "description...")

obj = Foo()

obj.BAR  # 自動調用第一個參數中定義的方法:get_bar
obj.BAR = "alex"  # 自動調用第二個參數中定義的方法:set_bar方法,並將“alex”當作參數傳入
desc = Foo.BAR.__doc__  # 自動獲取第四個參數中設置的值:description...
print(desc)
del obj.BAR  # 自動調用第三個參數中定義的方法:del_bar方法

由於類屬性方式創建property屬性具有3種訪問方式,我們可以根據它們幾個屬性的訪問特點,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除

綜上所述:

定義property屬性共有兩種方式,分別是【裝飾器】和【類屬性】,而【裝飾器】方式針對經典類和新式類又有所不同。
通過使用property屬性,能夠簡化調用者在獲取數據的流程。其中python2中適合裝飾器的經典類和類屬性,不適合裝飾器的新式類;python3都適合。

9. 文件異常處理

文件

#1.打開文件 open 函數
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
# file 是要打開的文件
# encoding 默認編碼方式爲空,一般window系統的需要設置'UTF-8'
# mode 是打開文件的方式,默認爲r--讀

#2.文件的打開模式
r 只讀模式,文件不存在時會報錯。
w 寫入模式,文件存在會清空之前的內容,文件不存在則會新建文件。
x 寫入模式,文件存在會報錯,文件不存在則會新建文件。
a 追加寫入模式,不清空之前的文件,直接將寫入的內容添加到後面。
b 以二進制模式讀寫文件,wb,rb,ab。
+ 可讀寫模式,r+,w+,x+,a+,這幾種模式還遵循了r,w,x,a的基本原則。

#3.文件的讀取
f.read(size)  #讀取文件的內容,將文件的內容以字符串形式返回。
'''size是可選的數值,指定字符串長度,如果沒有指定size或者指定爲負數,就會讀取並返回整個文件。當文件大小爲當前機器內存兩倍時就會產生問題,反之就儘可能大的size讀取和返回數據,如果到了文件末尾,會返回空字符串。
'''

f.readline() #從文件中讀取單獨一行。
'''字符串結尾會自動加上一個換行符\n,只有當文件最後沒有以換行符結尾時,這一操作纔會被忽略,這樣返回值就不會有混淆。如果返回空字符串,表示到達率文件末尾,如果是空行,就會描述爲\n,一個只有換行符的字符串。
'''

f.readlines() #一次讀取所有,返回一個列表,列表的元素爲文件行的內容。
'''可以通過列表索引的方式將文件的每一行的內容輸出。
可以通過for循環迭代輸出每一行的信息。
'''
#4.文件的寫入
f.write()       #將要寫入的內容以字符串的形式通過write方法寫入文件中。
f.writelines()  #括號裏必須是由字符串元素組成的序列。

#5.保存和關閉
f.flush()
#在讀寫模式下,當寫完的數據想要讀取出來時,要先緩存區的內容保存到文件當中。

f.close() 
#關閉文件。對一個已經關閉的文件進行操作會報錯。

#6.光標位置
f.tell()            #返回光標在文件中的位置。
f.seek(offset,from) #常用 f.seek(0) 返回起始位置
#在文件中移動文件指針,從from(0代表起始位置,1代表當前位置,2代表文件末尾)偏移offset個字節。
# 常用 f.seek(0,0)  返回起始位置。 其他了解一下

#7.查看文件信息
closed      #查看文件是否已經關閉,返回布爾值。
mode        #返回文件打開模式。
name        #返回文件名。

#8.with 形式打開文件,裏面的語句執行完後會自動關閉文件
with open('文件名') as f:
    f.read() 

讀文件

# coding=utf-8

# 1 Windows讀取文件
# Windows環境路徑,`\`非轉義字符,所以前面加r不識別,避免報語法錯誤
file_path = r"C:\Users\luo\Desktop\123.txt"

with open(file_path, encoding='UTF-8') as f:
    content = f.read()
    # print(type(f), f)
    # <class '_io.TextIOWrapper'> <_io.TextIOWrapper name='C:\\Users\\luo\\Desktop\\123.txt' mode='r' encoding='UTF-8'>
    print('----------', '\n', content)

with open() as f:好處:
關鍵字with在不再需要訪問文件後將其關閉。在這個程序中,注意到我們調用了open(),但
沒有調用close();你也可以調用open()和close()來打開和關閉文件,但這樣做時,如果程序存
在bug,導致close()語句未執行,文件將不會關閉。這看似微不足道,但未妥善地關閉文件可能
會導致數據丟失或受損。如果在程序中過早地調用close(),你會發現需要使用文件時它已關閉
(無法訪問),這會導致更多的錯誤。並非在任何情況下都能輕鬆確定關閉文件的恰當時機,但通
過使用前面所示的結構,可讓Python去確定:你只管打開文件,並在需要時使用它, Python自會
在合適的時候自動將其關閉。

文件路徑
  • 在Linux和OS X中,你可以這樣編寫代碼:
file_path = '/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object:
  • 在Windows系統中,在文件路徑中使用反斜槓(\)而不是斜槓(/):
file_path = r'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:

注意 Windows系統有時能夠正確地解讀文件路徑中的斜槓。如果你使用的是Windows系統,且
結果不符合預期,請確保在文件路徑中使用的是反斜槓。

  • 文件讀取函數
    • f.read() : 讀取整個文件 <class ‘str’>
    • f.readline() : 讀取第一行文件,返回list
    • f.readlines() : 讀取所有行文件, 回list
# 2 Windows環境下讀取列表
file_list_path = r"C:\Users\luo\Desktop\文檔\test.txt"
p_str = ''
with open(file_list_path, encoding='UTF-8') as f:
    content = f.read() # 讀取文檔 <class 'str'>
    # 打印內容
    """
     [1,2,3,4,5,6]
    [11,12,13,14,15,16]
    [2,21,22,23,24,25]
    """
    # content = f.readline() # 只讀第一行,返回列表 
    # [1,2,3,4,5,6]
    # content = f.readlines() # 讀所有行,返回列表
    # ['[1,2,3,4,5,6]\n', '[11,12,13,14,15,16]\n', '[2,21,22,23,24,25]']
    # for line in content:
    #   print(line.rstrip(), type(line)) # rstrip()方法去除字符串首尾的空格, <class 'str'>
    #   p_str += line
    """
    [1,2,3,4,5,6]
    [11,12,13,14,15,16]
    [2,21,22,23,24,25]
    """
    print('----------', '\n', type(content), content) # <class 'list'>
    # print('----------', '\n', type(p_str), p_str) # <class 'str'> 

寫文件

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

  • 寫文件主要有以下幾種方式:
    • 讀取模式(‘r’)、
    • 寫入模式(‘w’)、
    • 附加模式(‘a’)
    • 夠讀取和寫入文件的模式(‘r+’)
  • 寫入空文件:
# 寫空文件
filename = 'programming.txt'

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

注意: 如果你要寫入的文件不存在,函數open()將自動創建它。然而,以寫入(‘w’)模式打開文
件時千萬要小心,因爲如果指定的文件已經存在, Python將在返回文件對象前清空該文件。

  • 寫多行文件
filename = 'programming.txt'

with open(filename, 'w') as f:
    f.write("I love programming.\n")
    f.write("I love creating new games.\n")
  • 寫附加文件
    • 如果你要給文件添加內容,而不是覆蓋原有的內容,可以附加模式打開文件。
    • 你以附加模式打開文件時,Python不會在返回文件對象前清空文件,而你寫入到文件的行都將添加到文件末尾。
    • 如果指定的文件不存在, Python將爲你創建一個空文件。
filename = 'programming.txt'

with open(filename, 'a') as f:
    f.write("I also love finding meaning in large datasets.\n")
    f.write("I love creating apps that can run in a browser.\n")

存儲數據

模塊json讓你能夠將簡單的Python數據結構轉儲到文件中,並在程序再次運行時加載該文件
中的數據。你還可以使用json在Python程序之間分享數據。更重要的是,JSON數據格式並非Python
專用的,這讓你能夠將以JSON格式存儲的數據與使用其他編程語言的人分享。這是一種輕便格
式,很有用,也易於學習

json.dump()和 json.load()
  • json.dump()來存儲這組數字
import json

username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
    json.dump(username, f_obj)
    print("We'll remember you when you come back, " + username + "!")
  • json.load()加載存儲信息
import json
def greet_user():
    """"""
    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 remember you when you come back, " + username + "!")
    else:
        print("Welcome back, " + username + "!")

greet_user()
保存和讀取用戶數據
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 remember you when you come back, " + username + "!")
    else:
        print("Welcome back, " + username + "!")
重構

代碼能夠正確地運行,但可做進一步的改進——將代碼劃分爲一系列完成具體工作的函數。這樣的過程被稱爲重構。重構讓代碼更清晰、更易於理解、更容易擴展。

import json
def get_stored_username():
    """Èç¹û´æ´¢ÁËÓû§Ãû£¬¾Í»ñÈ¡Ëü"""
    filename = 'username.json'
    try:
        with open(filename) as f_obj:
        username = json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username

def greet_user():
    """ÎʺòÓû§£¬²¢Ö¸³öÆäÃû×Ö"""
    username = get_stored_username()
    if username:
        print("Welcome back, " + username + "!")
    else:
        username = input("What is your name? ")
        filename = 'username.json'
    wi

異常處理

try:
    suite1          #測試語句塊
except exception1:
    suite2          #如果測試語句suite1中發生exception1異常時執行
except (exception2,exception3):
    suite3          #如果測試語句suite1中發生元組中任意異常時執行
except exception4 as reason:    #as把異常的原因賦值給reason
    suite4          #如果測試語句suite1發生exception4的異常時執行
except:
    suite5          #如果測試語句suite1發生異常在所列出的異常之外時執行
else:
    suite5          #如果測試語句塊suite1中沒有發生異常時執行
finally:
    suit6           #不管測試語句suite1中又沒有發生異常都會執行
    
'''
注意:中間的except,else,finally都是可選的,但至少有一個,不然try就沒有意義了,根據實際中的需求來選擇。
所有錯誤類型都繼承自BaseException
https://docs.python.org/3/library/exceptions.html#exception-hierarchy
'''

#注意:如果拋出父類異常,在子類不會再獲取,如下:
try:
    fun()
except Exception as e:
    raise Exception
except ImportError as e:
    raise ImportError
finally:
    pass
    
'''
在上面的例子中,下面的ImportError就不會被拋出,應爲ImportError繼承Exception,但是可以把Exception放在後面是可以的
e可以得到系統給出的報錯信息
'''

assert #斷言
'''
測試表示式,其返回值爲假,就會觸發異常
'''

assert 1==1     #沒有返回值
assert 1==2     #返回AssertionError

10. 測試代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章