Python(函數與面向對象)
@(Knowledge)[Python, Auspice Vinson]
文章目錄
- Python(函數與面向對象)
- @[toc]
- 函數(function)
- 面向對象
- 類與對象
- 面向對象三大特性
- 垃圾回收
- 特殊方法
- \__new__(cls)
- \__init__(self)
- \__delete__(self)
- \__str__(self)
- \__repr__(self)
- \__lt__(self,other)
- \__le__(self,other)
- \__eq__(self,other)
- \__ne__(self,other)
- \__gt__(self,other)
- \__ge__(self,other)
- \__add__(self,other)
- \__sub__(self,other)
- \__mul__(self,other)
- \__len(self)__
- \__bool(self)__
- 模塊(module)
- 異常
- 文件
文章目錄
- Python(函數與面向對象)
- @[toc]
- 函數(function)
- 面向對象
- 類與對象
- 面向對象三大特性
- 垃圾回收
- 特殊方法
- \__new__(cls)
- \__init__(self)
- \__delete__(self)
- \__str__(self)
- \__repr__(self)
- \__lt__(self,other)
- \__le__(self,other)
- \__eq__(self,other)
- \__ne__(self,other)
- \__gt__(self,other)
- \__ge__(self,other)
- \__add__(self,other)
- \__sub__(self,other)
- \__mul__(self,other)
- \__len(self)__
- \__bool(self)__
- 模塊(module)
- 異常
- 文件
函數(function)
函數也是 對象
保存可執行代碼,並可重複調用
定義函數
函數名中保存內存首地址
def 函數名([形參1,形參2...]):
代碼塊
調用函數
函數名()
參數(形參)
形參聲明變量,但不賦值
- 形參可指定默認值
- 調用時不傳參,默認值生效
def fn(a,b,c = 20):
print(c)
fn(1,2,3)# 3
實參
調用函數時,傳遞的參數
- 關鍵字參數和位置參數可混合使用
- 混合使用時,位置參數必須在關鍵字參數前面
- 同一形參只能賦值一次
位置參數
將對應位置實參,賦值給對應的形參
關鍵字參數
直接根據參數名傳遞參數
fn(b = 1,c = 3,a = 2)
實參類型
解析器不會檢查實參類型
包括函數
- 如果形參指向的是一個對象,修改會影響指向對象的值
c = [1,2,3]
fn(c.copy())
fn(c[:])
不定長參數
形參前加 * ,將獲取所有剩餘形參保存至元組
- 接收所有位置實參,將這些實參保存到同一個元組
- 裝包參數最好放於參數列表末尾
- 若裝包參數位於參數列表中間,其後參數必須以關鍵字參數形式傳遞
- 關鍵字參數必須放於參數列表最後
def fn(a,*b,c):
print(a,b,c)
# a=1,b=(2,3,4),c=5
f(1,2,3,4,c=5)
- 帶 * 形參只能寫一個
# 求任意數字的和
def sum(*a):
print("a=",a,type(a))# tuple
result = 0
for i in a:
result += n
return n
- 要求所有參數以關鍵字形式傳遞
def fn(*,a,b,c):
pass
- *參數只能接收位置參數
- ** 可以接受其他關鍵字參數,保存至字典
- 鍵:關鍵字參數名
- 值:參數值
- 只能有一個
- 只能寫在參數列表最後
def fn(**a):
pass
# a = {'a':1,'b':2,'c':3}
fn(a=1,b=2,c=3)
參數解包
def fn(a,b,c):
pass
t = (10,11,12)
fn(*t)
- 序列中元素個數與形參個數一致
- *序列解包
- **字典解包
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LxGWf5pr-1587303200314)(./1585301982654.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8ZFdDvPH-1587303200318)(./1585301991659.png)]
返回值
關鍵字 return
- 如果return後不寫或沒有return ,返回空
- return用來結束函數
文檔字符串
直接在函數第一行寫一個字符串
def fn(a:int,b:bool,b:str = 'Hello')-> int:
```
文檔字符串實例
形參列表,參數名後加:表明參數類型
函數聲明 -> 表示返回類型
```
return 10
help(fnName)
查詢python中函數用法
作用域(scope)
變量生效區域
- 兩種作用域
- 全局作用域:
- 在程序執行時創建,程序結束時銷燬
- 所有函數以外的區域
- 函數作用域
- 在函數調用時創建 ,調用結束銷燬
- 每調用一次,產生新的函數作用域
- 函數作用域中定義的變量,是局部變量,只能在函數內部訪問
- 作用域嵌套
- 賦值默認爲當前作用域
- 同名變量
- 優先在當前作用域尋找,如果有則使用
- 當前作用域沒有,去上一級作用域查找
- 函數內部修改全局變量
- global聲明變量
- global a
命名空間(namespace)
變量作用域
- 每個變量都需要存儲到指定的命名空間內
- 存儲變量的字典
- 全局命名空間
- 保存全局變量
- 函數命名空間
- 保存函數中的變量
locals()
獲取當前作用域的命名空間
- 向scope添加變量
- 向字典中添加鍵值對
scope = locals()
scope['c'] = 1000
- 只用於查看當前命名空間
- 外部不能訪問內部
global()
在任意命名空間中獲取全局命名空間
遞歸
將大問題分解爲小問題,知道不可再分
解決小問題
- 遞歸與循環基本可互相轉換
- 可用循環優化代碼
# 遞歸求階乘
def fac(n):
if n==1:
return 1
else:
return n*fab(n-1)
# 漢諾塔實踐
# 函數定義
# def hanoi (n, src, dst, mid):
# pass
# 參數說明
# n是整數,表示圓柱 A 上面的圓盤個數。
# src是大寫字母A,表示最左邊的圓柱。
# dst是大寫字母C,表示最右邊的圓柱。
# mid是大寫字母B,表示中間的圓柱。
count = 0
def hanoi (n, src, dst, mid):
global count
if n == 1:
print("{}: {}->{}".format(1, src, dst))
count += 1
else:
hanoi(n-1,src,mid,dst)
count += 1
print(f"{count}:{src}->{dst}")
hanoi(n-1,mid,dst,src)
hanoi(3, "A", "C", "B")
print(count)
# 冪運算
# n:底數
# i:次數
def fn(n,i):
if i == 1:
return n
else:
return n*fn(n,i-1)
print(fn(2,3))
# 迴文串
def huiwen(str,beg,end):
if beg==end:
return True
if str[beg]!=str[end]:
return False
else:
return huiwen(str,beg+1,end-1)
str = "abaa"
print(huiwen(str,0,len(str)-1))
def hui_wen(str):
if len(str)<2:
return True
elif str[0] != str[-1]:
return False
return hui_wen(str[1:-1])
函數式編程
Python中,函數式一等對象
一等對象
- 對象是運行是創建
- 能賦值給變量或作爲數據結構中的元素
- 能作爲參數傳遞
- 能作爲返回值返回
高階函數
函數的函數
- 接收一個或多個函數作爲參數
- 將函數作爲返回值返回
函數作爲參數
def fn1(a):
# 檢查是否爲偶數
if a%2==0:
return True
else:
return False
def fn5(a):
# 檢查是否大於5
if a > 5:
return True
else:
return False
def fn(fnc,a):
# 判斷a是否滿足fnc
if fnc(a):
return True
else:
return False
print(fn(fn5,1))
匿名函數(lambda)
創建一些簡單函數
語法
- lambda 參數列表:返回值
def fn(a,b):
return a+b
lambda a,b:a+b
fliter(fnc,iteSeq)
從序列中過濾出符合條件的元素,返回一個可迭代結構
map(fnc,iteSeq)
對可迭代元素做指定操作,添加到新對象中返回
print(map(lambda i:i+1,lst))
list.sort(fnc)
默認比較大小
- 每次取列表中的一個元素作爲一個參數來調用函數
- 使用函數返回值比較元素大小
- key函數只在比較時起作用,不改變原數據
lst = ['a','bbb','a']
lst.sort(key=len)
print(lst)
sorted(seq,key=)
可對任意序列進行排列
- 不影響原序列,返回新對象
閉包
將函數作爲返回值返回
- 返回內部函數
- 通過閉包創建只有當前函數可訪問的變量
- 函數嵌套
裝飾器
通過裝飾器可以在不修改原函數情況下對函數進行擴展
def fn(old_fun):
def new_fun(*args,**kwargs):
# *args接收所有位置參數
# kwargs接收所有關鍵字參數
print('開始執行')
result = old_fun(*args,**kwargs)
return result
return new_fun
@fn
def old_fun():
pass
# old_fun被裝飾
- 通過@裝飾器,使用指定裝飾器
- 可以同時爲一個函數指定多個裝飾器,函數 由內向外 裝飾器裝飾
OCP(開閉原則)
- 開放對程序的擴展
- 關閉對程序的修改
面向對象
類與對象
對象
內存中專門用於存儲數據的一塊區域
- 三部分
- 對象的標識–id
- 對象的類型–type
- 對象的值–value
類(class)
對象是類的實例
- 自定義類使用 大寫字母開頭
# 內置類創建
a = int(10) # create int object
b = str('hello') # create a string object
- 創建自定義類
- 語法:
class 類名([父類]):
代碼塊
class Myclass():
pass
- 使用自定義類創建對象
class Myclass():
pass
mc = Myclass()
對象的創建流程
類是用來創建對象的對象
- 創建變量
- 在內存中創建一個新對象
- 執行_init_()
- 將對象的id賦值給變量
類的定義
屬性+方法
-
在類中定義的變量,將成爲所有實例的公共屬性
- 公共屬性都可以被實例訪問
-
類中定義的函數爲方法
- 所有實例都可訪問類方法
- 方法調用 默認傳遞一個參數,所以 方法 中至少有一個形參
屬性和方法
當調用一個對象的屬性時,解析器會現在當前對象中找是否有該屬性
- 有,則直接返回對象的屬性值
- 沒有,去類對象中找
- 有,則返回類屬性
- 無,報錯
類屬性(方法)
所有實例共享的屬性(方法)
實例屬性(方法)
某個實例特有的屬性(方法)
- 一般情況下,屬性 保存在實例對象中
- 方法保存在類對象中
self
本實例,相當於this
類init()
- 特殊方法以 _ 開始和結束
- 特殊方法不需要自己調用
_init()_在對象創建時執行
在新創建的對象初始化屬性
- 通過self向新創建的對象初始化屬性
- 作爲實例屬性
class Myclass:
def _init_(self.name):
self.name = name
- 調用類創建對象時,參數列表中的參數會依次傳遞到init()中
類的基本結構
class 類名([父類]):
公共屬性...
# 對象初始化方法
def _init_(self,...):
...
# 其他方法
def method_1(self,...):
...
def method_2(self,...):
...
類屬性
類屬性只能通過類方法修改,實例方法無法修改
實例屬性
實例屬性,只能通過實例方法訪問或修改的屬性,類方法無法修改
實例方法
第一個參數爲 self 的方法是實例方法
將 對象 作爲 self 傳入
- 類和實例都可調用實例方法
- 通過實例調用,將當前調用對象作爲 self 自動傳入
- 通過類調用,不會自動傳遞當前對象,需手動傳入 實例
class A:
pass
a = A()
a.test()
A.test(a)
類方法
使用 @classmethod 修飾的方法
- 第一個參數爲 cls, 自動傳遞,
- cls 表示當前類對象
class A:
@classmethod
def test(cls):
print(cls)
- 通過類和實例調用
靜態方法
類中 @staticmethod 修飾的方法
- 不需要傳遞參數
- 可通過類和實例調用
面向對象三大特性
1. 封裝
確保對象數據安全
隱藏對象中不希望被外部訪問的屬性或方法
-
通過更換變量名,隱藏
-
提供 getter 和 setter 外部可以訪問到屬性
- getter 獲取對象中的指定屬性
- get_屬性名()
- setter 修改對象中的指定屬性
- set_屬性名()
- 在 setter 中增加數據驗證,確保數據值的正確性
- getter 獲取對象中的指定屬性
-
一般情況 _屬性名 表示隱藏私有屬性
對象屬性前使用雙下劃綫
實際上將名字修改爲 __類名__屬性名
# __propertyName
class Person:
def _init_(self,name):
self.__name = name
def get_name(self,name):
return self.__name
def set_name(self,name):
self.__name = name
property裝飾器
property 裝飾器,將一個get方法轉換爲對象屬性
- 使用 @property 方法,必須和屬性名一樣
- setter裝飾器: @屬性名.setter
- getter裝飾器: @property
- 使用setter裝飾器 必須有 getter裝飾器
# @property
class Person:
def _init_(self,name):
self._name = name
@property
def name(self,name):
return self._name
@name.setter
def name(self,name):
self._name = name
p = Person('name1')
print(p.name)
2.繼承
保證對象的可擴展性
子類繼承父類中所有方法
包括特殊方法
- _init_(self,name)
class 子類名([父類列表]):
pass
- 省略父類列表,默認爲父類 object
- isinstance(instanceName,className)
檢查是否是某類的實例
- issubclass(subClassName,className)
檢查是否爲子類
重寫(overwrite)
子類中有與父類同名方法,調用子類方法
包括特殊方法
- _init_(self,name)
super()
調用父類方法修改父類屬性
- 通過 super() 調用父類方法,不需要傳遞 self
def Subclass(SuperClass):
def __init__(self,[Subclass propertyList]):
super().__init__([SuperClass propertyList])
self._propertyName = propertyVlue
className._bases_
獲取當前類的所有父類
多重繼承
爲一個類指定多個父類
- 父類列表前面方法覆蓋後邊
- 第一個父類
- 第一個父類的父類
- 第二個父類
- …
3. 多態
保證程序的靈活性
不考慮參數類型,只要符合某些特徵,就可以使用方法
- len()
- 只要對象中具有 _len_() 特殊方法,就可以通過 len() 方法獲取對象長度
垃圾回收
沒有引用的對象爲 垃圾
自動垃圾回收機制
不需要手動處理垃圾
- 在 程序結束 時,自動刪除垃圾
_delete_(self)
在垃圾回收前刪除
特殊方法
__ 開頭和結尾
- 配合多態使用
- 特殊方法不需要手動調用
_new_(cls)
對象創建時調用
_init_(self)
對象初始化
_delete_(self)
對象刪除前調用
_str_(self)
** ** 打印的是__str()__的返回值
_repr_(self)
會對當前對象使用 repr() 時調用
指定對象在 交互模式(命令行) 中直接輸出的效果
_lt_(self,other)
小於
- <
_le_(self,other)
小於等於
- <=
_eq_(self,other)
等於
- ==
_ne_(self,other)
不等於
- !=
_gt_(self,other)
大於
_ge_(self,other)
大於等於
- >=
# 定義 > < >= <= ==
class Person:
def __lt__(self,other):
return True
_add_(self,other)
_sub_(self,other)
_mul_(self,other)
_len(self)_
獲取對象長度
_bool(self)_
定義使用 bool() 返回值
模塊(module)
將一個完整程序分解爲一個個小模塊,將模塊組合,搭建一個完整程序
重要特性:複用
模塊創建
一個文件爲一個模塊
- 模塊名要符合標識符規範
- 在主模塊中相當於變量
引用外部模塊
- import 模塊名
- 在多次引用同一個模塊,但只包含一個實例
- import 模塊名 as 別名
通過 moduleName._name_ 可以獲取模塊名字
- 一個程序只有一個主模塊 _main_
包(package)
模塊中代碼過多,或一個模塊分解爲多個模塊
-
包:文件夾
-
模塊:.py文件
-
包中必須有 _init_ 文件,包含包中主要內容
from packageName import moduleName:引入包中指定模塊
_pycache_:模塊緩存文件
使用包時將模塊代碼轉換爲機器碼,在編譯一次後,將代碼保存到緩存文件中,避免重複編譯
python標準庫
sys
提供變量和函數,可以獲取到Python解析器信息
或者通過函數操作解析器
import sys
# sys.argv
# 獲取執行代碼時,命令行所包含的參數
# 返回列表,保存當前命令的所有參數
# sys.modules
# 獲取當前程序中引入的所有模塊
# 返回字典,key:模塊名字,value:模塊內容
# sys.path
# 返回列表,保存模塊的搜索路徑
# 當前目錄優先
# sys.platform
# 表示當前Python運行平臺
# sys.exit()
# 退出當前程
pprint
import pprint
# pprint()
# 對打印數據做簡單格式化
# pprint.pprint()
os
操作系統模塊,對操作系統進行訪問
import os
# os.environ[]
# 獲取系統的環境
# os.system()
# 執行操作系統的命令
# os.system('dir')
異常
程序運行時:
使用沒有賦值變量
使用不存在索引值
除0此時在異常處終止
處理異常
try:
代碼塊(出現錯誤語句)
except:
代碼塊(出現錯誤處理方式)
else:
代碼塊(沒出錯執行語句)
finally:
代碼塊(最後都會執行語句)
異常拋出
- 在函數中出現的異常進行處理,則不會繼續傳播
- 若未處理,繼續向調用處傳播,直到全局作用域
- 全局作用域爲處理,程序終止,顯示異常信息
- 所有異常信息會被保存到異常對象中
- 異常傳播是,將異常對象拋給調用處
異常對象
異常類 | 含義 |
---|---|
ZeroDivisionError | 表示除0異常 |
NameError | 處理變量錯誤異常 |
IndexError | 索引異常 |
捕獲異常對象
try:
代碼塊
except 異常類型:
# 加上異常類型,只捕獲特定類型異常
代碼塊
except 異常類型:
pass
except Exception as 異常名:
# except後不加內容,捕獲到所有異常
pass
finally:
#無論是否出現異常,該子句都會執行
pass
Exception
- 所有異常的父類
語法
- try必須有
- except和finally至少有一個
自定義異常對象
-
使用 raise 拋出異常
- raise 異常類或異常實例(異常信息)
-
所有異常都必須是 Exception 子類
class MyError(Exception):
pass
文件
- I/O(Input/Output)
文件操作步驟
- 打開文件
- 對文件進行操作
- 保存
- 關閉文件
打開文件
使用 open 函數打開文件
- 返回一個代表打開文件的對象
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
- file:要打開的文件路徑
- 需要注意相對路徑與絕對路徑
- 在 Windows 下,可以用 / 代替 \
- 或者使用 \\ 代替 \
- 或者使用原始字符串 r"str"
- 使用 … 返回上一級目錄
- 如果目標文件距離當前文件較遠,使用絕對路徑
try:
fileName = "demo.txt"
fileObj = open(fileName) # 打開fileName文件
print(fileObj.read())
fileObj.close()
except Exception as identifier:
print('文件不存在')
關閉文件
- close() 方法關閉文件
# with...as
with open(fileName) as file_obj:
# 在with語句中可以直接使用file_obj做文件操作
pass
文件讀取
- read 方法用來讀取文件的內容,會將內容保存爲一個字符串返回
- 默認爲純文本文件格式打開,編碼爲none
try:
fileName = ''
with open(fileName) as fileObj:
content = fileObj.read()
print(content)
except FileNotFoundError as identifier:
print(f"{fileName}文件不存在")
讀取文件格式
- 純文本文件(使用utf-8編寫的文本文件)
- 二進制文件(圖片,mp3,ppt)
讀取中文文件
- 指定文件編碼爲 utf-8
try:
fileName = 'demo.txt'
with open(fileName,encoding='utf-8') as fileObj:
content = fileObj.read()
print(content)
except FileNotFoundError as identifier:
print(f"{fileName}文件不存在")
讀取大文件
- read(size=-1)
- 指定要讀字符數量,默認值爲-1,讀取文件中所有字符
- 字符數量少於指定數量,全部讀出
- read()會記錄上次讀取位置
- 讀取到文件末尾,返回’’(空串)
try:
fileName = 'demo.txt'
with open(fileName,encoding='utf-8') as fileObj:
chunk = 100
fileContent = ""
while True:
content = fileObj.read(chunk)
# 檢查是否讀取到了內容
if not content:
# 內容讀取完畢
break
fileContent+=content
print("本次讀取到的內容"+content,end="")
except FileNotFoundError as identifier:
print(f"{fileName}文件不存在")
readline()&readlines()
- readline() 讀取一行內容
- readline() 自帶換行
- readlines()
- 一次讀取到的內容返回,封裝到一個列表中返回
try:
fileName = 'demo.txt'
with open(fileName,encoding='utf-8') as fileObj:
# readline() 讀取一行內容
print(fileObj.readline())
print(fileObj.readlines())
except FileNotFoundError as identifier:
print(f"{fileName}文件不存在")
直接遍歷文件對象
fileObj = open(fileName)
for t in fileObj:
print(t)
文件寫入
write()
- 使用 open() 打開文件,需要指定要做的操作
- 不指定默認爲讀取文件
- r:表示只讀
- w:表示可寫
- 文件不存在,創建文件
- 文件存在,覆蓋原文件
- a:表示追加內容
- 文件不存在,創建內容
- 文件存在,向文件追加內容
- +:表示增加權限
- r+: 即可讀又可寫,文件不存在報錯
- w+
- a+
- x:用來新建文件
- 不存在,則創建
- 存在,則報錯
- 寫入文本文件,傳遞一個字符串作爲參數
- 返回寫入字符的個數
import pprint
try:
fileName = 'demo.txt'
with open(fileName,'w',encoding='utf-8',) as fileObj:
# write()向文件寫入內容
fileObj.write("Hello World\n")
fileObj.write("Auspice Vinson")
with open(fileName,'r',encoding="utf-8") as fileObj:
for t in fileObj:
print(t)
except FileNotFoundError as identifier:
print(f"{fileName}文件不存在")
二進制文件
**open()**參數
- p
- 讀取文本文件
- b
- 讀取二進制文件
- 以字節讀取
# 讀取filename中的文件,寫入新對象中
with open(filename,'rb') as fileobj:
with open(fileName,'wb') as fileObj:
chunk = 1024*1024
while True:
content = fileObj.read(chunk)
if not content:
break
fileObj.write(content)
seek()&tell()
- fileObj.tell() 查看當前讀取位置
- fileObj.seek() 切換讀取位置
- arc1,切換的位置
- arc2,計算位置方式
- 0:從頭計算,默認
- 1:從當前位置計算
- 2:從最後位置開始計算
其他操作
- 需要引入 os
import os
# 返回列表,元素爲目錄中每個文件名
r = os.listdir()
# 獲取當前所在的目錄
r = os.getcwd()
# 切換當前目錄 cd
r = os.chdir()
# 創建目錄
os.mkdir()
# 刪除目錄
os.rmdir()
# 刪除文件
os.remove()
# 重命名,移動文件
os.rename(oldName,newName)