目錄
1. 類的繼承
1.1 面向對象的好處
1.2 示例
1.3 super()方法
1.4 類和實例的關系
1.4.1 isinstance ()函數
1.4.2 示例:判斷類與實例的關系
2.多態
2.1 Python中的多態
2.2 Python中的多態- 注意
2.3 多態性的好處
3. 經典類和新式類
3.1. python2和python3的類型區別
3.2 類的多重繼承
3.2.1 類可以多重繼承
3.2.2 經典類和新式類的繼承順序
3.2.3 經典類與新式類的繼承繼承原理
3.2.4 C3算法
4. 靜態方法,類方法,實例方法
4.1 實例方法
4.2 類方法 @classmethod
4.3 靜態方法 @staticmethod
4.4 各種方法的區別
5. python中的下劃線
5.1 以單下劃線開頭的
5.1.1 在類裡面
5.1.2 在模塊裡面
5.2 以雙下劃線開頭的
5.2.1 在類裡面
5.2.2 在模塊裡面
5.3 以雙下劃線開頭和雙下劃線結尾的
6.python中常見的魔術方法
構造函數(__new__/__init__)
析構函數(__del__)
調用方法(__call__)
獲取數據(__getitem__)
刪除數據(__delitem__)
設置數據(__setitem__)
其他魔術方法
繼承完全可以理解成類之間的類型和子類型關系。 • 可以節省很多的代碼,不需要寫,直接使用 • 衍生出不同的子類,大部分代碼一樣,部分代碼不一樣
############################################
class Animal():
species = "animal"
count = 0
def __init__(self):
self.name = "animal"
Animal.count += 1
print("初始化animal...")
def breath(self):
print("i can breath")
def eat(self):
print("i can eat")
class Person(Animal):
# 重寫父類的屬性 species
species = "Person"
animal1 = Animal()
print(animal1.count)
# 初始化自己沒有init,會執行父類的__init__
p = Person()
print(p.species, p.count)
print(p.name)
Person類沒有__init__,所以會調用父類Animal的__init__ 因為Animal的__init__有name屬性,所以不會報錯 print(d.name) 而Dog類自己有__init__,就不會再調用父類的__init__ 但是Dog類的__init__裡面沒有name屬性,所以會報錯class Dog(Animal):
def __init__(self):
print("i am dog")
# 重寫父類eat方法
def eat(self):
print("dog is eating...")
d = Dog()
# # person類沒有init,會調用父類init
# # 父類init有name屬性,所以不會報錯
# print(p.name)
# # dog類自己有init,不會再調用父類init
# # dog類init裡面沒有name屬性,會報錯
# print(d.name)
d.eat()
############################################
如果一個子類的__init__方法想使用父類的__init__中的屬性,這個時候可以使用super()方法
但是super()方法一般寫在最前面,因為如果寫在後面的話父類的__init__方法可能會覆蓋子類的
一些屬性。
class Pig(Animal):
count = 0 # 重寫父類屬性
def __init__(self):
# 調用父類的init
super().__init__()
# super().eat()
self.name = "pig"
Pig.count += 1
print("初始化pig")
print('*' * 20)
pig1 = Pig()
print(pig1.count, animal1.count)
********************
初始化animal...
初始化pig
1 3
############################################
isinstance() 函數來判斷一個對象是否是一個已知的類型,類似 type()。
isinstance() 與 type() 區別:
type() 不會認為子類是一種父類類型,不考慮繼承關系。
isinstance() 會認為子類是一種父類類型,考慮繼承關系。
如果要判斷兩個類型是否相同推薦使用 isinstance()。
語法
以下是 isinstance() 方法的語法:
isinstance(object, classinfo)
############################################
# 類與實例的關系
print('*'*20)
print(isinstance(pig1, Pig), isinstance(pig1, Animal))
print(type(pig1))
a = str(10)
# 所謂的工廠函數其實本質就是類
# ’ABC‘.lower(),就是類調用lower方法
print(type(a), str.lower("ABC"), "ABC".lower())
********************
True True
<class '__main__.Pig'>
<class 'str'> abc abc
############################################
class zhifubao():
def pay(self):
print("this is zhifubao pay")
class weixin():
def pay(self):
print("this is weixin pay")
class bank():
def pay(self):
print("this is bank pay")
z = zhifubao()
w = weixin()
b = bank()
def pay(obj): # 接口的多種形態,接口的重用
obj.pay()
pay(z)
pay(w)
pay(b)
E:\python\python3.9.1\python.exe E:/tlbb/2022-05-28-python面向對象/05.多態.py
this is zhifubao pay
this is weixin pay
this is bank pay
Process finished with exit code 0
############################################
python3裡面默認所有類都是繼承的object,所以python3都是新式類
# 經典類 通過type查看到的實例都是 instance
# 類和實例只能通過.__class__屬性
# 新式類 通過type查看到的實例類型就是類名
<class '__main__.A'>
# __main__代表當前模塊
# 代表當前模塊下的A類
[[email protected] lianxi]# python2
Python 2.7.5 (default, Oct 14 2020, 14:45:30)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class A: pass
...
>>> a = A()
>>> type(a)
<type 'instance'>
>>> a.__class__
<class __main__.A at 0x7f2a02719258>
>>>
─────────────────────────────────────────────────────────────────
[[email protected] ~]# python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A: pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class '__main__.A'>
>>>
############################################
class A():
def test(self):
print("from A")
class B(A):
def test(self):
print("from B")
class C(A):
def test(self):
print("from C")
class D(B):
def test(self):
print("from D")
class E(C):
def test(self):
print("from E")
class F(D, E):
def test(self):
print("from F")
f = F()
f.test()
經典類: F--D--B--A--E--C
新式類: F--D--B--E--C--A
############################################
############################################
# c3算法 # 首先將自身類加入本序列,然後再對繼承序列的元素依次判斷 # 若某個元素不在其他序列或者他是所有繼承序列的第一個,那麼就把這個元素提取到本序列
############################################
class A:
name = "class A"
def __init__(self): # 自動調用
self.country = "china"
# 實例方法,第一參數代表實例本身
def normal_method(self, name):
# 方法的裡面,即可以訪問類屬性,又可以訪問實例屬性
print("normal:")
print(self.name, name)
# 類方法 cls代表類
@classmethod # 裝飾器 被裝飾器裝飾過的方法稱為類方法
def class_method(cls, name):
# 類方法可以類屬性
print("classmethod")
print(cls, cls.name)
@staticmethod # 靜態方法
def static_method(name):
# 靜態方法可以通過類名去訪問類屬性
print("static_method", name, A.name)
a1 = A()
# 靜態方法,實例方法,類方法都能通過實例去調用
a1.normal_method("a1")
a1.class_method("a1")
a1.static_method("a1")
# 也可以通過類去調用
# 類調用實例方法需要傳入實例參數
A.normal_method(a1, "A")
A.class_method("A")
A.static_method("A")
############################################
實例方法,第一參數代表實例本身
在實例方法裡面即可以訪問類屬性,又可以訪問實例屬性
可以通過self訪問實例屬性 # 實例方法,第一參數代表實例本身
def normal_method(self, name):
# 方法的裡面,即可以訪問類屬性,又可以訪問實例屬性
print("normal:")
print(self.name, name)
############################################
@classmethod --> 裝飾器
被裝飾器裝飾過的方法稱為類方法
類方法可以訪問類屬性
可以通過cls訪問類屬性(希望取的值不受實例影響時使用) # 類方法 cls代表類
@classmethod # 裝飾器 被裝飾器裝飾過的方法稱為類方法
def class_method(cls, name):
# 類方法可以類屬性
print("classmethod")
print(cls, cls.name)
############################################
靜態方法可以通過類名去訪問類屬性
@staticmethod # 靜態方法
def static_method(name):
# 靜態方法可以通過類名去訪問類屬性
print("static_method", name, A.name)
############################################
############################################
############################################
############################################
不能模糊導入模塊 即 不能用“ from xxx import *“導入包/模塊。
• 名稱(具體為一個方法名)前雙下劃線(“__“)的用法並不是一種慣例,對解釋器來說它有特定 的意義。Python中的這種用法是為了避免與子類定義的名稱沖突。Python文檔指出,“__spam” 這種形式(至少兩個前導下劃線,最多一個後續下劃線)的任何標識符將會被 “_classname__spam”這種形式原文取代,在這裡“classname”是去掉前導下劃線的當前類 名。class P:
"""
this is P
"""
_min = 1 # 保護屬性
__max = 10 # 私有屬性
def __init__(self):
self.name = "sc"
self.age = 4
self.__desc = "it"
def __make(self):
print("這是一個私有方法")
print(self.__desc)
def _protectmake(self):
print("這是一個保護方法")
def show(self):
print(self.__max, self.__desc)
class Child(P):
def show(self):
print(self.__max)
#
#
p = P()
c = Child()
# 保護屬性和普通屬性沒有區別
print(c._min, p._min, Child._min, P._min)
# 訪問私有屬性 子類訪問不到私有成員
# print(c.__make)
# 類對象也不能訪問私有成員
# print(p.__max)
# p.__make()
# 想訪問__make()要加上類名 p._P__make()
# 私有成員只能在類的內部訪問
p.show()
print('*' * 20)
print(c._min)
# print(dir(p))
# '_P__desc', '_P__make', '_P__max',
# python中的私有都是偽私有,實際其實就是將雙下劃線開頭的標識符
# 改了一個名字存儲 _類名__標識符
E:\python\python3.9.1\python.exe E:/tlbb/2022-05-28-python面向對象/08.python中的下劃線.py
1 1 1 1
10 it
********************
1
Process finished with exit code 0
############################################
# 常見的以雙下劃線開頭和以雙下劃線結尾的特殊變量
# __dict__ # 查看命名空間
print(P.__dict__)
print(p.__dict__)
print(P.__name__)
# __class__ 查看對象屬於哪個類
print(p.__class__)
# __module__ 查看所在哪個模塊
print(P.__module__)
#
# __doc__文檔注釋, 類,函數的文檔注釋都會放到 __doc__裡面
print(P.__doc__)
E:\python\python3.9.1\python.exe E:/tlbb/2022-05-28-python面向對象/08.python中的下劃線.py
{'__module__': '__main__', '__doc__': '\n this is P\n ', '_min': 1, '_P__max': 10, '__init__': <function P.__init__ at 0x0000021A1689DC10>, '_P__make': <function P.__make at 0x0000021A168E1940>, '_protectmake': <function P._protectmake at 0x0000021A168E19D0>, 'show': <function P.show at 0x0000021A168E1A60>, '__dict__': <attribute '__dict__' of 'P' objects>, '__weakref__': <attribute '__weakref__' of 'P' objects>}
{'name': 'sc', 'age': 4, '_P__desc': 'it'}
P
<class '__main__.P'>
__main__
this is P
Process finished with exit code 0
############################################
魔術方法 :一般以雙下劃線開頭和雙下劃線結尾
而且是有特殊含義的方法,一般不需要手動去調用
它會在某種特定場景下自動執行
class A:
def __del__(self):
print("this is A.del")
a1 = A()
del a1
print("xxxxxx")
class A:
def __call__(self, name):
print(f"i am A.__call__,name is {name}")
a1 = A()
a1("sc")
def func1():
pass
print(dir(func1))
自定義異常類
class NotIsIntException(Exception):
def __str__(self):
return 'NotIsIntException類型不是整數'
n = input('請輸入一個整數')
try:
if n.isdigit():
print(n)
else:
raise NotIsIntException
except NotIsIntException as ni:
print(ni)
############################################
class A:
def __init__(self):
self.data = {}
def __getitem__(self, key):
print("get data")
return self.data.get(key, 0)
def __setitem__(self, key, value):
print("set data:", key, value)
self.data[key] = value
def __delitem__(self, key):
print("delete data")
del(self.data[key])
a1 = A()
print(a1["key1"])
a1["key1"] = "xxxxxxx"
del a1["key1"]
############################################
class B:
def __init__(self, num):
self.num = num
def __add__(self, x):
print("this is add")
return self.num + x
a = B(4)
print(a + 6)