python學習——類,文件和異常

 

創建類

創建一個小狗的類

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創建出來的東西是類實例,類實例可以用的方法是實例方法,所有實例共享的方法是類方法

所有實例所共享的屬性叫做類屬性

構造函數的要點如下

  1. 名稱固定,必須爲__int__() 這裏是兩道下劃線
  2. 第一個參數固定,必須爲self。 self指的是剛剛創建好的實例對象
  3. 構造函數通常用來初始化實例對象屬性
  4. 通過類名(參數列表)來調用構造函數。調用後,將創建好的對象返回給相應的變量
  5. 例如 s = Dog("哈士奇",5)
  6. __init__()方法是初始化創建好的對象
  7. __new__方法是用於創建對象,一般無需重定義該方法

所有類方法的第一個參數必須是self

實例屬性要點如下

1.實例屬性一般在__init__()方法中定義,初始化

2.在本類的其他實例方法中,也是通過self進行訪問

3.創建實例對象後,通過實例對象訪問實例屬性

如 

a = Dog("哈士奇",5)
a.age = 10#將哈士奇的年齡改爲10歲

實例方法

實例方法是從屬於實例對象的方法,實例方法的定義格式如下

def 方法名(self,形參列表)
     函數體

方法的調用格式如下

對象.方法名(參數列表)

要點如下

  1. 第一個參數必須爲self
  2. 調用實例方法時,不需要也不能給self傳參,self由解釋器自動傳參

函數與方法的區別

  • 1.都是用來完成一個功能的語句塊,本質一樣
  • 2.方法調用時,通過對象來調用,方法從屬於特定實例對象
  • 3.直觀上看,方法定義時需要傳遞self,函數不需要

 

實例對象的方法調用實質

a.sit 相當於 Dog.sit(a)

其他操作

  1. dir(obj)可以獲得對象的所有屬性和方法
  2. obj.__dict__對象的屬性字典 就是將一個對象的各個屬性以及它的值以字典的形式打印出來
  3. pass空語句
  4. 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指的是類對象
    函數體
  1. @classmethod 必須位於方法上面一行
  2. 第一個cls必須有,cls指的就是類對象本身
  3. 調用類方法格式:“類名.類方法名(參數列表)” 參數列表中,不需要也不能給cls傳值
  4. 類方法中訪問實例屬性和實例方法會導致錯誤(不知道訪問的是哪一個對象)
  5. 子類繼承父類方法時,傳入cls是子類對象,而非父類對象

舉個簡單的例子

class Student:
    company = "SXT"
    @classmethod
    def printCompany(cls):
        print(cls.company)
Student.printCompany()

注意類方法是不存在於該類對象的內存中的

 

靜態方法

python中允許定義與類對象無關的方法,稱爲靜態方法

靜態方法和在模塊中定義的普通函數沒有任何區別,只不過靜態方法放到了類中,需要通過類調用

靜態方法語法如下

@staticmethod
def 靜態方法名(形參列表)
    函數體

要點如下

  1. @staticmethod必須位於方法上面一行
  2. 調用靜態方法的格式:“類名.靜態方法名(參數列表)”
  3. 靜態方法中訪問實例屬性和實例方法會導致錯誤
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)

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章