類
創建類
創建一個小狗的類
class Dog():
def __int__(self, name, age):
self.name = name
self.age = age
def sit(self):
print(self.name.title() + " is now sitting")
def roll_over(self):
print(self.name.title() + " rolled over!")
這裏我們定義了一個Dog類,python中首字母大寫的名稱指的是類
根據類來創建實例叫做實例化。
首先會執行一個程序生成的默認的方法__new__()(用於創建對象,一般不需要重定義)
__int__(self,name,age)相當於構造函數,每當創建一個對象的時候會自動執行,用來初始化對象
self參數實際上就是對象本身的引用,相當於C++裏的this指針,我們在調用類方法的時候不需要管它,它會自動傳遞實例的引用
我們可以直接在類內初始化一個值,只需要在初始化函數裏添加相應的語句即可。
與C++不同的是,Dog是類對象,用Dog創建出來的東西是類實例,類實例可以用的方法是實例方法,所有實例共享的方法是類方法
所有實例所共享的屬性叫做類屬性
構造函數的要點如下
- 名稱固定,必須爲__int__() 這裏是兩道下劃線
- 第一個參數固定,必須爲self。 self指的是剛剛創建好的實例對象
- 構造函數通常用來初始化實例對象屬性
- 通過類名(參數列表)來調用構造函數。調用後,將創建好的對象返回給相應的變量
- 例如 s = Dog("哈士奇",5)
- __init__()方法是初始化創建好的對象
- __new__方法是用於創建對象,一般無需重定義該方法
所有類方法的第一個參數必須是self
實例屬性要點如下
1.實例屬性一般在__init__()方法中定義,初始化
2.在本類的其他實例方法中,也是通過self進行訪問
3.創建實例對象後,通過實例對象訪問實例屬性
如
a = Dog("哈士奇",5)
a.age = 10#將哈士奇的年齡改爲10歲
實例方法
實例方法是從屬於實例對象的方法,實例方法的定義格式如下
def 方法名(self,形參列表)
函數體
方法的調用格式如下
對象.方法名(參數列表)
要點如下
- 第一個參數必須爲self
- 調用實例方法時,不需要也不能給self傳參,self由解釋器自動傳參
函數與方法的區別
- 1.都是用來完成一個功能的語句塊,本質一樣
- 2.方法調用時,通過對象來調用,方法從屬於特定實例對象
- 3.直觀上看,方法定義時需要傳遞self,函數不需要
實例對象的方法調用實質
a.sit 相當於 Dog.sit(a)
其他操作
- dir(obj)可以獲得對象的所有屬性和方法
- obj.__dict__對象的屬性字典 就是將一個對象的各個屬性以及它的值以字典的形式打印出來
- pass空語句
- isinstrance(對象,類型)判斷對象是不是指定類型
修改類中屬性的值
1.通過實例進行修改
a.age=10//直接通過實例來修改狗狗的年齡
2.通過類方法進行設置
def changeAge(self,aimAge):
self.age=aimAge
將這個方法添加到類中,並調用這個方法即可修改年齡
規範
類名首字母大寫
類方法使用小寫字母,且單詞之間使用_分隔
類方法之間空一行來分隔
類之間使用兩個空行來分隔
類對象
class Student:
pass
print(type(Student))
print(id(Student))
'''
<class 'type'>
2922809951984
'''
這個type是python中的摸具類,所有的類都是以他爲摸具創建的
可以輸出Student的地址,說明Student是一個對象,即類的模板也是個一個對象
類屬性
類屬性是屬於類對象的屬性,也稱爲類變量,由於,類屬性從屬於類對象,可以被所有實例對象共享
類屬性相當於C++中的靜態成員變量
class Student:
#在方法外面的是類屬性,它被所有Student類的對象所共享
company = "SXT"
count = 0
def __init__(self,name,score):
self.name = name #實例屬性
self.score = score
Student.count+=1
def say_score(self): #實例方法
print("我的公司是",Student.company)
print(self.name,"的分數是:",self.score)
s1 = Student("張三",80) #s1是實例對象,自動調用__init__()方法
s1.say_score()
print("一共創建了{0}個對象".format(Student.count))
內存分析
可以看到類屬性並沒有在對象的內存中
類方法
類方法是從屬於類對象的方法,類方法通過裝飾器@classmethod來定義,格式如下
@classmethod
def 類方法名(cls ,參數列表)#cls指的是類對象
函數體
- @classmethod 必須位於方法上面一行
- 第一個cls必須有,cls指的就是類對象本身
- 調用類方法格式:“類名.類方法名(參數列表)” 參數列表中,不需要也不能給cls傳值
- 類方法中訪問實例屬性和實例方法會導致錯誤(不知道訪問的是哪一個對象)
- 子類繼承父類方法時,傳入cls是子類對象,而非父類對象
舉個簡單的例子
class Student:
company = "SXT"
@classmethod
def printCompany(cls):
print(cls.company)
Student.printCompany()
注意類方法是不存在於該類對象的內存中的
靜態方法
python中允許定義與類對象無關的方法,稱爲靜態方法
靜態方法和在模塊中定義的普通函數沒有任何區別,只不過靜態方法放到了類中,需要通過類調用
靜態方法語法如下
@staticmethod
def 靜態方法名(形參列表)
函數體
要點如下
- @staticmethod必須位於方法上面一行
- 調用靜態方法的格式:“類名.靜態方法名(參數列表)”
- 靜態方法中訪問實例屬性和實例方法會導致錯誤
class Student:
company = "SXT"
@staticmethod
def add(a,b):
print("{0}+{1}={2}".format(a,b,a+b))
Student.add(1,2)
析構函數和垃圾回收機制
__del__方法稱爲析構方法,用於實現對象被銷燬時所需進行的操作,比如釋放對象佔用的資源
python實現自動的垃圾回收,當對象沒有被引用時(引用計數爲0),由垃圾回收器調用__del__方法
也可以通過del語句刪除對象,從而保證調用__del__方法
系統會自動提供__del__方法,一般不需要自定義析構方法
class Person:
def __del__(self):
print("銷燬對象:{0}".format(self))
p1 = Person()
p2 = Person()
del p2
print("程序結束")
'''
銷燬對象:<__main__.Person object at 0x000001A7BE2956A0>
程序結束
銷燬對象:<__main__.Person object at 0x000001A7BE281730>
'''
__call__方法
在python中,函數其實時一個對象,可以通過函數名(參數列表)調用函數,我們一個把一個類實例變成一個可調用對象,即通過類實例名(參數列表)來調用某個函數
class fun:
def __call__(self, str,salary):
print(str,"你的工資是",salary)
aa = fun()
aa("張三",3000)
'''
張三 你的工資是 3000
'''
方法重載
在其他語言中, 可以定義多個重名的方法, 只要保證方法簽名唯一即可; 方法簽名包含3個部分: 方法名, 參數數量, 參數類型
Python中, 方法的參數沒有聲明類型(調用時確定參數的類型), 參數的數量也可以由可變參數控制; 因此, Python中是沒有方法重載的; 定義一個方法即可有多重調用方法, 相當於實現了其他語言中的方法的重載;
如果我們在類體中定義了多個重名的方法, 只有最後一個有效;
建議: 不要使用重名的方法, Python中方法沒有重載;
方法的動態性
Python是動態語言, 我們可以動態的爲類添加新的方法, 或者動態的修改類的已有的方法;
#Python中沒有方法的重載,定義多個同名方法,只有最後一個有效
class Person:
def say_hi(self):
print('hello')
def say_hi(self,name):
print("{0},hello".format(name))
p1 = Person()
p1.say_hi('張三') #張三,hello
# p1.say_hi() #不帶參數,報錯say_hi() missing 1 required positional argument: 'name'
#測試方法的動態性,一切都是對象,方法也是對象
class Test:
def work(self):
print("努力上班")
def play_game(s):
print("{0}在玩遊戲".format(s))
def work2(s):
print("好好學習")
Test.play = play_game;#把paly_game方法添加到類裏面去,把實例方法變成類方法
s = Test()
s.work()
s.play() #上面已經把play賦值爲函數play_game
Test.work = work2
s.work()
輸出:
D:\wwwroot\pyiteam\venv\Scripts\python.exe D:/wwwroot/pyiteam/mypro_obj/mypy02.py
張三,hello
努力上班
<__main__.Test object at 0x0141C3D0>在玩遊戲
好好學習
Process finished with exit code 0
@property 裝飾器
@property可以將一個方法的調用方式變成“屬性調用”。
在我們定義數據庫字段類的時候,往往需要對其中的類屬性做一些限制,一般用get和set方法來寫,那在python中,我們該怎麼做能夠少寫代碼,又能優雅的實現想要的限制,減少錯誤的發生呢,這時候就需要我們的@property閃亮登場啦,巴拉巴拉能量……..
用代碼來舉例子更容易理解,比如一個學生成績表定義成這樣
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
我們調用的時候需要這麼調用:
>>> s = Student()
>>> s.set_score(60) # ok!
>>> s.get_score()
60
>>> s.set_score(9999)
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
但是爲了方便,節省時間,我們不想寫s.set_score(9999)啊,直接寫s.score = 9999不是更快麼,加了方法做限制不能讓調用的時候變麻煩啊,@property快來幫忙….
class Student(object):
@property//相當於getter
def score(self):
return self._score
@score.setter//相當於setter
def score(self,value):
if not isinstance(value, int):
raise ValueError('分數必須是整數纔行吶')
if value < 0 or value > 100:
raise ValueError('分數必須0-100之間')
self._score = value
看上面代碼可知,把get方法變爲屬性只需要加上@property裝飾器即可,此時@property本身又會創建另外一個裝飾器@score.setter,負責把set方法變成給屬性賦值,這麼做完後,我們調用起來既可控又方便
>>> s = Student()
>>> s.score = 60 # OK,實際轉化爲s.set_score(60)
>>> s.score # OK,實際轉化爲s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
類的繼承
如果在類定義中沒有指定父類,則默認父類是object類,也就是說,object是所有類的父類,裏面定義了一些所有類的共有的默認實現,比如:new().
定義子類時,必須在其構造函數中調用父類的構造函數。調用格式如下:
父類名.__init__(self,參數列表)
class Car():
#汽車類
def __int__(self,make,model,year):
self.make=make
self.model=model
self.year=year
self.odometer_reading=0#初始化里程爲0
def get_descriptive_name(self):
long_name=str(self.year+' '+self.make+' '+self.model)
return long_name.title()
def read_odometer(self,mileage):
if mileage >= self.odometer_reading:
self.odometer_reading=mileage
else:
print("你不能這樣做")
#電動汽車類
class ElectricCar(Car):
def __init__(self,make,model,year):
super().__init__(make,model,year)#這條代碼是初始化父類所有屬性
self.battery_size=70#電動車特有電瓶屬性
內存分析
注意事項:創建子類時,父類必須在前面,而且必須在子類括號裏指明父類的名稱
super()是一個特殊函數,它可以將子類和父類關聯起來,可以調用父類的__init__()方法,使子類中包含父類的所有屬性
只要子類方法裏的方法與父類方法同名,python就只會執行子類裏的方法
類成員的繼承和重寫
1、成員繼承:子類繼承了父類除構造方法之外的所有成員。
2、方法重寫:子類可以重新定義父類中的方法,這樣就會覆蓋父類中的方法,也稱爲重寫。
查看類的繼承層次結構
通過類的方法 mro() 或者類的屬性 mor 可以輸出這個類的繼承層次結構。
查看類的繼承層次結構
class A:pass
class B(A):pass
class C(B):pass
print(C.mro())
結果如下
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
object根類
object類是所有類的父類,因此所有的類都有object類的屬性和方法。
例如我們建一個空的類
內置函數dir()可以讓我們看到指定對象所有的屬性。
class A:
pass
a = A()
print(a.__dir__())
輸出如下,可以看出有很多來自object類的方法
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
實際上我們自己定義的方法也是一種屬性,只不過它是屬於方法屬性罷了
重寫_str_()方法
object有一個_str_()方法,用於返回一個對於“對象描述”,對應於內置函數str()經常用於print()方法,幫助我們查看對象的信息,str()可以重寫。
class Person: #默認繼承object類
def __init__(self,name):
self.name = name
def __str__(self):
return"名字是:{0}".format(self.name)
p = Person("弟弟")
print(p)
輸出是
名字是:弟弟
MRO()
Python支持多繼承,如果父類中有相同名字的方法,在子類沒有指定父類名時,解釋器將“從左向右”按順序搜索。
MRO(Method Resolution Order):方法解析順序。我們可以通過mro()方法獲得“類的層次結構”,方法解析順序也是按照這個“類的層次結構”尋找的。
class A:
def aa(self):
print("aa")
def say(self):
print("say AAA!")
class B:
def bb(self):
print("bb")
def say(self):
print("say BBB!")
class C(B,A):
def cc(self):
print("cc")
c = C()
print(C.mro()) #打印類的層次結構
c.say() #解釋器尋找方法是“從左到右”的方式尋找,此時會執行B中的say
結果如下
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
say BBB!
super()獲得父類定義
在子類中,如果想要獲得父類的方法時,我們可以通過super()來做。
supper()代表父類的定義,不是父類對象。
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
#A.say(self)
super().say()
print("B:",self)
B().say()
結果如下
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
say BBB!
多態
多態(polymorphism)是指同一個方法調用由於對象不同可能會產生不同的行爲。
要點
1、多態是方法的多態,屬性沒有多態。
2、多態的存在有2個必要條件:繼承、方法重寫。
class Man:
def eat(self):
print("餓了,喫飯啦!")
class Chinese(Man):
def eat(self):
print("中國人用筷子喫飯")
class English(Man):
def eat(self):
print("英國人用叉子喫飯")
class Indian(Man):
def eat(self):
print("印度人用右手喫飯")
def manEat(m):
if isinstance(m,Man):
m.eat() #多態,一個方法調用,根據對象不同調用不同的方法。
else:
print("不能喫飯")
manEat(Chinese())
manEat(English())
結果如下
中國人用筷子喫飯
英國人用叉子喫飯
感覺比C++簡單多了
特殊方法和運算符重載
Python的運算符實際上是通過調用對象的特殊方法實現的。比如:
a = 20
b = 30
c = a+b
d = a.__add__(b)
print("c=",c)
print("d=",d)
結果如下
c= 50
d= 50
常見的特殊方法統計如下
以上方法都要加上雙下劃線
每個運算符實際上都對應了相應的方法,統計如下:
以上方法都要加上單下劃線
測試運算符重載
class Person:
def __init__(self,name):
self.name = name
def __add__(self,other):
if isinstance(other,Person):
return ("{0}--{1}".format(self.name,other.name))
else:
return "不是同類對象,不能相加"
def __mul__(self,other):
if isinstance(other,int):
return self.name*other
else:
return "不是同類對象不能相乘"
p1 = Person("我的")
p2 = Person("弟弟")
x = p1 + p2
print(x)
print(x*30)
結果如下
我的--弟弟
我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟我的--弟弟
特殊屬性
Python對象中包含了很多雙下劃線開始和結束的屬性。
測試一些特殊屬性
class A:
pass
class B:
pass
class C(B,A):
def __init__(self,nn):
self.nn = nn
def cc(self):
print("cc")
c = C(3)
print(dir(c))
print(c.__dict__)
print(c.__class__)
print(C.__bases__)
print(C.mro())
print(A.__subclasses__())
結果如下
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cc', 'nn']
{'nn': 3}
<class '__main__.C'>
(<class '__main__.B'>, <class '__main__.A'>)
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
[<class '__main__.C'>]
對象的淺拷貝和深拷貝
變量的賦值操作
只是形成兩個變量,實際還是指向同一個對象。
淺拷貝
Python拷貝一般都是淺拷貝,拷貝時,對象包含的子對象內容不拷貝。因此,源對象和拷貝對象會引用同一個對象。
深拷貝
使用copy模塊的deepcopy函數,遞歸拷貝對象中包含的子對象。源對象和拷貝對象所有的子對象也不同。
測試對象的淺拷貝、深拷貝
import copy
class MobilePhone:
def __init__(self,cpu,screen):
self.cpu = cpu
self.screen = screen
class CPU:
def calculate(self):
print("12345")
print("cpu的對象:",self)
class Screen:
def show(self):
print("顯示一個好看的畫面")
print("screen對象:",self)
#測試變量賦值
c1 = CPU()
c2 = c1
print(c1)
#測試淺複製
s1 = Screen()
m1 = MobilePhone(c1,s1)
m2 = copy.copy(m1)
print(m1,m1.cpu,m1.screen)
print(m2,m2.cpu,m2.screen)
#測試深複製
m3 = copy.deepcopy(m1)
print(m1,m1.cpu,m1.screen)
print(m3,m3.cpu,m3.screen)
結果
測試淺複製
<__main__.MobilePhone object at 0x000002C36CD43240> <__main__.CPU object at 0x000002C36BC74E10> <__main__.Screen object at 0x000002C36CD431D0>
<__main__.MobilePhone object at 0x000002C36CD43128> <__main__.CPU object at 0x000002C36BC74E10> <__main__.Screen object at 0x000002C36CD431D0>
測試深複製
<__main__.MobilePhone object at 0x000002C36CD43240> <__main__.CPU object at 0x000002C36BC74E10> <__main__.Screen object at 0x000002C36CD431D0>
<__main__.MobilePhone object at 0x000002C36CD435F8> <__main__.CPU object at 0x000002C36CD436A0> <__main__.Screen object at 0x000002C36CD43710>
組合
“Is-a”關係,我們可以使用“繼承”,從而實現子類擁有的父類的方法和屬性。“is-a”關係指的是類似這樣的關係。
“has-a”關係,我們可以使用“組合”,也能實現一個類擁有另一個類的方法和屬性。
#測試組合
#使用繼承實現代碼的複用
class A1:
def say_a1(self):
print("a1,a1,a1")
class B1(A1):
pass
b1 = B1()
b1.say_a1()
#同樣的效果,使用組合實現代碼的複用
class A2:
def say_a2(self):
print("a2,a2,a2")
class B2:
def __init__(self,a):
self.a = a
a2 = A2()
b2 = B2(a2)
b2.a.say_a2()
結果如下:
a1,a1,a1
a2,a2,a2
測試has-a關係,使用組合
#測試has-a關係,使用組合
class MoilePhone:
def __init__(self,cpu,screen):
self.cpu = cpu
self.screen = screen
class CPU:
def calculate(self):
print("12345")
print("cpu對象:",self)
class Screen:
def show(self):
print("顯示一個好看的畫面")
print("screen對象",self)
m = MoilePhone(CPU(),Screen())
m.cpu.calculate()
m.screen.show()
結果如下
12345
cpu對象: <__main__.CPU object at 0x0000017EDEA2C3C8>
顯示一個好看的畫面
screen對象 <__main__.Screen object at 0x0000017EDEA2C358>
設計模式_工廠模式實現
設計模式是面嚮對象語言特有的內容,是我們在面臨某一類問題時候固定的做法。設計模式有很多種,比較流行的是:GOF(Group Of Four)23種設計模式。
工廠模式實現了創建者和調用者的分離,使用專門的工廠類將選擇實現類,創建對象進行統一的管理和控制。
#測試工廠模式
class CarFactory:
def create_car(self,brand):
if brand == "奔馳":
return Benz()
elif brand == "寶馬":
return BMW()
elif brand == "比亞迪":
return BYD()
else:
return "未知品牌,無法創建"
class Benz:
pass
class BMW:
pass
class BYD:
pass
factory = CarFactory()
c1 = factory.create_car("奔馳")
c2 = factory.create_car("比亞迪")
print(c1)
print(c2)
結果如下:
<__main__.Benz object at 0x000002C245C44E48>
<__main__.BYD object at 0x000002C246CD8908>
設計模式_單例模式實現
單例模式(singleton Pattern)的核心作用是確保一個類只有一個實例,並且提供一個訪問該實例的全屬訪問點。
單例模式只生成一個實例對象,減少了對系統資源的開銷。當一個對象產生需要比較多的資源,如讀取配置文件、產生其他依賴對象時,可以產生一個"單例對象",然後永久駐留內存中,從而極大的降低開銷。
#測試單例模式
class MySingleton:
__obj = None #類屬性
__init_flag = True
def __new__(cls, *args, **kwargs):
if cls.__obj == None:
cls.__obj =object.__new__(cls)
return cls.__obj
def __init__(self,name):
if MySingleton.__init_flag:
print("init......")
self.name = name
MySingleton.__init_flag = False
a = MySingleton("aa")
b = MySingleton("bb")
print(a)
print(b)
c = MySingleton("cc")
print(c)
結果如下
init......
<__main__.MySingleton object at 0x00000290F4EDBE80>
<__main__.MySingleton object at 0x00000290F4EDBE80>
<__main__.MySingleton object at 0x00000290F4EDBE80>
可以將工廠模式和單例模式組合起來,即只有一個工廠
# 測試工廠模式和單例模式
class CarFactory:
__obj = None # 類屬性
__init_flag = True
def create_car(self, brand):
if brand == "奔馳":
return Benz()
elif brand == "寶馬":
return BMW()
elif brand == "比亞迪":
return BYD()
else:
return "未知品牌,無法創建"
def __new__(cls, *args, **kwargs):
if cls.__obj == None:
cls.__obj =object.__new__(cls)
return cls.__obj
def __init__(self):
if CarFactory.__init_flag:
print("CarFactoryinit......")
CarFactory.__init_flag = False
class Benz:
pass
class BMW:
pass
class BYD:
pass
a = CarFactory()
b = CarFactory()
print(a)
print(b)
結果如下
CarFactoryinit......
<__main__.CarFactory object at 0x0000027423547DC0>
<__main__.CarFactory object at 0x0000027423547DC0>
導入類
導入類和導入模塊的方法是一樣的
1.import 文件名
可使用該文件中的所有類 以及函數,但是注意,用類來定義實例時候要加文件名.類名
2.from 文件名 import 類名
直接使用類名來定義實例即可
3. import 文件名 as 改後的名字
4.from 文件名 import 類名 as 改後的名字
文件和異常
從文件中讀取數據
#aa.txt
123
456
789
在當前目錄下創建一個aa.txt的文件
with open("aa.txt") as fp:
c=fp.read()
print(c)
open函數參數爲要打開文件的文件名,返回一個表示該文件的對象,用as 將其存儲在fp中
後續對fp的操作就相當於對相應的文件進行操作,read方法是從文件頭讀到文件尾,返回一個字符串,當讀到文件尾部的時候,返回一個空字符串
輸出結果爲:
我們可以使用rstrip方法來刪除這個空白
rstrip:用來去除結尾字符、空白符(包括\n、\r、\t、' ',即:換行、回車、製表符、空格)
with open("aa.txt") as fp:
c=fp.read()
print(c.rstrip())
文件路徑
如果要讀取的文件不在當前目錄內,而是在當前目錄的文件內,需要提供文件路徑
windows下是這樣的
逐行讀取
with open("aa.txt") as fp:
for i in fp:
print(i)
會發現輸出變成這樣了
123
456
789
爲什麼會有這麼多空行呢
因爲文件中每行有一個換行符,再加上print也會輸出一個換行符。可以通過rstrip方法來消除文件行換行符
with open("aa.txt") as fp:
for i in fp:
print(i.rstrip())
創建一個包含文件各行內容的列表
with open("aa.txt") as fp:
c=fp.readlines()
print(c)
輸出結果是
['123\n', '456\n', '789\n']
可以使用rstrip來消除'\n'
json.uload函數
可以將json格式文件中數據以字符串的形式讀取出來
import json
fp = open('aa.txt','r')
a = json.load(fp)
print(a)
寫入文件
with open('aa.txt','w') as fp:
fp.write("123456")
將‘123456’寫入aa.txt文件
注意w是指只寫的方式打開文件,r的只讀方式打開文件,r+是可讀可寫的方式打開文件,a是以接着上次的寫,w是清空文件,之後再寫。python默認方式是隻讀。
如果想寫入多行的話,需要加上換行符
也可以使用庫中的json.dump()函數
與write方法不同的時,json.dump()函數可以將寫入文件的數據
自動轉換爲str類型。
列表和字典無法通過write存儲到文件中,因此要使用json.dump()將字典轉換爲一種叫json格式來存儲它
json.dump(x,y) x是要存的數據,y是文件對象
import json
a={'a':1,'b':2}
with open('aa.txt','w') as fp:
json.dump(a,fp)
'''
aa.txt
{"a": 1, "b": 2}
'''
異常
程序在運行時,如果Python 解釋器遇到到一個錯誤,會停止程序的執行,並且提示一些錯誤信息,這就是異常
程序停止執行並且提示錯誤信息這個動作,我們通常稱之爲:拋出(raise)異常
程序開發時,很難將所有的特殊情況都處理的面面俱到,通過異常捕獲可以針對突發事件做集中的處理,從而保證程序的穩定性和健壯性
捕獲異常
在程序開發中,如果對某些代碼的執行不能確定是否正確,可以增加try(嘗試)來捕獲異常
捕獲異常最簡單的語法格式:
try:
嘗試執行的代碼
except:
出現錯誤後的處理
try 下面編寫要嘗試的代碼。
except 如果不是,下面編寫嘗試失敗的代碼
處理ZeroDivisionError異常
print(5/0)
這一條代碼,python會報錯
使用try-except
try:
print(5/0)
except ZeroDivisionError:
print("error")
意思是執行try中的語句,然後如果出錯,就會執行except中的內容
在程序執行時,可能會遇到不同類型的異常,並且需要針對不同類型的異常,做出不同的響應,這個時候,就需要捕獲錯誤類型了
語法如下:
try:
#嘗試執行的代碼
except 錯誤類型1:
except 錯誤類型2:
except Exception as result:
print("未知錯誤 %s"% result)
舉個例子
try:
num = int(input("請輸入整數:"))
print(8/num)
except ValueError:
print("請輸入正確的整數")
except ZeroDivisionError:
print("除 0 錯誤")
捕獲未知錯誤
在開發時,要預判到所有可能出現的錯誤,還是有一定難度的
如果希望程序無論出現任何錯誤,都不會因爲Python解釋器拋出異常而被終止,可以再增加一個exucept
語法如下
except Exception as result:
print("未知的錯誤 %s"%s result)
else 代碼塊
try:
print(3/2)
except ZeroDivisionError:
print("error")
else:
print("no error")
如果try裏的代碼成功執行了,則執行else裏的內容。
finally代碼塊
無論執行成功與否,都會執行finally代碼塊裏的代碼
完整代碼展示
try:
print(8/a)
except ZeroDivisionError:
print("error")
except Exception as result:
print("未知錯誤 %s"% result)
else:
print("執行成功")
finally:
print("無論執行是否成功,都會執行的代碼")
輸出結果
未知錯誤 name 'a' is not defined
無論執行是否成功,都會執行的代碼
拋出hraise異常
在開發中,除了代碼執行出錯Python解釋器會拋出異常之外
還可以根據應用程序特有的業務需求主動拋出異常
示例
提示用戶輸入密碼,如果長度少於 8,拋出異常
注意
當前函數只負責提示用戶輸入密碼,如果密碼長度不正確,需要其他的函數進行額外處理
因此可以拋出異常,由其他需要處理的函數捕獲異常
4拋出異常
Python中提供了一個Exception異常類
在開發時,如果滿足特定業務需求時,希望拋出異常,可以:
創建一個Exception的對象
使用raise關鍵字拋出異常對象
def input_password():
pwd = input("請輸入密碼:")
if len(pwd) >= 8:
return pwd
e = Exception("密碼長度不夠")
raise e
try:
user_pwd = input_password()
print(use_pwd)
except Exception as result:
print("發現錯誤:%s"%result)