Python學習筆記總結
前言
由於有其他高級語言的開發經驗,所以入門學起來就快很多,不用像初學那樣詳細的看,我根據《Python編程:從入門到實踐(第2版)》做個簡單筆記總結。
安裝
安裝就不記錄了,傻瓜式的下載Python安裝包,然后運行python來確定是否已經添加到環境變量、安裝完畢,當然還要安裝pip.
數據類型
Hello,World
先來寫個簡單的Hello,World看看
msg = "Hello,World!"
print(msg)
變量
和其他高級語言意思一樣,Python推薦命名規范用下划線划分單詞,比如greeting_message
,有空格會引發錯誤比如greeting message
.
字符串
在編程中最常用的應該就是字符串相關的處理了。
Python中推薦字符串用""來包括單引號,用'來包括雙引號,比如:
"The language `Python` is named after Monty Python,not the snake."
'I told my friend,"Python is my favorite language!"'
首字母大寫
name = "ada lovelace"
print(name.title())
#輸出
Ada Lovelace
全部小寫
name = "Ada Lovelace"
print(name.lower())
#輸出
ada lovelace
全部大寫
name = "Ada Lovelace"
print(name.upper())
#輸出
ADA LOVELACE
Tab和換行符
hello="\thello,world!\r\n"
print(hello)
#輸出
hello,world!
格式化
first_name = "ada"
last_name = "lovelace"
full_name = f"{first_name} {last_name}"
print(full_name)
#也可以用format
first_name = "ada"
last_name = "lovelace"
full_name = "{0} {1}".format(first_name,last_name)
print(full_name)
去除空格
#刪除左邊空格
s = ' hello,world '
print(s.lstrip())
#刪除右邊空格
print(s.rstrip())
#刪除兩端的空格
print(s.strip())
'hello,world '
' hello,world'
'hello,world'
List列表
列表由一系列按特定順序排列的元素組成。你可以創建包含字母表中所有字母、數字0~9或所有家庭成員姓名的列表;也可以將任何東西加入列表中,其中的元素之間可以沒有任何關系。
列表增刪改查排序
list.append('添加某元素')
list.insert('插入某元素')
del list[0] #刪除元素
print(list[0]) #打印元素
print(list.pop(0)) #打印彈出的值
list.remove('刪除某值元素')
list.sort()#進行字母排序
list.sorted()#進行臨時排序
list.reverse()#倒序
遍歷列表
mobiles = ['小米','華為','Oppo','iPhone','Vivo']
print(mobiles[3])
for mobile in mobiles:
print(f"{mobile},",end='')
#還可以用range 創建數值列表
for value in range(1,5):
print(value)
#對數值列表進行統計計算
digits=[1,2,3,4,5,6,7,8,9]
min(digits)
max(digits)
sum(digits)
Slice切片
處理列表的部分元素,Python稱之為切片。
mobiles = ['小米','華為','Oppo','iPhone','Vivo']
#切片練習
print("輸出前3個元素:")
print(mobiles[0:3])
print("索引位置從1開始,到索引4位置結束")
print(mobiles[1:4])
print("從列表頭開始,到索引4位置結束")
print(mobiles[:4])
print("索引位置從2開始,到列表尾")
print(mobiles[2:])
print("負數索引,從末尾開始")
print(mobiles[-3:])
遍歷切片
mobiles = ['小米','華為','Oppo','iPhone','Vivo']
#遍歷切片
for mobile in mobiles[:3]: #遍歷3個元素
print(mobile)
for re_mobile in mobiles[-3:]: #遍歷倒數3個元素
print(re_mobile)
復制列表
我們經常需要根據既有列表創建全新的列表。下面來介紹復制列表的工作原理,以及復制列表可提供極大幫助的一種情形。
要復制列表,可創建一個包含整個列表的切片,方法是同時省略起始索引和終止索引([:])
my_foods = ['pizza','falafel','carrot cake']
friend_foods = my_foods[:] #復制了一份我的食物
friend_foods.append('ice cream')
print(my_foods)
print(friend_foods)
Tup元組
元組看起來很像列表,但使用圓括號
而非中括號來標識。定義元組后,就可使用索引來訪問其元素,就像訪問列表元素一樣。
例如,如果有一個大小不應改變的矩形,可將其長度和寬度存儲在一個元組中,從而確保它們是不能修改的:
dimensions=(200,50,1,23,4,5,6,7)
print(dimensions[0])
print(dimensions[1])
#遍歷元組數據
for dimension in dimensions:
print(dimension)
修改元組變量
雖然不能修改元組的元素,但可以給存儲元組的變量賦值。因此,如果要修改前述矩形的尺寸,可重新定義整個元組:
dimensions = (1,2,3,4,5)
for dimension in dimensions:
print(dimension)
#修改
dimensions = (2,3,4,5,6)
for dimension in dimensions:
print(dimension)
Dictionary字典
在Python中,字典是一系列鍵值對
。每個鍵
都與一個值
相關聯,你可使用鍵來訪問相關聯的值。與鍵相關聯的值可以是數、字符串、列表乃至字典。事實上,可將任何Python對象用作字典中的值。
tel = {'jack':4098,'space':4139}
tel['guido'] = 4127
tel['space'] = 4056
print(tel)#打印字典
print(tel['jack'])#訪問字典的值
del tel['space']#刪除鍵值space的字典
print(list(tel)) #遍歷字典鍵值
if 'jack' in tel:
print("yes")
else:
print("no")
#通過get函數來避免報錯
test_key = tel.get('test','no key')
print(test_key)
遍歷字典
一個Python字典可能只包含幾個鍵值對,也可能包含數百萬個鍵值對。鑒於字典可能包含大量數據,Python支持對字典進行遍歷。字典可用於以各種方式存儲信息,因此有多種遍歷方式:可遍歷字典的所有鍵值對
,也可僅遍歷鍵或值
。
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k,v in knights.items():
print(f"\nKey:{k}")
print(f"\nValue:{v}")
#遍歷所有鍵 Key
for name in knights.keys():
print(key.title())
#遍歷所有值 Value
for knight in knights.values():
print(knight.title())
#按照順序遍歷
for name in sorted(knights.keys()):
print(key.title())
While循環
for循環用於針對集合中的每個元素都執行一個代碼塊,而While循環則不斷運行,直到指定的條件不滿足為止。
current_number = 1
while current_number <= 5:
print(current_number)
current_number += 1
讓用戶來選擇何時退出!
msg = "\nTell me something, and I will repeat it back to you:"
msg += "\nEnter 'quit' to end the program. "
message = ""
while message != 'quit':
message = input(msg)
print(message)
用While循環處理列表和字典
#創建一個待驗證用戶列表
unconfirmed_users = ['alice','brian','candace']
#用來存儲已驗證的用戶列表
confirmed_users = []
while unconfirmed_users:
current_user = unconfirmed_users.pop()
print(f"Verifying user:{current_user.title()}")
confirmed_users.append(current_user)
#顯示所有已經驗證過的用戶
print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())
def 函數
定義函數
使用關鍵字def
來告訴Python,你要定義一個函數
。
def greet_user():
"""顯示簡單的問候語"""
print("Hello!")
greet_user()
傳遞參數
def greet_user(username):
"""像誰問好"""
print(f"Hello! {username}")
greet_user("Hacker!")
形參和實參
在函數greet_user()的定義中,變量username是一個形參
(parameter),即函數完成工作所需的信息。在代碼greet_user('jesse')中,值'jesse'是一個實參
(argument)
調用函數時,Python必須將函數調用中的每個實參都關聯到函數定義中的一個形參
。為此,最簡單的關聯方式是基於實參的順序
。這種關聯方式稱為位置實參。
def describe_pet(animal_type,pet_name):
"""顯示寵物的信息."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}'.")
describe_pet('hamster','harry')
關鍵字實參
關鍵字實參是傳遞給函數的名稱值對。因為直接在實參中將名稱和值關聯起來,所以向函數傳遞實參時不會混淆。關鍵字實參的順序無關緊要.
def describe_pet(animal_type,pet_name):
"""顯示寵物的信息。"""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.'")
describe_pet(pet_name='harry',animal_type='hamster')
默認值
編寫函數時,可給每個形參指定默認值。這個在其他高級語言里面也有,就是定義函數的時候直接給形參賦值了。
def describe_pet(animal_type,pet_name='dog'):
"""顯示寵物的信息。"""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.'")
describe_pet('willie')
返回值
Python的函數的返回值和C++的不太一樣,C++在定義函數的時候必須要明確的聲明返回的是什么類型,而Python是根據return 關鍵字來判斷你需要返回什么類型。
def test():
return 1
print(test()+2)
禁止函數修改列表
有時候,需要禁止函數修改列表,可向函數傳遞列表的副本而非原件。
def function_name(list_name[:]):
...
class 類
Python中和其他語言一樣,用關鍵字class
來定義一個類。
__init__
方法,這個類似C++中的構造函數
,self
類似C++中的this指針
,python中聲明定義熟悉直接在__init__
中用self來定義.
class Dog:
"""一次模擬小狗的簡單嘗試"""
def __init__(self,name,age):
"""初始化屬性name和age,類似構造函數"""
self.name = name
self.age = age
def sit(self):
"""模擬小狗收到命令時蹲下!"""
print(f"{self.name.title()} is now sittring.")
def roll_over(self):
"""模擬小狗收到命令時打滾。"""
print(f"{self.name.title()} rolled over!")
my_dog = Dog('Willie',6)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()
my_dog.roll_over()
繼承
面向對象的靈魂三大要素:封裝
、繼承
、多態
,所以在class中繼承必不可少.
在python中,在既有類的基礎上編寫新類時,通常要調用父類的方法__init__()
。這將初始化在父類__init__()
方法中定義的所有屬性,從而讓子類包含這些屬性.
子類繼承父類的關鍵字:(父類),在子類中可以用super()
來調用父類的方法.
class Animal:
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print(f"eating....")
def run(self):
print(f"running....")
def sleep(self):
print(f"sleeping....")
class Dog(Animal):
def __init__(self,name,age):
self.tails = True
super().__init__(name,age)
def roll_over(self):
"""模擬小狗收到命令時打滾。"""
print(f"{self.name.title()} rolled over!")
my_dog = Dog('Willie',6)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
print(f"My dog's tails is {my_dog.tails}.")
my_dog.eat()
my_dog.run()
my_dog.sleep()
my_dog.roll_over()
模塊
模塊就是單獨的一個類文件,將類寫在了.py文件中.
car模塊
"""一個用戶表示汽車的類"""
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 = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""打印一條消息,指出汽車的里程。"""
print(f"This car has {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
my_car.py
代碼
此處的import
語句讓python打開模塊car
並且導入其中的Car
類,因為在一個模塊中可能包含多個類 class
from car import Car
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
導入類是一種有效的編程方式。如果這個程序包含整個Class類,它該有多長啊!通過將這個類移到一個模塊中並導入該模塊,依然可以使用其所有功能,但主程序文件變得整潔而易於閱讀了。這還讓你能夠將大部分邏輯存儲在獨立的文件中。確定類像你希望的那樣工作后,就可以不管這些文件,而專注於主程序的高級邏輯了。
導入模塊中的多個類
利用逗號分隔,可以導入模塊中的多個類。
from car import Car,..,....
導入整個模塊
可以直接用import導入整個模塊
import car #可以使用car模塊中的所有類
car.Car()#使用Car類
導入模塊中的所有類
不推薦這種做法,因為這種方式可能引發名稱方面的迷惑,如果不小心導入了一個與程序文件中其他東西同名的類,將引發難以診斷的錯誤。
需要從一個模塊中導入很多類時,最好導入整個模塊
from module_name import *
使用別名
使用模塊來組織項目代碼時,別名大有裨益。導入類時,也可為其指定別名。
例如,要在程序中創建大量電動汽車實例,需要反復輸入ElectricCar,非常煩瑣。為避免這種煩惱,可在import語句中給ElectricCar指定一個別名:
from electric_car import ElectricCar as EC
文件操作
Python open()
函數用於打開一個文件,創建一個 file
對象,相關的方法才可以調用它進行讀寫。
和C語言中的差不多,前面是打開文件的路徑,后面是打開文件的方式,as
上面說過用來創建別名,那么file_object即使他的對象名。
顯式地調用close
關閉了這個文件句柄,但前提是只有在read成功的情況下。如果有任意異常正好在f = open(...)
之后產生,f.close()
將不會被調用(取決於Python解釋器的做法,文件句柄可能還是會被歸還,但那是另外的話題了)。為了確保不管異常是否觸發,文件都能關閉,我們將其包裹成一個with
語句:
with open('hello.txt') as file_object:
text = file_object.read()
print(text)
bytes類型和str互相轉換
bytes
Python中bytes
表示字節序列
(二進制形式),是一個不可變的數據類型,對應的可變形式是bytearray,也就是字節數組。
可以通過字符串來創建 bytes 對象,或者說將字符串轉換成 bytes 對象有以下三種方法可以達到這個目的:
- 如果字符串的內容都是 ASCII 字符,那么直接在字符串前面添加
b
前綴就可以轉換成 bytes。 bytes 是一個類
,調用它的構造方法,也就是bytes()
,可以將字符串按照指定的字符集轉換成 bytes;如果不指定字符集,那么默認采用 UTF-8。- 字符串本身有一個
encode()
方法,該方法專門用來將字符串按照指定的字符集轉換成對應的字節串;如果不指定字符集,那么默認采用 UTF-8
#通過構造函數創建空 bytes
b1 = bytes()
#通過空字符串創建空 bytes
b2 = b''
#通過b前綴將字符串轉換成 bytes
b3 = b'http://c.biancheng.net/python/'
print("b3: ", b3)
print(b3[3])
print(b3[7:22])
#為 bytes() 方法指定字符集
b4 = bytes('C語言中文網8歲了', encoding='UTF-8')
print("b4: ", b4)
#通過 encode() 方法將字符串轉換成 bytes
b5 = "C語言中文網8歲了".encode('UTF-8')
print("b5: ", b5)
運行結果:
b3: b'http://c.biancheng.net/python/'
112
b'c.biancheng.net'
b4: b'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x918\xe5\xb2\x81\xe4\xba\x86'
b5: b'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x918\xe5\xb2\x81\xe4\xba\x86'
bytes.decode()方法
#通過 encode() 方法將字符串轉換成 bytes
print(b5.decode('UTF-8'))
運行結果:
b5: C語言中文網8歲了
python中字節字符和非字節字符
python3中默認輸入字符串以非字節字符編碼,使用unicode字符集表示,可以使用encode方法轉化為ascii,utf-8, utf-16等各種編碼形式的字節字符;因此僅非字節字符才被python3認為是標准字符串.
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> uni_str = 'abc'
>>> type(uni_str)
<class 'str'>
>>> utf8_str = uni_str.encode('utf-8')
>>> type(utf8_str)
<class 'bytes'>
>>> asc_str = uni_str.encode('utf-8')
>>> type(asc_str)
<class 'bytes'>
>>> uni_str
'abc'
>>> utf8_str
b'abc'
>>> asc
asc_str ascii(
>>> asc_str
b'abc'
python2中輸入字符串默認使用ascii編碼的字節字符,因此默認不支持中文(存疑),可以使用decode方法將默認字節編碼的字符串轉化為非字節字符,使用unicode字符集表示,進而使用encode方法將unicode字符集的非字節字符轉化為其他編碼形式的字符如utf-8, utf-16;因此編碼后字符串,即字節字符才被python2認為是字符串格式
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> str = 'abc'
>>> type(str)
<type 'str'>
>>> uni_str = str.decode('ascii')
>>> uni_str
u'abc'
>>> type(uni_str)
<type 'unicode'>
>>> utf8_str = uni_str.encode('utf-8')
>>> utf8_str
'abc'
>>> type(utf8_str)
<type 'str'>
Struct解析二進制數據
有的時候需要用python處理二進制數據,比如,存取文件,socket操作時.這時候,可以使用python的struct
模塊來完成.可以用 struct來處理c語言中的結構.
官方解釋是:在Python值和C結構之間轉換的函數。Python bytes對象用於保存表示C結構的數據
直白一點,在c語言中c語言包含不同類型的數據(int,char,bool等等),方便對某一結構對象進行處理。而在網絡通信當中,大多傳遞的數據是以二進制流(binary data)存在的。當傳遞字符串時,那你就需要有一種機制將某些特定的結構體類型打包成二進制流的字符串然后再網絡傳輸,而接收端也應該可以通過某種機制進行解包還原出原始的結構體數據。python中的struct模塊就提供了這樣的機制,該模塊的主要作用就是對python基本類型值與用python字符串格式表示的C struct類型間的轉化,以下原話來自https://www.cnblogs.com/coser/archive/2011/12/17/2291160.html
格式字符串
格式字符串是用來在打包和解包數據時指定預期布局的機制。 它們使用指定被打包/解包數據類型的 格式字符 進行構建。 此外,還有一些特殊字符用來控制 字節順序,大小和對齊方式。
字節順序,大小和對齊方式
默認情況下,C類型以機器的本機格式和字節順序表示,並在必要時通過跳過填充字節進行正確對齊(根據C編譯器使用的規則)。
或者,根據下表,格式字符串的第一個字符可用於指示打包數據的字節順序,大小和對齊方式:
字符 | 字節順序 | 大小 | 對齊方式 |
---|---|---|---|
@ |
按原字節 | 按原字節 | 按原字節 |
= |
按原字節 | 標准 | 無 |
< |
小端 | 標准 | 無 |
> |
大端 | 標准 | 無 |
! |
網絡(=大端) | 標准 | 無 |
如果第一個字符不是其中之一,則假定為 '@'
。
格式字符
格式字符具有以下含義;C 和 Python 值之間的按其指定類型的轉換應當是相當明顯的。 標准大小
列是指當使用標准大小時以字節表示的已打包值大小;也就是當格式字符串以 '<'
, '>'
, '!'
或 '='
之一開頭的情況。 當使用本機大小時,已打包值的大小取決於具體的平台。
格式 | C 類型 | Python 類型 | 標准大小 | 備注 |
---|---|---|---|---|
x |
填充字節 | 無 | ||
c |
char | 長度為 1 的字節串 | 1 | |
b |
signed char | 整數 | 1 | (1), (2) |
B |
unsigned char | 整數 | 1 | (2) |
? |
_Bool | bool | 1 | (1) |
h |
short | 整數 | 2 | (2) |
H |
unsigned short | 整數 | 2 | (2) |
i |
int | 整數 | 4 | (2) |
I |
unsigned int | 整數 | 4 | (2) |
l |
long | 整數 | 4 | (2) |
L |
unsigned long | 整數 | 4 | (2) |
q |
long long | 整數 | 8 | (2) |
Q |
unsigned long long | 整數 | 8 | (2) |
n |
ssize_t |
整數 | (3) | |
N |
size_t |
整數 | (3) | |
e |
(6) | float | 2 | (4) |
f |
float | float | 4 | (4) |
d |
double | float | 8 | (4) |
s |
char[] | 字節串 | ||
p |
char[] | 字節串 | ||
P |
void* | 整數 | (5) |
格式字符之前可以帶有整數重復計數。 例如,格式字符串 '4h'
的含義與 'hhhh'
完全相同。
格式之間的空白字符會被忽略;但是計數及其格式字符中不可有空白字符。
10s 表示10個字節的字節串
10c 表示10個字符
0s 表示空字符串
0c 表示0個字符
Example:(三個整數)
打包/解包三個整數的基礎示例:
import struct
pack_data = pack('hhl',1,2,3) #打包兩個short類型一個long類型的數值,即0x00 0x01|0x00 0x02|0x00 0x00 0x00 0x03
print(pack_data)
在C語言中一個short
占用2個字節即word
,一個long
占用4個字節即dword
,
可以看到我當前系統上他以小端格式輸出了如下的數據。
如果需要轉成大端格式比較可視化,只要在改成這種格式>hhl
即可。
接下來是解包,我們從文件或網絡得到C格式的字節流后需要轉成對應的python數據。
import struct
unpack_data = struct.unpack('hhl',b'\x00\x01\x00\x02\x00\x00\x00\x03')
print(unpack_data)
執行后發現數據對不上,如下圖:
這是因為他默認以小端的方式去解包了,所以剛好對應的十進制數據就是256.
所以在解包的時候我們必須要明確解包的順序,是大端還是小端,這里我們需要解成大端的格式即>hhl
Example:(元組)
record = b'raymond \x32\x12\x08\x01\x08'
name, serialnum, school, gradelevel = unpack('<10sHHb', record)
#小端模式
#10s 長度10的字節串
#unsigned short
#unsigned short
#一個字節
Example:(填充)
以下格式 'llh0l'
指定在末尾有兩個填充字節,假定 long 類型按 4 個字節的邊界對齊:
>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
參考文獻:
《Python編程從入門到實踐》
http://c.biancheng.net/view/2175.html [Python bytes類型及用法]
https://www.cnblogs.com/blili/p/11798504.html#綜述python中字符串分為字節字符和非字節字符 [python字符串的encode與decode]
https://docs.python.org/zh-cn/3/library/struct.html#format-strings [struct --- 將字節串解讀為打包的二進制數據]