python 學習程序中,對新手來說,最難的就是面向物件部分了,但又不得不把它掌握,
在 python 中所有的內容都是物件
python 中的類
學習面向物件,第一個知識點就是類,它可以看成是物件的設計圖,通過提煉各種相似物件的屬性和方法,然后形成一個“模板”,就是類,
在正式開始前,一定要明確一個類可以實體化出多個物件實體,這句話中也包含了,物件、實體、類之間的關系,一定要理解清楚,
類是在程式中實體化物件的設計圖
類的定義
使用關鍵字 class 定義類,class 后面為類名,類名一般采用駝峰命名法,即 MyClass,單詞首字母大寫,
class MyClass:
pass
c = MyClass()
c.name = "橡皮擦"
print(c.name)
類的呼叫與函式類似,使用 類名() 即可,上述 MyClass 是一個空白類(設計圖),呼叫類之后賦值給變數 c,此時的 c 就是類的一個實體物件,一般簡稱為實體或物件,
使用點號 .,可以給物件添加屬性,每個物件都可以添加自己的屬性,
當然一個類可以實體化出多個物件
class MyClass:
pass
c1 = MyClass()
c1.name = "橡皮擦"
print(c1.name)
c2 = MyClass()
c2.name = "大象"
print(c1.name)
print(c2.name)
**類的初始化方法 __init__ **
在類中可以直接定義類初始化時的方法 __init__,該方法在實體生成時執行,類中的方法與普通的函式存在一個小的差異,就是類中的方法必須帶有關鍵字 self,即實體本身,該關鍵字可以為任意變數名,只是約定俗成為 self,
宣告一個類,并給類增加一個初始化方法,
# 定義類
class MyClass:
# 初始化方法,第一個引數為物件本身 self,第二個引數為實體化時必須傳遞的引數
def __init__(self, name):
print(name)
# 類的呼叫,只需要傳遞 name 引數即可
c = MyClass("橡皮擦")
在初始化方法中,可以直接給 self 系結屬性,例如下述代碼:
class MyClass:
def __init__(self, name):
# 將傳遞進來的 name 引數系結到物件(self)上
self.name = name
c = MyClass("橡皮擦")
print(c.name)
類的定義是一個抽象概念的程序
下面將通過一個簡單類定義的程序,為你展示類的抽象程序,
我們要定義一個學生類,這個類是一個設計圖,用它可以實體化出多個學生物件,
首先定義一個空類:
class Student:
pass
接下來要思考的是,在類呼叫(實體化)初始化時就傳遞學生姓名與性別,可以大幅度提高類的便捷性,
class Student:
def __init__(self, name, sex):
self.name = name
self.sex = sex
學生類具備屬性之后,一個學生還應該具備跑這一動作,動作就是方法,就是類內部的函式,
class Student:
def __init__(self, name, sex):
self.name = name
self.sex = sex
def run(self):
print("我是{0},我可以跑步".format(self.name))
除了跑步以外,學生還具備跳高動作,繼續增加一個類方法
class Student:
def __init__(self, name, sex):
self.name = name
self.sex = sex
def run(self):
print("我是{0},我可以跑步".format(self.name))
def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))
到此為止,一個 Student 類就已經定義完畢了,可以拿著這個設計圖去實體化學生了,
xiao_ming = Student("小明", "男")
xiao_hong = Student("小紅", "女")
xiao_ming.run()
xiao_hong.jump()
在類的定義程序中,內部的方法(函式)第一個關鍵字一定不要丟掉,
屬性轉為私有屬性
在 python 中有個約定俗稱的規則,在屬性或者方法名稱前,增加一個下劃線 _,表示該屬性或者方法僅在類的內部使用,
class Student:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self._age = age
def run(self):
print("我是{0},我可以跑步".format(self.name))
def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))
xiao_ming = Student("小明", "男", 19)
xiao_hong = Student("小紅", "女", 20)
xiao_ming.run()
xiao_hong.jump()
# 呼叫私有屬性,可以掉到,但是請遵守約定規則
print(xiao_hong._age)
上述代碼,你可以手動的去呼叫 _age,從而獲取到 age 屬性,更加嚴格的辦法是在屬性或者方法前增加兩個下劃線 __,此時手動呼叫屬性無法獲取,
class Student:
def __init__(self, name, sex, age, weight):
self.name = name
self.sex = sex
self._age = age
self.__weight = weight
def run(self):
print("我是{0},我可以跑步".format(self.name))
def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))
xiao_ming = Student("小明", "男", 19, 180)
xiao_hong = Student("小紅", "女", 20, 90)
xiao_ming.run()
xiao_hong.jump()
# 呼叫私有屬性,可以掉到,但是請遵守約定規則
print(xiao_hong._age)
# 無法呼叫兩個下劃線的屬性
print(xiao_hong.__weight)
錯誤提示如下所示
AttributeError: 'Student' object has no attribute '__weight'
這里真實的情況也是無法避免被呼叫,只是增加兩個下劃線之后,名稱在內部被置換成其它名稱了,看上去是被隱藏掉了,
繼承類以及面向物件的高級特征
在 python 中撰寫類之后,有時需要給類擴展功能,此時最直接的辦法就是繼承類,
類的繼承就是以某一個類為基類來制作新的類,這里的基類也叫做超類,繼承自超類創建的類,為子類,
Python 支持多重繼承,將多個類組合成一個新的類,
類繼承的語法格式如下(包括多重繼承)
class 類名稱(超類1,超類2,超類3,...):
pass
在子類中可以對超類的方法進行重寫,簡單理解就是在子類重新定義一個與超類同名的方法,
class Student:
def __init__(self, name, sex, age, weight):
self.name = name
self.sex = sex
self._age = age
self.__weight = weight
def run(self):
print("我是{0},我可以跑步".format(self.name))
def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))
class Mid_Student(Student):
# 重寫超類方法
def run(self):
print("我重新了超類的 run 方法")
xiao_ming = Student("小明", "男", 19, 180)
xiao_hong = Mid_Student("小紅", "女", 20, 90)
# 呼叫子類的 run Fangfa
xiao_hong.run()
在子類的初始化方法中,可以呼叫超類的初始化方法
該處關鍵詞為 super,使用 super 呼叫超類方法是由于在 python 中,重寫方法是完全覆寫原有內容,例如下述代碼:
class Student:
def __init__(self, name, sex, age, weight):
self.name = name
self.sex = sex
self._age = age
self.__weight = weight
def run(self):
print("我是{0},我可以跑步".format(self.name))
def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))
class Mid_Student(Student):
# __init__ 方法將超類中的初始化方法完全覆寫
def __init__(self, card_id):
self.card_id = card_id
def run(self):
print("我重新了超類的 run 方法")
xiao_hong = Mid_Student(10086)
# 報錯,沒有該屬性
print(xiao_hong.name)
如果希望繼續使用超類的屬性,可以使用 super 函式解決,
class Mid_Student(Student):
def __init__(self, name, sex, age, weight, card_id):
# 通過 super 函式向 Student 類傳參
super().__init__(name, sex, age, weight)
self.card_id = card_id
def run(self):
print("我重新了超類的 run 方法")
xiao_hong = Mid_Student("小紅", "女", 19, 100, 10086)
print(xiao_hong.name)
在 python 中是可以給物件實體任意添加屬性的,例如下述代碼:
class MyClass:
pass
c = MyClass()
c.name = "橡皮擦"
print(c.name)
那是否存在限制任意添加屬性的辦法呢?有的,
使用 __slots__ 屬性即可限制屬性的添加,
class MyClass:
__slots__ = ['name', 'age']
pass
c = MyClass()
c.name = "橡皮擦"
c.age = 19
c.sex = "女"
print(c.name)
運行代碼會出現如下錯誤:AttributeError: 'MyClass' object has no attribute 'sex',
類中的特殊方法
在上文提及的 __init__ 是類的初始化方法,與之相同的還有一些其它特殊方法,
__add__和__iadd__:當物件使用+和+=運算子時,被呼叫;__sub__和__isub__:當物件使用-和-=運算子時,被呼叫;__mul__和__imul__:當物件使用*和*=運算子時,被呼叫;_truediv__和itruediv:當物件使用/和/=運算子時,被呼叫;
相同的規則還有 __floordiv__ 和 __ifloordiv__,__and__,__or__,這些都可以算作類內部定義算術運算子,
比較運算子也可以在類內部進行重定義,
__eq__:使用==運算子時,被呼叫;__ne__:使用!=時被呼叫;__lt__:使用<被呼叫;__gt__:使用>被呼叫;
型別轉換也存在一些特殊方法,
__int__:被內置函式int()呼叫時使用的方法;__float__:被內置函式float()呼叫時使用的方法;__str__:被str()呼叫時使用的方法;__repr__:回傳物件的字串表示方法;__bytes__:被bytes()呼叫時使用的方法;__format__:被format()格式化字串時用到的方法,
如果你定義一個容器型別的類,那還有如下特殊方法可用
__len__:呼叫len()函式時使用;__getitem__:如果想讓物件具備按索引獲取的形式,定義該方法;__setitem__:通過索引設定值;__delitem__:使用del洗掉物件中元素時,被呼叫;__iter__:被iter等迭代類代碼呼叫時;__contains__:使用in運算子時被呼叫,
其它幾個特殊方法
__call__:將物件向函式一樣呼叫;__del__:洗掉物件時被呼叫;__hash__:使用hash函式時被呼叫,
寫在后面
以上內容就是本文的全部內容,希望對學習路上的你有所幫助~
今天是持續寫作的第 226 / 365 天,
期待 關注,點贊、評論、收藏,
更多精彩
- 滾雪球學 Python(完結)
- 滾雪球學 Python 第二輪(完結)
- 滾雪球學 Python 第三輪
- 滾雪球學 Python 番外篇(完結)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/302240.html
標籤:python
