Day03 - Python基礎(chǔ)3

Day03的課程要點(diǎn)記錄
詳細(xì)教程地址:金角大王 - Day3 Python基礎(chǔ)3 | 金角大王 - Day2 Python基礎(chǔ)2 | 銀角大王 - Python基礎(chǔ)(二)

一、集合的使用

集合是一個(gè)無(wú)序的,不重復(fù)的數(shù)據(jù)組合,它的主要作用如下:

  • 去重,把一個(gè)列表變成集合,自動(dòng)去重
  • 關(guān)系測(cè)試,測(cè)試兩組數(shù)據(jù)之前的交集、差集、并集等關(guān)系

1.1 常用操作

a = {11, 22, 33, 44}
s = set([3, 5, 9, 10]) #創(chuàng)建一個(gè)數(shù)值集合
t = set('Hello') #創(chuàng)建一個(gè)唯一字符的集合

a = t | s # t 和 s 的并集
b = t & s # t 和 s 的交集
c = t - s # 求差集(項(xiàng)在t中,但不在s中)
d = t ^ s # 對(duì)稱(chēng)差集(項(xiàng)在t或s中,但不會(huì)同時(shí)出現(xiàn)在二者中)

1.2 基本操作

  • s.intersection(t),s & t,交集,返回一個(gè)新的 set 包含 s 和 t 中的公共元素
>>> s.intersection(t)
set()
  • s.union(t),s | t,并集,放回一個(gè)新的 set 包含 s 和 t 中的每一個(gè)元素
>>> s.union(t)
{'e', 3, 'l', 5, 'H', 9, 10, 'o'}
  • s.difference(t),s - t,差集,返回一個(gè)新的 set 包含 s 中有但是 t 中沒(méi)有的元素
>>> s.difference(t)
{9, 10, 3, 5}
  • s.issubset(t),s <= t,子集,測(cè)試 s 中的每一個(gè)元素是否都在 t 中
>>> s.issubset(t)
False
  • s.issuperset(t),s >= t,父集,測(cè)試 t 中的每一個(gè)元素是否都在 s 中
>>> s.issuperset(t)
False
  • s.symmetric_difference(),s ^ t,對(duì)稱(chēng)差集,返回一個(gè)新的 set 包含 s 和 t 中不重復(fù)的元素
>>> s.symmetric_difference(t)
{'e', 'l', 'H', 3, 5, 9, 10, 'o'}
  • s.copy(),返回 set “s”的一個(gè)淺復(fù)制

  • s.isdisjoint(t),零交叉測(cè)試,如果兩個(gè)集合中零交叉,則返回True

>>> s.isdisjoint(t)
True

1.3 增刪改查

1.3.1 增加元素
  • t.add('a') 向集合內(nèi)添加一項(xiàng)元素
>>> t.add('a')
>>> t
{'o', 'e', 'l', 'H', 'a'}
  • s.update([111, 222, 333]) 向集合內(nèi)添加多項(xiàng)元素
>>> s.update([111, 222, 333])
>>> s
{3, 5, 9, 10, 333, 111, 222}
1.3.2 刪除元素
  • s.pop() 隨機(jī)刪除 s 中的一個(gè)元素,并返回
>>> s.pop()
3
  • t.remove('a') 刪除 t 中的元素 a
>>> t.remove('a')
>>> t
{'o', 'e', 'l', 'H'}
  • s.discard() 刪除 s 中的一個(gè)指定元素,如果沒(méi)有此元素,不報(bào)錯(cuò)
>>> s.discard(333)
>>> s
{5, 9, 10, 111, 222}
>>> s.discard(999)
>>> s
{5, 9, 10, 111, 222}
1.3.4 其他
  • len(s) set 的長(zhǎng)度

  • x in s 測(cè)試 x 是否是 s 的成員

  • x not in s 測(cè)試 x 是否不是 s 的成員


set集合練習(xí)題

old_dict = {
   '#1': 8,
   '#2': 4,
   '#4': 2
}

new_dict ={
   '#1': 4,
   '#2': 4,
   '#3': 2
}

需求

  1. 應(yīng)該刪除哪幾個(gè)槽位?
  2. 應(yīng)該更新哪幾個(gè)槽位?
  3. 應(yīng)該增加哪幾個(gè)槽位?

實(shí)現(xiàn)代碼:

old_set = set(old_dict.keys())
new_set = set(new_dict.keys())

del_set = old_set.difference(new_set)   # 應(yīng)該刪除old中有new中無(wú)的差集
update_set = old_set.intersection(new_set)  # 應(yīng)該更新old和new的交集
add_set = new_set.difference(old_set)   # 應(yīng)該增加new中有old中無(wú)的差集

print(del_set)
print(update_set)
print(add_set)

二、文件操作

對(duì)文件操作流程:

  1. 打開(kāi)文件,得到文件句柄并賦值給一個(gè)變量
  2. 通過(guò)句柄對(duì)文件進(jìn)行操作
  3. 關(guān)閉文件

2.1 基本操作 - 讀、寫(xiě)、追加

f = open('lyrics')     # 打開(kāi)文件
first_line = f.readline()
print('first line:',first_line)     # 讀一行
print('我是分隔線(xiàn)'.center(50,'-'))
data = f.read()        # 讀取剩下的所有內(nèi)容,文件大時(shí)不要用
print(data)     # 打印文件
 
f.close()     # 關(guān)閉文件

打開(kāi)文件的模式有:

  • r,只讀模式(默認(rèn))。
  • w,只寫(xiě)模式。【不可讀;不存在則創(chuàng)建;存在則刪除內(nèi)容;】
  • a,追加模式。【可讀; 不存在則創(chuàng)建;存在則只追加內(nèi)容;】

"+" 表示可以同時(shí)讀寫(xiě)某個(gè)文件

  • r+,可讀寫(xiě)文件。【可讀;可追加寫(xiě)】
  • w+,寫(xiě)讀
  • a+,同a 【追加讀】

"U"表示在讀取時(shí),可以將 \r \n \r\n自動(dòng)轉(zhuǎn)換成 \n (與 r 或 r+ 模式同使用)

  • rU
  • r+U

"b"表示處理二進(jìn)制文件(如:FTP發(fā)送上傳ISO鏡像文件,linux可忽略,windows處理二進(jìn)制文件時(shí)需標(biāo)注)

  • rb 網(wǎng)絡(luò)傳輸情況下
  • wb
  • ab

2.2 循環(huán)讀取文件內(nèi)容

  • 差方法
# 讀取到第9行時(shí),打印分割線(xiàn)
for index,line in enumerate(f.readlines())
    if index == 9:
        print("我是分隔線(xiàn)".center(20, '-'))
        continue
    print(line.strip())
  • 好方法
count = 0
for line in f:
    if count == 9:
        print("我是分隔線(xiàn)".center(20, '-'))
        count += 1
        continue
    print(line.strip())
    count += 1

2.3 其他方法

f.tell()獲取當(dāng)前光標(biāo)位置,以及f.seek()移動(dòng)光標(biāo)位置

print(f.tell())         # 獲取當(dāng)前光標(biāo)位置。 (0)
print(f.readline())     # 打印第一行
print(f.readline())     # 打印第二行
print(f.tell())         # 獲取當(dāng)前光標(biāo)位置。 (140)
print(f.seek(0))        # 光標(biāo)移回至起始處
print(f.readline())     # 打印第一行

f.enconding() 當(dāng)前文件的編碼
f.fileno() 返回文件在內(nèi)存中的編號(hào)
f.name() 當(dāng)前文件的名字
f.seekable() 判斷文件光標(biāo)是否可移
f.readable() 判斷文件是否可讀
f.writable() 判斷文件是否可寫(xiě)
f.truncate() 從文件起始截?cái)嗟街付〝?shù)(不填則清空)
f. flush() 將內(nèi)存中暫存的內(nèi)容刷新寫(xiě)入硬盤(pán)

命令行進(jìn)度條實(shí)現(xiàn)方式

import sys, time
for i in range(100):
    sys.stdout.write('#')
    sys.stdout.flush()
    time.sleep(0.1)    # 每打印一個(gè)sleep0.1秒

2.4 文件的修改

將文件中某一行內(nèi)的文字進(jìn)行部分替換

# 將文本中全部的"我"替換為"你"
f = open('Yesterday2', 'r', encoding='utf-8')
f_new = open('Yesterday2.bak', 'w', encoding='utf-8')
for line in f:
    if '我' in line:
        line = line.replace('我', '你')
    f_new.write(line)
f.close()
f_new.close()

2.5 with語(yǔ)句

為了避免打開(kāi)文件后忘記關(guān)閉,可以通過(guò)管理上下文,即:

with open('log','r') as f:
    ...

如此方式,當(dāng)with代碼塊執(zhí)行完畢時(shí),內(nèi)部會(huì)自動(dòng)關(guān)閉并釋放文件資源。

在Python 2.7 后,with又支持同時(shí)對(duì)多個(gè)文件的上下文進(jìn)行管理,即:

with open('log1') as obj1, open('log2') as obj2:
    pass

課堂練習(xí)

程序1:實(shí)現(xiàn)簡(jiǎn)單的shell sed替換功能

import sys
find_str = sys.argv[1]
replace_str = sys.argv[1]
 
with open('Yesterday2', 'r', encoding='utf-8')as f,\
        open('Yesterday3', 'w', encoding='utf-8') as f_new:
    for line in f:
        if find_str in line:
            line = line.replace(find_str, replace_str)
        f_new.write(line)

三、字符轉(zhuǎn)編碼操作

詳細(xì)文章:py編碼終極版 | Strings - Dive into Python3

Ascii碼:每個(gè)字符存1個(gè)字節(jié)
Unicode:每個(gè)字符存2個(gè)字節(jié)
utf-8:英文用1個(gè),其他用3個(gè)字節(jié)


Decode & Encode

所有轉(zhuǎn)換動(dòng)作都需要先decode為Unicode,再encode為相應(yīng)編碼
在字符串之前加u,默認(rèn)為其是Unicode,可直接encode

練習(xí):將字符按順序轉(zhuǎn)換編碼,gb2312 -> utf-8 -> gbk。
Python2

import sys
print(sys.getdefaultencoding())     # 獲取默認(rèn)編碼格式
s = '學(xué)習(xí)學(xué)習(xí)再學(xué)習(xí)'
s_gb = s.decode('uft-8').encode('gb2312')   # utf-8 -> gb2312
s_gb_utf8 = s_gb.decode('gb2312').encode('utf-8')   # gb2312 -> utf-8
s_gb_utf8_gbk = s_gb_utf8.decode('utf-8').encode(gbk)   # utf-8 -> gbk 
print(s_gb.decode('gb2312'))
print(s_gb_utf8.decode('utf-8'))
print(s_gb_utf8_gbk.decode('gbk'))

Python3: 3中encode同時(shí)會(huì)轉(zhuǎn)換為bytes,顯示字符串需要decode為unicode

import sys
print(sys.getdefaultencoding())     # 獲取默認(rèn)編碼格式
s = '學(xué)習(xí)學(xué)習(xí)再學(xué)習(xí)'       # py3_default = unicode
s_gb = s.encode('gb2312')   # unicode -> gb2312
s_gb_utf8 = s_gb.decode('gb2312').encode('utf-8')   # gb2312 -> utf-8
s_gb_utf8_gbk = s_gb_utf8.decode('utf-8').encode('gbk')     # utf-8 -> gbk 
print(s_gb.decode('gb2312'))
print(s_gb_utf8.decode('utf-8'))
print(s_gb_utf8_gbk.decode('gbk'))

四、函數(shù)

4.1 函數(shù)是什么?

函數(shù)是指將一組語(yǔ)句的集合通過(guò)一個(gè)名字(函數(shù)名)封裝起來(lái),要想執(zhí)行這個(gè)函數(shù),只需調(diào)用其函數(shù)名。

4.2 基本語(yǔ)法及特性

4.2.1 語(yǔ)法定義
def sayhi():    #函數(shù)名
    print("Hello, I'm nobody!")

sayhi()        #調(diào)用函數(shù)

帶參數(shù)

# 下面這段代碼
a,b = 5,8
c = a**b
print(c)
 
# 改成用函數(shù)寫(xiě)
def calc(x,y):
    res = x**y
    return res    # 返回函數(shù)執(zhí)行結(jié)果
 
c = calc(a,b)    # 結(jié)果賦值給c變量
print(c)
4.2.2 特性:
  1. 減少重復(fù)代碼
  2. 使程序變得可擴(kuò)展
  3. 使程序變得易維護(hù)

4.3 返回值

return語(yǔ)句返回函數(shù)的執(zhí)行結(jié)果。
注意:

  1. 函數(shù)在執(zhí)行過(guò)程中只要遇到return語(yǔ)句,就會(huì)停止執(zhí)行并返回結(jié)果。所以可以理解為return語(yǔ)句代表著函數(shù)的結(jié)束。
  2. 如果未在函數(shù)中指定return,那這個(gè)函數(shù)的返回值為None

4.4 函數(shù)參數(shù)

4.4.1 形參與實(shí)參

形參:變量只有在被調(diào)用時(shí)才分配內(nèi)存單元,在調(diào)用結(jié)束時(shí),即刻釋放所分配的內(nèi)存單元。因此,形參只在函數(shù)內(nèi)部有效。函數(shù)調(diào)用結(jié)束返回主調(diào)用函數(shù)后則不能再使用該形參變量
實(shí)參:可以是常量、變量、表達(dá)式、函數(shù)等,無(wú)論實(shí)參是何種類(lèi)型的量,在進(jìn)行函數(shù)調(diào)用時(shí),它們都必須有確定的值,以便把這些值傳送給形參。因此應(yīng)預(yù)先用賦值,輸入等辦法使參數(shù)獲得確定值

# 改成用函數(shù)寫(xiě)
def calc(x,y):
    res = x**y
    return res

c = calc(a,b)
print(c)
4.4.2 位置參數(shù)

按順序給函數(shù)傳參數(shù)

def test(x,y,z):
   print(x)
   print(y)
   print(z)

test(1, 2, 3)
4.4.3 關(guān)鍵參數(shù)

正常情況下,給函數(shù)傳參數(shù)要按順序,不想按順序就可以用關(guān)鍵參數(shù),只需指定參數(shù)名即可。但記住一個(gè)要求就是,關(guān)鍵參數(shù)必須放在位置參數(shù)之后。

def test(x,y,z):
   print(x)
   print(y)
   print(z)

test(3, z=6, y=9)
4.4.4 默認(rèn)參數(shù)

在寫(xiě)形參時(shí)直接給形參定義的一個(gè)值。
特點(diǎn):調(diào)用函數(shù)的時(shí)候,默認(rèn)函數(shù)非必須傳遞。
用途:

  1. 默認(rèn)安裝值
  2. 默認(rèn)端口號(hào)
def test(x,y=2):
   print(x)
   print(y)

test(1)
test(1,10)
4.4.5 非固定參數(shù)

*args - 把多傳入的位置參數(shù)變成一個(gè)元組形式。

def stu_register(name,age,*args):    # *args 會(huì)把多傳入的參數(shù)變成一個(gè)元組形式
    print(name,age,args)
 
stu_register("Alex",22)
#輸出
#Alex 22 ()    # 后面這個(gè)()就是args,只是因?yàn)闆](méi)傳值,所以為空
 
stu_register("Jack",32,"CN","Python")
#輸出
# Jack 32 ('CN', 'Python')    # 多傳入的參數(shù)為元組形式

**kwargs - 將多個(gè)關(guān)鍵字參數(shù)寫(xiě)為字典

def stu_register(name,age,*args,**kwargs): # *kwargs 會(huì)把多傳入的參數(shù)變成一個(gè)dict形式
    print(name,age,args,kwargs)
 
stu_register("Alex",22)
#輸出
#Alex 22 () {}#后面這個(gè){}就是kwargs,只是因?yàn)闆](méi)傳值,所以為空
 
stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#輸出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

4.5 全局變量與局部變量

在子程序中定義的變量稱(chēng)為局部變量,在程序的一開(kāi)始定義的變量稱(chēng)為全局變量。
全局變量作用域是整個(gè)程序,局部變量作用域是定義該變量的子程序。
當(dāng)全局變量與局部變量同名時(shí):
在定義局部變量的子程序內(nèi),局部變量起作用;在其它地方全局變量起作用。

name = 'Will'
 
def change_name(name):
    print("before change:", name)
    name = 'William'
    print('after name', name)
 
change_name(name)
print(name)

想在函數(shù)內(nèi)改變?nèi)肿兞恳嚷暶鳎?strong>可實(shí)現(xiàn),但盡量不要用,出錯(cuò)后調(diào)試難度幾何級(jí)提升)

name = 'Will'
school = 'Hometown'
 
def change_name(name):
    global school
    print("before change:", name)
    name = 'William'
    school = 'University'
    print('after name', name)
 
change_name(name)
print(name,school)

五、遞歸

在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身,這個(gè)函數(shù)就是遞歸函數(shù)。
遞歸的特性:

  1. 遞歸必須有一個(gè)明確的結(jié)束條件
  2. 每次進(jìn)入更深一層遞歸時(shí),問(wèn)題規(guī)模相比上次遞歸都應(yīng)有所減少
  3. 遞歸效率不高,遞歸層次過(guò)多會(huì)導(dǎo)致棧溢出(在計(jì)算機(jī)中,函數(shù)調(diào)用是通過(guò)棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會(huì)加一層棧幀,每當(dāng)函數(shù)返回,棧就會(huì)減一層棧幀。由于棧的大小不是無(wú)限的,所以,遞歸調(diào)用的次數(shù)過(guò)多,會(huì)導(dǎo)致棧溢出)
def calc(n):
    print(n)
    if int(n) > 0:
        return calc(int(n/2))
 
calc(10)

六、函數(shù)式編程介紹

函數(shù)是Python內(nèi)建支持的一種封裝,我們通過(guò)把大段代碼拆成函數(shù),通過(guò)一層一層的函數(shù)調(diào)用,就可以把復(fù)雜任務(wù)分解成簡(jiǎn)單的任務(wù),這種分解可以稱(chēng)之為面向過(guò)程的程序設(shè)計(jì)。函數(shù)就是面向過(guò)程的程序設(shè)計(jì)的基本單元。
函數(shù)式編程中的函數(shù)這個(gè)術(shù)語(yǔ)不是指計(jì)算機(jī)中的函數(shù)(實(shí)際上是Subroutine),而是指數(shù)學(xué)中的函數(shù),即自變量的映射。也就是說(shuō)一個(gè)函數(shù)的值僅決定于函數(shù)參數(shù)的值,不依賴(lài)其他狀態(tài)。比如sqrt(x)函數(shù)計(jì)算x的平方根,只要x不變,不論什么時(shí)候調(diào)用,調(diào)用幾次,值都是不變的。

Python對(duì)函數(shù)式編程提供部分支持。由于Python允許使用變量,因此,Python不是純函數(shù)式編程語(yǔ)言。

6.1 定義

簡(jiǎn)單說(shuō),"函數(shù)式編程"是一種"編程范式"(programming paradigm),也就是如何編寫(xiě)程序的方法論。主要思想是把運(yùn)算過(guò)程盡量寫(xiě)成一系列嵌套的函數(shù)調(diào)用。
一個(gè)數(shù)學(xué)表達(dá)式:(1 + 2) * 3 - 4
傳統(tǒng)的過(guò)程式編程

var a = 1 + 2;
var b = a * 3;
var c = b - 4;

函數(shù)式編程要求使用函數(shù),可以把運(yùn)算過(guò)程定義為不同的函數(shù),寫(xiě)成下面這樣:

var result = subtract(multiply(add(1, 2), 3), 4);

再演進(jìn)一下,可以變成這樣

add(1,2).multiply(3).subtract(4)

這基本就是自然語(yǔ)言的表達(dá)了。再看下面的代碼,應(yīng)該一眼就能明白它的意思:

merge([1,2],[3,4]).sort().search("2")

因此,函數(shù)式編程的代碼更容易理解。
但要想學(xué)好函數(shù)式編程,不要用Python,用Erlang,Haskell。

七、高階函數(shù)

變量可以指向函數(shù),函數(shù)的參數(shù)能接收變量。
而一個(gè)函數(shù)就可以接收另一個(gè)函數(shù)作為參數(shù),這種函數(shù)就稱(chēng)之為高階函數(shù)。

def add(a, b, f):
    return f(a)+f(b)
 
res = add(3, 6, abs)
print(res)

八、作業(yè)

將輸入的字符串轉(zhuǎn)為字典的方法:b = eval(b) | json

第3周作業(yè):day3 作業(yè)詳細(xì)
HAproxy配置文件操作(配置文件參考):

  1. 根據(jù)用戶(hù)輸入輸出對(duì)應(yīng)的backend下的server信息
  2. 可添加backend 和sever信息
  3. 可修改backend 和sever信息
  4. 可刪除backend 和sever信息
  5. 操作配置文件前進(jìn)行備份
  6. 添加server信息時(shí),如果ip已經(jīng)存在則修改;如果backend不存在則創(chuàng)建;若信息與已有信息重復(fù)則不操作
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容