類
class Student:
def __init__(self, n, a, s):
'''初始化方法'''
def __del__(self):
'析構方法'
def set_score(self, s):
...
def get_score(self):
return self.score
執行個體方法, 描述或規定對象能有哪些行為
執行個體屬性, 記錄每個對象自身的資料(屬性)
添加和修改
obj.attr = 表達式
删除
del obj.attr
初始化方法__init__(self, ....) 把所有對象添加相同個數的屬性
析構方法 __del__(self) 在對象銷毀前釋放對象自身占用的資源
預置的執行個體屬性:
__dict__ 綁定存儲執行個體屬性的字典
__class__ 綁定建立此對象的類
isinstance(obj, 類或元組)
type(obj)
新的一天 筆記:
類屬性
類屬性是類的屬性,此屬性屬于類,不屬于此類的執行個體
作用:
通常用來存儲該類建立的對象的共有屬性
說明:
類屬性,可以通過該類直接通路
類屬性可以通過此類的執行個體直接通路(取值不能指派)
類屬性可以通過此類對象的'__class__' 屬性間接通路
執行個體方法和類方法都屬于類的屬性
示例見:
```
class Car:
total_count = 0 # 建立類屬性,用來儲存汽車的數量
# 類屬性,可以通過該類直接通路
print(Car.total_count) # 0 # 取類屬性的值
Car.total_count += 100 # 修改類屬性
print(Car.total_count) # 100
```
類的文檔字元串:
類内第一個沒有指派給任何變量的字元串為類的文檔字元串
類的文檔字元串綁定在類的__doc__屬性上
示例:
class Dog:
'這是Dog類的文檔字元串'
print(Dog.__doc__)
>>> help(Dog)
h1 = Human('Tarena', 17)
h1.show_info() # Tarena 今年 17 歲
# h1.Age = 18 # 報錯,不允許添加此Age屬性
h1.show_info() # Tarena 今年 17 歲
```
類方法 @classmethd
類方法是用于描述類的行為的方法,類方法屬于類,不屬于該類創
建的對象
說明:
類方法需要使用@classmethod裝飾器定義
類方法至少有一個形參,第一個形參用于綁定類,約定寫為'cls'
類和該類的執行個體都可以調用類方法
類方法不能通路此類建立的對象的執行個體屬性
示例見:
```
class A:
v = 0 # 類屬性
@classmethod
def get_v(cls): # cls為class簡寫
return cls.v
@classmethod
def set_v(cls, value):
cls.v = value
print(A.get_v()) # ???
a = A()
print(a.get_v())
A.set_v(100)
print(A.get_v()) # 100
a.set_v(200)
print(A.get_v()) # 200
```
靜态方法 @staticmethod
靜态方法是定義在類的内部的函數,此函數的作用域是類的内部
說明:
靜态方法需要使用@staticmethod 裝飾器定義
靜态方法與普通函數定義相同,不需要傳入self執行個體參數和cls類參數
靜态方法隻能憑借類或類建立的執行個體調用
靜态方法不能通路類屬性和執行個體屬性
示例見:
```
class A:
@staticmethod
def myadd(x, y):
return x + y
print(A.myadd(100, 200)) # 300
a = A()
print(a.myadd(3, 4)) # 7
```
小結:
函數 操作全局變量和局部變量
執行個體方法 操作全局變量,局部變量,執行個體屬性,類屬性
類方法 操作全局變量,局部變量,類屬性
靜态方法 操作全局變量,局部變量(作用域在類内)
class 用類來描述一個學生的資訊(可以修改之前的Student類)
class Student:
... 此處自己實作
學生資訊有: 姓名,年齡,成績
将這些學生對象存于清單中,可以任意添加和删除學生資訊
1. 列印學生的總個數
2. 列印出所有學生的平均成績
(建議用類來封裝學生資訊,用函數或類方法對學生資料進行操作)
繼承(inheritance) 和 派生(derived)
什麼是繼承和派生
繼承是從已有類中派生出新類,新類具有原類的屬性和行為.
派生就是從一個已有類中衍生出新類,在新類上可以添加新的屬性和行為
說明:
繼承的目的是延續舊的類的功能
派生的目地是在舊類的基礎上添加新的功能
作用:
用繼承派生機制,可以将一些共有功能加在基類中,實作代碼的共享
在不改變基類的代碼的基礎上改變原有類的功能
名詞:
基類(base class)/超類(super class)/父類(father class)
派生類(derived class)/子類(child class)
單繼承
文法:
class 類名(基類名):
語句塊
說明:
單繼承是指派生類由一個基類衍生出新類
示例見:
```
class Human:
'''定義一個'人'類,用來描述人的行為'''
def say(self, what):
print("say:", what)
def walk(self, distance):
print("走了", distance, '公裡')
class Student(Human):
def study(self, subject):
print("學習:", subject)
class Teacher(Human):
def teach(self, language):
print("教:", language)
h1 = Human()
h1.say('今天天氣真好!')
h1.walk(5)
s1 = Student()
s1.walk(4)
s1.say("走的有點累")
s1.study('python')
t1 = Teacher()
t1.teach("面向對象")
t1.walk(6)
t1.say('晚上吃點啥好!')
```
繼承說明:
Python3任何類都直接或間接的繼承自object類
object類是一切類的超類
類的__base__屬性
__base__屬性用來記錄此類的基類
檢視全部python3内建類的繼承關系的方法:
>>> help(__builtins__)
思考:
list 類裡隻有append向末尾追加資料的方法,但沒有向清單頭部
添加元素的方法,試想能否為例表在不改變原有功能的基礎上添加
一個insert_head(n) 方法來實作向頭部插入資料?
即:
class MyList(list):
def insert_head(self, n):
...
myl = MyList(range(3, 6))
print(myl) # [3, 4, 5]
myl.insert_head(2)
print(myl) # [2, 3, 4, 5]
myl.append(6)
print(myl) # [2, 3, 4, 5, 6]
覆寫 override
什麼是覆寫
覆寫是指在有繼承關系的類中,子類中實作了與基類同名的方法,在
子類的執行個體調用該方法時,實際調用的是子類中的覆寫版本,這種現象
叫覆寫
作用:
實作和父類同名,但功能不同的方法
示例見:
```
class A:
def work(self):
print("A.work被調用")
class B(A):
def work(self):
'''此方法會覆寫父類的work方法'''
print("B.work被調用!!!!")
pass
b = B()
b.work() # 請問調用誰? B.work被調用
a = A()
a.work() # 請問調用誰?
```
提出問題
問題:
當覆寫發生時,子類對象能否調用父類中的方法?
子類對象顯式調用父類方法的方式:
基類名.方法名(執行個體, 實際調用傳參, ...)
super 函數:
super(cls, obj) 傳回綁定超類的執行個體(要求obj必須為cls類型
的執行個體)
super() 傳回綁定超類的執行個體,等同于:
super(__class__, 執行個體方法的第一個參數),
必須在方法内調用
作用:
借助super() 傳回的執行個體間接調用其父類的覆寫方法
顯式調用基類的初始化方法:
當子類中實作了__init__ 執行個體方法時,基類的初始化方法并不會
被調用.如何顯式調用父類的初始化方法?
示例見:
```
class Human(object):
def __init__(self, n, a):
self.name = n
self.age = a
print("Human.__init__被調用", n, a)
def show_info(self):
print("姓名:", self.name)
print("年齡:", self.age)
class Student(Human):
def __init__(self, n, a, s):
super().__init__(n, a)
print("Student.__init__(", n, a, s, ')')
self.score = s
def show_info(self):
super().show_info()
print("成績:", self.score)
s1 = Student('李四', 25, 100)
s1.show_info()
# print(dir(s1))
# h1 = Human('小張', 20) # 請問是否會調用__init__方法?
# h1.show_info()
```
用于類的函數:
issubclass(cls, class_or_tuple) 判斷一個類是否繼承自其
它的類,如果此類cls是class或tuple中的一個類的派生子
類則傳回True, 否則傳回False
示列:
class A:
pass
class B(A):
pass
class C(B):
pass
issubclass(C, B) # True
issubclass(B, C) # False
issubclass(C, A) # True
issubclass(B, (int, float, A)) # True
issubclass(bool, int) # True
練習(easy):
寫一個類Bicycle類(自行車類), 有run方法,調用時顯示騎行裡程
class Bicycle:
def run(self, km):
print("自行車騎行了", km, '公裡')
再寫一個類EBicycle(電動自行車類), 在Bicycle類的基礎上添加
電池電量volume屬性,
有兩個方法:
1. fill_charge(vol) 用來充電,vol為電量(度)
2. run(km) 方法每騎行10km 消耗電量1度,同時顯示目前
電量,當電量耗盡時,則調用Bicycle的run方法(人力騎行)
class EBicycle(Bicycle):
... # 此處自己實作,邏輯要符合現實
b = EBicycle(5) # 新買的電動車内有5度電
b.run(10) # 電動騎行了10公裡,還剩4度電
b.run(100) # 電動騎行了40公裡,還剩0度電,人力騎行60km
b.fill_charge(10) # 電動自行車充電10度
b.run(50) # 電動騎行了50公裡,還剩5度電