Python學習筆記2
函式
定義函式
def 函式名(引數):
程式碼1
程式碼2
......
呼叫函式
函式名(引數)
- 引數可有可無
- 函式必須先定義後使用
函式的說明文件
定義函式的說明文件
def 函式名(引數):
"""說明文件的位置"""
程式碼
......
檢視函式的說明文件
help(函式名)
def num(a, b): """ 求和 :param a: 引數1 :param b: 引數2 :return: 返回值 """ res = a + b return res help(num) 輸出: num(a, b) 求和 :param a: 引數1 :param b: 引數2 :return: 返回值
修改全域性變數
a = 100
def test():
a = 200
test()
print(a) # 100
a = 100
def test2():
global a
a = 200
test2()
print(a) # 200
返回值
def test1():
return 1, 2
print(test1()) # (1, 2)
- 返回多個數據的時候,預設是元組型別
- return 後面可以連線列表、元組或字典,以返回多個值
函式的引數
一、位置引數
def user_info(name, age, gender): print(f"您的名字是{name}, 年齡是{age}, 性別是{gender}") user_info("Tom", 20, "男")
二、關鍵字引數
函式呼叫通過“鍵=值”形式加以指定。清晰、容易,清除了引數的順序需求
def user_info(name, age, gender):
print(f"您的名字是{name}, 年齡是{age}, 性別是{gender}")
user_info("Tom", age=20, gender="男")
user_info("Jerry", gender="男", age=16)
注意:函式呼叫時,如果有位置引數時,位置引數必須在關鍵字引數的前面,但關鍵字之間不存在先後順序
三、預設引數
也叫預設引數,用於定義函式,為引數提供預設值,呼叫函式時可不傳該預設引數的值(注意:所有位置引數必須出現在預設引數前,包括函式定義和呼叫)
def user_info(name, age, gender="男"):
print(f"您的名字是{name}, 年齡是{age}, 性別是{gender}")
user_info("TOM", 20)
user_info("Rose", 18, "女")
四、不定長引數
也叫可變引數。用於不確定呼叫的時候會傳遞多少個引數(不傳參也可以)的場景。
包裹位置傳遞
def user_info(*args):
print(args)
user_info("TOM") # ('TOM',)
user_info("TOM", 18) # ('TOM', 18)
傳進的所有引數都會被args變數收集,它會根據傳進引數的位置合併為一個元組(tuple),args是元組型別
包裹關鍵字傳遞
def user_info(**kwargs):
print(kwargs)
user_info(name="TOM", age=18, gender="男")
# {'name': 'TOM', 'age': 18, 'gender': '男'}
合併為一個字典
拆包與交換變數
元組拆包
def return_num():
return 100, 200
num1, num2 = return_num()
print(num1) # 100
print(num2) # 200
字典拆包
dict1 = {"name": "TOM", "age": 18}
a, b = dict1
print(a) # name
print(b) # age
print(dict1[a]) # TOM
print(dict1[b]) # 18
交換變數
方法一:定義中間變數
方法二:
a, b = 1, 2
a, b = b, a
print(a) # 2
print(b) # 1
引用
在Python中,值是靠引用來傳遞的
id() 獲取地址
可變型別:列表、字典、集合
不可變型別:整形、浮點型、字串、元組
(資料能否直接修改,能直接修改就是可變、否則是不可變)
引用當做實參
def test1(c):
print(c)
print(id(c))
c += c
print(c)
print(id(c))
a = 100
test1(100)
100
140728557835008
200
140728557838208
b = [1, 2]
test1()
[1, 2]
2156910280832
[1, 2, 1, 2]
2156910280832
lambda
lambda 引數列表: 表示式
- lambda表示式的引數可有可無,函式的引數在lambda表示式中完全使用
- lambda表示式能接收任何數量的引數但只能返回一個表示式的值
計算a+b
fn1 = lambda a, b: a + b
print(fn1(1, 2)) # 3
引數形式
無引數
fn1 = lambda: 100
print(fn1())
一個引數
fn1 = lambda a: a
print(fn1("hello world"))
預設引數
fn1 = lambda a, b, c=100: a + b +c
print(fn1(10, 20))
可變引數 *agrs
fn1 = lambda *args: args
print(fn1(1, 2, 3)) # 返回值為元組
可變引數 **kwargs
fn1 = lambda **kwargs: kwargs
print(fn1(name="Tom", age=20)) # {'name': 'Tom', 'age': 20}
應用
判斷
fn1 = lambda a, b: a if a > b else b
print(fn1(100, 99))
列表資料按字典key的值排序
students = [
{"name": "TOM", "age": 20},
{"name": "ROSE", "age": 19},
{"name": "JACK", "age": 22},
]
# 按age值升序排列
students.sort(key=lambda x: x["age"])
print(students)
# 按age值降序排列
students.sort(key=lambda x: x["age"], reverse=True)
print(students)
高階函式
abs() 取絕對值
round() 四捨五入
def sum_num(a, b, f):
return f(a) + f(b)
res = sum_num(-1, 2, abs)
print(res) # 3
res = sum_num(1.4, 2.5, round)
print(res) # 4
內建高階函式
map()
map(func, lst), 將傳入的函式變數func作用到lst變數的每個元素中,並將結果組成新的列表(Python2) / 迭代器(Python3)返回。
計算list1序列中各個數字的2次方
list1 = [1, 2, 3, 4, 5]
def func(x):
return x ** 2
res = map(func, list1) # res是迭代器
print(res) # <map object at 0x000002839775C070>
print(list(res)) # [1, 4, 9, 16, 25]
reduce()
reduce(func, lst), 其中func必須有兩個引數。每次func計算的結果繼續和序列的下一個元素做累計計算。
計算list1序列中各個數字的累加和
import functools
list1 = [1, 2, 3, 4, 5]
def func(a, b):
return a + b
res = functools.reduce(func, list1)
print(res) # 15
filter()
filter(func, lst) 函式用於過濾序列,過濾掉不符合條件的元素,返回一個filter物件。如果要轉換為列表,可以使用list() 來轉換
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def func(x):
return x % 2 == 0
res = filter(func, list1)
print(res) # <filter object at 0x000002A29F1C6B80>
print(list(res)) # [2, 4, 6, 8, 10]
檔案操作
開啟
open(name, mode) # 開啟一個已存在的檔案,或建立一個新的檔案
name: 目標檔名的字串(可以包含檔案所在的具體路徑)
mode: 訪問模式(只讀、寫入、追加...)
f = open("text.txt", "w")
f.write("abc")
f.close()
訪問模式
r :只讀;如果檔案不存在,報錯;檔案指標在開頭(預設訪問模式)
rb:以二進位制格式開啟
r+:可讀可寫
rb:二進位制,讀寫
w : 只寫;如果檔案不存在,新建;檔案指標在開頭
wb :
w+ :
wb+ :
a 追加;如果檔案不存在,新建;檔案指標在結尾
ab:
a+:
ab+:
讀
read()
檔案物件.read(num) num表示讀取的長度,省略則讀取全部
readlines()
整行讀取,返回是列表,其中每一行的資料為一個元素
readline()
一次讀取一行內容
seek() 移動檔案指標
檔案物件.seek(偏移量, 起始位置)
起始位置
0:檔案開頭
1:當前位置
2:檔案結尾
檔案備份
old_name = input("請輸入您要備份的檔名:")
index = old_name.rfind(".")
if index > 0:
postfix = old_name[index:]
new_name = old_name[:index] + "[備份]" + postfix
print(new_name)
old_f = open(old_name, "rb")
new_f = open(new_name, "wb")
while True:
con = old_f.read(1024)
if len(con) == 0:
break
new_f.write(con)
old_f.close()
new_f.close()
檔案和資料夾操作
import os
重新命名檔案/資料夾
os.rename("text.txt", "text2.txt")
刪除檔案
os.remove("text[備份].txt")
建立資料夾
os.mkdir("aa")
刪除資料夾
os.rmdir("aa")
獲取當前目錄
print(os.getcwd()) # D:\pycharm\hello
改變預設目錄
os.chdir("aa")
print(os.getcwd()) # D:\pycharm\hello\aa
獲取某個資料夾下的所有檔案,返回一個列表,無參則返回當前目錄下的所有資料夾
print(os.listdir("aa"))
例項:批量修改檔名
import os
flag = 1
file_list = os.listdir()
print(file_list)
for i in file_list:
if flag == 1: # 新增Python_字首
new_name = "Python_" + i
elif flag == 2: # 刪除Python_字首
num = len("Python_")
new_name = i[num:]
os.rename(i, new_name)
面向物件
定義類
class 類名():
程式碼
......
注意:類名要滿足識別符號命名規則,同時遵循大駝峰命名習慣
class Washer():
def wash(self):
print("洗衣服")
print(self)
haier1 = Washer()
haier1.wash()
洗衣服
<__main__.Washer object at 0x000002DCD8DAA430>
haier2 = Washer()
haier2.wash()
洗衣服
<__main__.Washer object at 0x000002DCDA8A55B0>
新增和獲取物件屬性
類外面新增和獲取物件屬性
物件名.屬性名 = 值
haier1.width = 500
haier1.height = 800
print(haier1.width) # 500
類裡面獲取物件屬性
class Washer():
def wash(self):
print("洗衣服")
def print_info(self):
print(self.width)
haier1 = Washer()
haier1.width = 500
haier1.print_info()
魔法方法
在Python中,_xx_() 的函式叫做魔法方法,指的是具有特殊功能的函式
_init_() 初始化物件
class Washer():
def __init__(self):
self.width = 500
self.height = 800
def wash(self):
print("洗衣服")
def print_info(self):
print(f"洗衣機的寬度是{self.width},高度是{self.height}")
haier1 = Washer()
haier1.width = 501
haier1.print_info() # 洗衣機的寬度是501,高度是800
帶引數
class Washer():
def __init__(self, width, height):
self.width = width
self.height = height
def wash(self):
print("洗衣服")
def print_info(self):
print(f"洗衣機的寬度是{self.width},高度是{self.height}")
haier1 = Washer(500, 800)
haier1.print_info()
注意:
_init_() 方法,在建立一個物件時預設被呼叫,不需要手動呼叫
_inti_(self)中的self引數,不需要開發者傳遞,Python直譯器會自動把當前的物件引用傳遞過去
_str_()
當使用print輸出物件的時候,預設列印物件的記憶體地址。如果類定義了_str_方法,那麼就會列印從這個方法中return的資料
class Washer():
def __str__(self):
return "這是洗衣機的說明書"
haier1 = Washer()
print(haier1) # 這是洗衣機的說明書
_del_()
當刪除物件時,Python直譯器也會預設呼叫_del_()方法
def __del__(self):
print(f"{self}物件已被刪除")
繼承
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(A):
pass
res = B()
res.info_print() # 1
在Python中,所有類預設繼承object類,object類是頂級類或基類;其他子類叫做派生類。
單繼承
多繼承
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(object):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
class C(A, B):
pass
res = C()
print(res.num) # 1
res.info_print() # 1
當一個類有多個父類的時候,預設使用第一個父類的同名屬性和方法
子類重寫父類同名屬性和方法
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(object):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
class C(A, B):
def __init__(self):
self.num = 3
def info_print(self):
print(self.num)
res = C()
print(res.num) # 3
res.info_print() # 3
_mro_ 檢視繼承關係
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
子類呼叫父類同名方法和屬性
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(object):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
class C(A, B):
def __init__(self):
self.num = 3
def info_print(self):
# 如果先呼叫了父類,父類屬性會覆蓋子類屬性,故在呼叫屬性前,先呼叫自己子類的初始化
self.__init__()
print(self.num)
def info_print_a(self):
A.__init__(self) # 同理
A.info_print(self)
def info_print_b(self):
B.__init__(self)
B.info_print(self)
res = C()
print(res.num) # 3
res.info_print() # 3
res.info_print_a() # 1
res.info_print() # 3
super()
super() 函式是用於呼叫父類(超類)的一個方法。
super 是用來解決多重繼承問題的,直接用類名呼叫父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查詢順序(MRO)、重複呼叫(鑽石繼承)等種種問題。
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(A):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
# 有參寫法
# super(B, self).__init__()
# super(B, self).info_print()
# 無參寫法
super().__init__()
super().info_print()
class C(B):
def __init__(self):
self.num = 3
def info_print(self):
self.__init__()
print(self.num)
# 同時呼叫A和B
def info_print_ab(self):
# super(C, self).__init__()
# super(C, self).info_print()
super().__init__()
super().info_print()
res = C()
res.info_print_ab() # 2 1
私有許可權
設定某個例項屬性或例項方法不繼承給子類
class A(object):
def __init__(self):
self.num = 1
self.__money = 200
def __info_print(self):
print("私有")
class B(A):
pass
res = B()
print(res.money) # AttributeError: 'B' object has no attribute 'money'
res.info_print() # AttributeError: 'B' object has no attribute 'info_print'
獲取和修改私有屬性值
一般定義 get_xx()、set_xx()
class A(object):
def __init__(self):
self.num = 1
self.__money = 200
def get_money(self):
return self.__money
def set_money(self, val):
self.__money = val
def __info_print(self):
print("私有")
class B(A):
pass
res = B()
print(res.get_money()) # 200
res.set_money(500)
print(res.get_money()) # 500
多型
class Dog(object):
def work(self):
print("指哪打哪")
class ArmyDog(Dog):
def work(self):
print("追擊敵人")
class DrugDog(Dog):
def work(self):
print("追查毒品")
class Person(object):
def work_with_dog(self, dog):
dog.work()
ad = ArmyDog()
dd = DrugDog()
daqiu = Person()
daqiu.work_with_dog(ad) # 追擊敵人
daqiu.work_with_dog(dd) # 追查毒品
類屬性和例項屬性
類屬性就是類物件所擁有的屬性,它被該類的所有例項物件所共有
類屬性可以使用類物件或例項物件訪問
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
print(Dog.tooth) # 10
print(wangcai.tooth) # 10
print(xiaohei.tooth) # 10
類屬性的優點
記錄的某項資料始終保持一致時,則定義類屬性
例項屬性要求每個物件為其單獨開闢一份記憶體空間來記錄資料,而類屬性為全類所共有,僅佔用一份記憶體,更加節省記憶體空間
修改類屬性
類屬性只能通過類物件修改,不能通過例項物件修改,如果通過例項物件修改類屬性,表示的是建立了一個例項屬性
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
# 修改類屬性
Dog.tooth = 12
print(Dog.tooth) # 12
print(wangcai.tooth) # 12
print(xiaohei.tooth) # 12
# 不能通過物件修改屬性,如果這樣操作,實則是建立了一個例項屬性
wangcai.tooth = 20
print(Dog.tooth) # 12
print(wangcai.tooth) # 20
print(xiaohei.tooth) # 12
類方法和靜態方法
類方法
需要用裝飾器@classmethod來標識其為類方法,對於類方法,第一個引數必須是類物件,一般以cls作為第一個引數
使用場景
當方法中需要使用類物件(如訪問私有類屬性等)時,定義類方法
類方法一般和類屬性配合使用
class Dog(object):
__tooth = 10
@classmethod
def get_tooth(cls):
return cls.__tooth
wangcai = Dog()
print(wangcai.get_tooth()) # 10
靜態方法
需要通過裝飾器@staticmethod來進行修飾,靜態方法既不需要傳遞類物件也不需要傳遞例項物件(形參沒有self/cls)
靜態方法也能夠通過例項物件和類物件去訪問
使用場景
當方法中既不需要使用例項物件(如例項物件,例項屬性),也不需要使用類物件(如類屬性、類方法、建立例項等)時,定義靜態方法
取消不需要的引數傳遞,有利於減少不必要的記憶體佔用和效能消耗
class Dog(object):
__tooth = 10
@staticmethod
def info_print():
print("建立狗例項")
wangcai = Dog()
# 靜態方法既可以使用物件訪問又可以使用類訪問
wangcai.info_print() # 建立狗例項
Dog.info_print() # 建立狗例項
異常
try:
可能發生錯誤的程式碼
except:
如果出現異常執行的程式碼
try:
f = open("test.txt", "r")
except:
f = open("text.txt", "w")
捕獲指定異常
try:
可能發生錯誤的程式碼
except 異常型別:
如果捕獲到該異常型別執行的程式碼
try:
print(num)
except NameError:
print("有錯誤")
一般嘗試執行的程式碼的異常型別和要捕獲的異常型別不一致,則無法捕獲異常
一般try下方只放一行嘗試執行的程式碼
捕獲多個指定異常
try:
print(1/0)
except (NameError, ZeroDivisionError): # 元組的方式
print("有錯誤")
捕獲異常描述資訊
try:
print(num)
except (NameError, ZeroDivisionError) as result:
print(result) # name 'num' is not defined
捕獲所有異常
Exception是所有程式異常類的父類
try:
print(num)
except Exception as result:
print(result) # name 'num' is not defined
異常的else
else表示的是如果沒有異常要執行的程式碼
try:
print(1) # 1
except Exception as result:
print(result)
else:
print("沒有異常") # 沒有異常
異常的finally
finally表示的是無論是否異常都要執行的程式碼
try:
f = open("test.txt", "r")
except Exception as result:
f = open("text.txt", "w")
else:
print("沒有異常")
finally:
f.close()
異常的傳遞
import time
try:
f = open("text2.txt", "r")
try:
while True:
con = f.readline()
if len(con) == 0:
break
time.sleep(2) # 每隔兩秒
print(con)
except:
print("讀取資料被終止")
finally:
f.close()
print("關閉檔案")
except:
print("開啟失敗")
自定義異常
raise 異常類物件
class ShortInputError(Exception): # 繼承Exception類
def __init__(self, length, min_len):
self.length = length
self.min_len = min_len
# 設定丟擲異常的描述資訊
def __str__(self):
return f"你輸入的長度是{self.length},不能少於{self.min_len}個字元"
def main():
try:
con = input("請輸入密碼:")
if len(con) < 3:
raise ShortInputError(len(con), 3)
except Exception as result:
print(result)
else:
print("密碼輸入完成")
main()
模組
Python模組(Module),是一個Python檔案,以.py結尾,包含了Python物件定義和Python語句
匯入模組
- import 模組名
- from 模組名 import 功能名
- form 模組名 import *
- import 模組名 as 別名
- from 模組名 import 功能名 as 別名
import 模組名
import 模組名1, 模組名2...
import math
math.sqrt(9) # 3.0
from 模組名 import 功能1,功能2......
from math import sqrt
print(sqrt(9))
from 模組名 import *
from math import *
print(sqrt(9))
as定義別名
# 模組別名
import time as tt
tt.sleep(2)
print("hello")
# 功能別名
from time import sleep as sl
sl(2)
print("hello")
製作模組
在當前檔案中呼叫該函式
print(_name_) # _main_
呼叫其他匯入的檔案
print(_name_) # 匯入的檔名
模組定義順序
自己的檔名不要和已有模組名重複,否則導致模組功能無法使用
使用from 模組名 import 功能 的時候,如果功能名字重複,呼叫到的是最後定義或匯入的功能
__all__ 列表
如果一個模組檔案中有__all__變數,當使用from xxx import *匯入時,只能匯入這個列表中的元素
__all__ = ["testA"]
def testA():
print("testA")
def testB():
print("testB")
包
新建包
[new]--->[Python Package]
匯入包
法一
import 包名.模組名
包名.模組名.目標
法二
必須在_init_.py檔案中新增__all__ = [] 控制允許匯入的模組列表
from 包名 import *
模組名.目標
__dict__
class A(object):
a = 0
def __init__(self):
self.b = 1
aa = A()
# 返回類內部所有屬性和方法對應的字典
print(A.__dict__)
{'__module__': '__main__', 'a': 0, '__init__': <function A.__init__ at 0x000001B38BC191F0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
# 返回例項屬性和值組成的字典
print(aa.__dict__)
{'b': 1}