1. 程式人生 > >學習筆記五 函式和常用模組

學習筆記五 函式和常用模組

一.列表生成式:

列表生成式即List Comprehensions,是Python內建的非常簡單卻強大的可以用來建立list的生成式。

運用列表生成式,可以快速生成list,可以通過一個list推匯出另一個list,而程式碼卻十分簡潔。

[表示式 for迴圈]

s =[1,2,3,4,5,6,7,8]

res1 = [ i+1 for i in s]
res2 = [str(i) for i in s]
print(res1)
print(res2)

執行結果:

[2, 3, 4, 5, 6, 7, 8, 9]
['1', '2', '3', '4', '5', '
6', '7', '8']

for迴圈後面還可以加上if判斷,這樣我們就可以篩選出僅偶數的平方:

res=[x * x for x in range(1, 11) if x % 2 == 0]
print(res)

執行結果:

[4, 16, 36, 64, 100]

還可以使用兩層迴圈,可以生成全排列:

res=[m + n for m in 'ABC' for n in 'XYZ']
print(res)

執行結果:

['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

for迴圈其實可以同時使用兩個甚至多個變數,比如dict

iteritems()可以同時迭代key和value:

d = {'x': 'A', 'y': 'B', 'z': 'C' }
res=[k + '=' + v for k, v in d.items()]
print(res)

執行結果:

['x=A', 'y=B', 'z=C']

 

二.函式:

1.函式返回return的作用有兩點:

    1、把函式處理的結果返回

    2、結束函式,函式裡面遇到return,函式立即結束

2.全域性變數:

  python裡分兩種資料型別:可變型別和不可變型別

  如果改變了變數的值,相當於是新建了一個物件,而對於相同的值的物件,在記憶體中則只有一個物件,內部會有一個引用計數來記錄有多少個變數引用這個物件變資料型別,允許變數的值發生變化,即如果對變數進行append、+=等這種操作後,只是改變了變數的值,而不會新建一個物件,變數引用的物件的地址也不會變化,不過對於相同的值的不同物件,在記憶體中則會存在不同的物件,即每個物件都有自己的地址,相當於記憶體中對於同值的物件儲存了多份,這裡不存在引用計數,是實實在在的物件。

  可變型別(值可以修改):

    列表list

    字典dict

  不可變型別(值不允許修改):

    數值型別int,long,bool,float

    字串str

    元組tuple 

  可變型別表示修改值後id不會發生變化,都是一個標籤,一改都改;不可變型別則修改值後id也變了,換了一個引用,是不同的標籤不同的變數函式裡如果對可變型別修改,則在函式外面這個變數值也會變化,不可變型別則在函式外面不會發生變化(類似內部變數不影響外部變數)  

  全域性變數
  #list、字典、集合,不需要宣告global
  #字串、數值型別、元組 需要宣告global

def test():
    global a
    a = 5
    print(id(a))
    a = 6
    print(id(a))

def test1():
    c= a + 5
    return c
test()
res = test1()
print(res)

執行結果:

1523215552
1523215584
11

因為是不可變型別,所以定義了全域性變數後,當a值重新賦值6的時候,id也發生了變化,不是對同一個id的變數進行修改

a=5
def test():
    global a
    print(id(a))
    a=a+5
    print(id(a))
    return a


res = test()
print(res)
print(a,id(a))

執行結果:

1523215552
1523215712
10
10 1523215712

a是不可變型別的全域性變數,當test宣告引用全域性時,之後a=a+5,右邊的a是id 1523215552,左邊由於不可變原因,所以新生成了一個全域性的引用id 1523215712,值為11,此時有兩個全域性變數a(id不同),值也不同,一個為5,一個為11。注意的是gloable不宣告的話,a會當成一個未定義的區域性變數報錯!

同理:

 

 1 def test():
 2     global a
 3     a = 5
 4     print(id(a))
 5     a = 6
 6     print(id(a))
 7 
 8 def test1():
 9     global a
10     print(id(a))
11     a= a + 5
12     print(id(a))
13     return a
14 
15 test()
16 res = test1()
17 print(res)
18 print(a,id(a))

 

1523215552
1523215584
1523215584
1523215744
11
11 1523215744

3.淺拷貝與深拷貝:

  淺拷貝:兩個變數指向的是同一塊記憶體地址(id)

  深拷貝:是會開闢一個新的記憶體,存放資料,就是兩塊不同記憶體(id)。

比較兩段程式碼及結果:

 

1 import copy
     #0 1 2
2 num1 = [1,1,2,3,4,5,6,7,7,8] 3 num2 = num1 #淺拷貝 4 print(id(num1)) 5 print(id(num2)) 6 for i in num2: 7 if i%2!=0: 8 num1.remove(i) 9 print(num1)

 

2412905492616
2412905492616
[1, 2, 4, 6, 7, 8]

----------------------------------------------

1 import copy
     #0 1 2
2 num1 = [1,1,2,3,4,5,6,7,7,8] 3 num2 = copy.deepcopy(num1)#深拷貝 num2=num1[:]也屬於深拷貝 4 print(id(num1)) 5 print(id(num2)) 6 for i in num2: 7 if i%2!=0: 8 num1.remove(i) 9 print(num1)
1872643092616
1872643092744
[2, 4, 6, 8]

迴圈刪除一個列表會有一個錯位問題:因為在迴圈num1,並刪除num1的元素時,列表的位置發生了移位,當刪除“1”後,第二個元素“1”補位,這樣第二個“1”就躲過了被刪除的命運被留了下來,列表是通過下標迴圈,讀過的下標就不會再讀,輪到“2”了,“2”被刪除之後,“3”來補位,以此類推!!

 

4.函式可變引數

當函式定義的時候有多個引數,則在函式呼叫的時候要注意傳入引數的順序

 

1 def mysql(host,user,password,port,charset,sql,db):
2     print('連線mysql')

 

例如上述程式碼的引數有7個,則以下傳入的順序都是正確的

1 mysql('ip','user','sdfsdf',3306,'sdfsdf','select','db')
2 mysql(user='root',password='123456',host='192.168.1.3',port=3306,sql='sdfsdf',db='sdfsdf',charset='sdfsdf')
3 mysql('192.168.1.1','root',port=3306,password='sdfsdf')

但是下述方式不正確,因為在函式定義的時候,引數的順序是固定好的,如果傳值得時候嚴格按照順序傳入而不帶形參,python是可以識別的,如果打亂順序指定形參傳值,之後的形參就不能省略了

mysql(password='123456','root',...,) 

 

5.可變引數:*args  **args

如果一個函式定義時發現需要傳入的引數的個數是不確定的,則應該使用可變引數*arg,在函式調動的時候,python會將入參打包成元組的形式傳給被調函式

 

def mysql2(ip,*info):
    print(info)

 

*info前可以帶指定的引數,但是ip不能定義在*info後,因為如果是*info ip則python不知道傳入的引數哪些是打包在*info內

 

 

1 def send_mail(*args):
2     print(args)
3 
4 send_mail('[email protected]')
5 send_mail('[email protected]','[email protected]','[email protected]')

 

('[email protected]',)
('[email protected]', '[email protected]', '[email protected]')

除了以上的元組形式,python還支援dict形式的引數傳入,需要用**args

 1 def mysql(**mysql_info):
 2     print(mysql_info)
 3 
 4 dic = {
 5     'host':'192.168.1.1',
 6     'user':'root',
 7     'password':123456,
 8     'port':3306,
 9     'charset':'utf-8',
10     'sql':'sql',
11     'db':'db'
12 }
13 mysql(**dic)
{'host': '192.168.1.1', 'user': 'root', 'password': 123456, 'port': 3306, 'charset': 'utf-8', 'sql': 'sql', 'db': 'db'}

 

三.常用模組

json模組:特定是用且必須用"""括起來的一個字典形式,本質上是一個字串

json是網路傳輸的一種格式,所以他是一個字串,在python裡使用裡面的元素時對字串操作非常不方便,所以需要用json模組將這個字串轉成容易操作的dict形式,在寫入文字對資料永續性儲存的時候再將他轉換成字串寫入文字。

 1 import json
 2 #解析json的
 3 
 4 # json_str = '''
 5 # {"name":"xiaohei","age":18,"sex":"男","age":18}
 6 # '''
 7 # res = json.loads(json_str) #把字串(json串)轉成字典
 8 # print(res)
 9 # print(type(json_str))
10 # print(type(res))
11 
12 dic = {
13     "xiaohei":{
14         "age":18,
15         "password":12345,
16         "sex":"",
17         "addr":"北京"
18     },
19     "馬春波":{
20         "age":18,
21         "password":12345,
22         "sex":"",
23         "addr":"北京"
24     },
25     "王東澤":{
26         "age":18,
27         "password":12345,
28         "sex":"",
29         "addr":"北京"
30     },
31 }
32 # res = json.dumps(dic,ensure_ascii=False,indent=4)#把字典變成字串
33 # print(res)
34 # f = open('user.json','w',encoding='utf-8')
35 # f.write(res)
36 
37 #load 自己讀
38 # f = open('user.json',encoding='utf-8')
39 # res = json.loads(f.read())
40 # print(res)
41 # res = json.load(f)
42 # print(res)
43 
44 #dump 自己寫的
45 fw = open('newuser.json','w')
46 json.dump(dic,fw,indent=4,ensure_ascii=False)#indent表示縮排,一般4即可,ensure_ascii表示轉碼,false可以避免中文輸入到檔案中變成ascii碼可讀性差

一共四個方法:

loads/dumps對字串的操作

load/dump對檔案的操作

 

time模組:

時間戳和格式化好的時間不能直接互轉,必須經過時間元組!

 1 import time
 2 
 3 #格式化好的時間 20181202
 4 #時間戳    2343242
 5 
 6 #時間元組
 7 
 8 # print(int(time.time()))#時間戳
 9 # res = time.strftime('%Y-%m-%d %H:%M:%S')#取當前格式化好的時間
10 # print(res)
11 
12 #時間戳轉換成時間元組,時間戳轉格式化好的時間
13 #time1 = time.gmtime(int(time.time()))#把時間戳轉成時間元組,以標準時間的時間轉換的
14 # time1 = time.localtime(int(time.time()))#把時間戳轉成時間元組,以標準時間的時間轉換的
15 # res = time.strftime('%Y-%m-%d %H:%M:%S',time1)
16 # print(res)
17 
18 
19 #格式化好的時間轉時間戳
20 
21 timep = time.strptime('2018-10-23 15:38:59','%Y-%m-%d %H:%M:%S')
22 print(timep)
23 res = time.mktime(timep)#把時間元組轉成時間戳
24 print(res)
25 #20181023 2323
26 def timestampToStr(timestamp=None,format='%Y-%m-%d %H:%M:%S'):
27     #時間戳轉格式化好的時間
28     if timestamp:
29         time1 = time.localtime(timestamp)
30         res = time.strftime(format, time1)
31     else:
32         res = time.strftime(format)
33     return res
34 #20180304153958
35 def strTotimestamp(str=None,format='%Y%m%d%H%M%S'):
36     #格式化的時間轉時間戳
37     if str:
38         timep = time.strptime(str, format)
39         res = time.mktime(timep)
40     else:
41         res = time.time()
42     return int(res)

 

os模組:

 1 import os
 2 res = os.listdir('/Users/nhy/Desktop') #列出某個目錄下的所有檔案
 3 # os.remove()#用於刪除指定路徑下的檔案
 4 # os.rename()#方法用於命名檔案或目錄,從 src 到 dst,如果dst是一個存在的目錄, 將丟擲OSError。
 5 # os.mkdir(r'test/niuhy/haha')#建立資料夾
 6 # os.makedirs(r'test1/lyl/aaa')#會建立父目錄
 7 # res = os.path.exists(r'/Users/nhy/Desktop/stu.txt')
 8 # os.path.isfile() #判斷是否為檔案
 9 # os.path.isdir()#判斷是否為檔案
10 # res = os.path.split(r'/Users/nhy/Desktop/stu.txt')#判斷括號裡的檔案是否存在的意思,括號內的可以是檔案路徑。
11 # res = os.path.dirname(r'/Users/nhy/Desktop/stu.txt')#取父目錄
12 # res = os.getcwd() #獲取當前的目錄
13 # os.chdir(r'/Users/nhy/Desktop/')#更改當前目錄
14 # res = os.getcwd()
15 # print(res)
16 # open('a.txt','w')
17 # print(os.environ)#看你電腦的環境變數
18 #
19 # res = os.path.join('test','hhh','abc','a.txt')#拼接路徑
20 # print(res)
21 # res= os.path.abspath('..')#根據相對路徑取絕對路徑
22 # print(res)
23 
24 # res = os.system('hhhsdf')#執行作業系統命令
25 # # print(res)
26 # res = os.popen('ifconfig').read()
27 # print('res',res)