多繼承
獅虎獸, 不知道你有沒有聽說過? 獅虎獸,是雄獅(Panthera leo)與雌虎(Panthera tigris)雜交后的產(chǎn)物,是屬于貓科豹屬的一員.
用程序模擬一下獅虎獸.
class Animal(object):
def __init__(self):
print("init Animal")
class Tiger(Animal):
def __init__(self):
print("init Tiger")
Animal.__init__(self)
class Lion(Animal):
def __init__(self):
print("init Lion")
Animal.__init__(Lion)
class LionTiger(Lion, Tiger):
def __init__(self):
print("init LionTiger")
Lion.__init__(self)
Tiger.__init__(self)
LionTiger()
print(LionTiger.__mro__) # 類初始化的順序表
# 運(yùn)行結(jié)果:
# init LionTiger
# init Lion
# init Animal
# init Tiger
# init Animal
# (<class '__main__.LionTiger'>, <class '__main__.Lion'>, <class '__main__.Tiger'>, <class '__main__.Animal'>, <class 'object'>)
當(dāng)子類有多個(gè)父類 ( Lion 和 Tiger ), 并且父類又有一個(gè)共同的父類 ( Animal ) 時(shí), 使用父類名. 父類方法 ( Lion.__init__(self) ) 強(qiáng)制調(diào)用的方式父類的父類 ( Animal ) 會被多次初始化. 怎么解決這個(gè)問題? 我們發(fā)現(xiàn)如果按照LionTiger.__mro__ 屬性值的順序去初始化, 父類的父類 ( Animal ) 只會被初始化一次. 那么怎么使類按照這個(gè)順序取初始化呢?
super() 調(diào)用
class Animal(object):
def __init__(self):
print("init Animal")
class Tiger(Animal):
def __init__(self):
print("init Tiger")
super().__init__()
class Lion(Animal):
def __init__(self):
print("init Lion")
super().__init__()
class LionTiger(Lion, Tiger):
def __init__(self):
print("init LionTiger")
super().__init__()
LionTiger()
print(LionTiger.__mro__) # 類初始化的順序表
# 運(yùn)行結(jié)果:
# init LionTiger
# init Lion
# init Tiger
# init Animal
# (<class '__main__.LionTiger'>, <class '__main__.Lion'>, <class '__main__.Tiger'>, <class '__main__.Animal'>, <class 'object'>)
通過super() 調(diào)用父類可以按照__mro__的順序初始化父類
方法
實(shí)例方法
class Test(object):
def func(self):
print("func")
test = Test()
Test.func(test)
test.func()
print("*" * 30)
print(Test.__dict__)
print(test.__dict__)
# 運(yùn)行結(jié)果
# func
# func
# ******************************
# {'__module__': '__main__', 'func': <function Test.func at 0x0000022CF9BE89D8>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}
# {}
通過運(yùn)行結(jié)果以及__dict__屬性可以看出 類對象以及 實(shí)例對象都可以調(diào)用實(shí)例方法, 但是不建議使用類對象調(diào)用實(shí)例方法. 同時(shí) 類對象的__dict__ 有 'func': <function Test.func at 0x0000022CF9BE89D8> , 而 實(shí)例對象的__dict__ 為 {} , 所以可以得出 實(shí)例方法是存儲在類對象的內(nèi)存中
類方法
class Test(object):
@classmethod
def func(cls):
print("func")
test = Test()
Test.func()
test.func()
print("*" * 30)
print(Test.__dict__)
print(test.__dict__)
# 運(yùn)行結(jié)果
# func
# func
# ******************************
# {'__module__': '__main__', 'func': <classmethod object at 0x000001BABFD66940>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}
# {}
通過運(yùn)行結(jié)果以及__dict__屬性可以看出 類對象以及 實(shí)例對象都可以調(diào)用類方法, 但是不建議使用 實(shí)例對象調(diào)用 類方法. 同時(shí) 類對象的__dict__ 有 'func': <function Test.func at 0x000001BABFD66940> , 而 實(shí)例對象的__dict__ 為 {} , 所以可以得出 類方法是存儲在類對象的內(nèi)存中
靜態(tài)方法
class Test(object):
@staticmethod
def func():
print("func")
test = Test()
Test.func()
test.func()
print("*" * 30)
print(Test.__dict__)
print(test.__dict__)
# 運(yùn)行結(jié)果
# func
# func
# ******************************
# {'__module__': '__main__', 'func': <staticmethod object at 0x00000200193E6940>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}
# {}
通過運(yùn)行結(jié)果以及__dict__屬性可以看出 類對象以及 實(shí)例對象都可以調(diào)用靜態(tài)方法, 但是不建議使用 實(shí)例對象調(diào)用 靜態(tài)方法. 同時(shí) 類對象的__dict__ 有 'func': <function Test.func at 0x000001BABFD66940> , 而 實(shí)例對象的__dict__ 為 {} , 所以可以得出 靜態(tài)方法是存儲在類對象的內(nèi)存中
私有方法
class Test(object):
def __func(self):
print("func")
def test(self):
self.__func()
Test.__func(self)
test = Test()
test.test()
print("*" * 30)
print(Test.__dict__)
print(test.__dict__)
# 運(yùn)行結(jié)果
# func
# func
# ******************************
# {'__module__': '__main__', '_Test__func': <function Test.__func at 0x00000240FEC989D8>, 'test': <function Test.test at 0x00000240FEC98A60>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}
# {}
私有方法不能在類外訪問 ( 正常來說 ), 通過 類對象以及 實(shí)例對象都可以在類內(nèi)訪問私有方法. 同時(shí) 類對象的__dict__ 有 'func': <function Test.func at 0x000001BABFD66940> , 而 實(shí)例對象的__dict__ 為 {} , 所以可以得出 私有方法是存儲在類對象的內(nèi)存中
屬性
那么類屬性以及實(shí)例屬性存儲在哪里?
class Test(object):
class_property = "class_property"
def __init__(self):
self.property = "property"
test = Test()
print(Test.class_property)
print(test.class_property)
print("*" * 30)
# print(Test.property)
print(test.property)
print("*" * 30)
print(Test.__dict__)
print(test.__dict__)
# 運(yùn)行結(jié)果
# class_property
# class_property
# ******************************
# property
# ******************************
# {'__module__': '__main__', 'class_property': 'class_property', '__init__': <function Test.__init__ at 0x00000286E96A8A60>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}
# {'property': 'property'}
通過運(yùn)行結(jié)果以及__dict__屬性可以看出 類對象以及 實(shí)例對象都可以調(diào)用類屬性, 但是不建議使用 實(shí)例對象調(diào)用類屬性. 同時(shí) 類對象的__dict__ 有'class_property': 'class_property' 說明類屬性存儲在類對象的內(nèi)存中, 實(shí)例對象的__dict__ 有 'property': 'property' 說明實(shí)例屬性存儲在實(shí)例對象的內(nèi)存中
小結(jié):
- 公有方法:實(shí)例方法 / 類方法 / 靜態(tài)方法, 類對象和實(shí)例對象在類內(nèi)類外都可以調(diào)用.
- 私有方法: 類對象和實(shí)例對象在類內(nèi)都可以調(diào)用.
- 方法: 公有方法 / 私有方法 , 都存儲在類對象的內(nèi)存中.
- 類屬性: 類對象和實(shí)例對象在類內(nèi)類外都可以調(diào)用, 類屬性存儲在類對象的內(nèi)存中.
- 實(shí)例屬性: 類對象不能調(diào)用, 實(shí)例對象在類內(nèi)可以調(diào)用, 實(shí)例屬性存儲在實(shí)例對象的內(nèi)存中.
- 私有類屬性: 類對象和實(shí)例對象在類內(nèi)都可以調(diào)用, 私有類屬性存儲在類對象的內(nèi)存中.
- 私有實(shí)例屬性:類對象不能調(diào)用, 實(shí)例對象在類內(nèi)可以調(diào)用, 私有實(shí)例屬性存儲在實(shí)例對象的內(nèi)存中.
常量
其它語言中有常量,比如 Java中 使用static final 定義一個(gè)靜態(tài)常量, Python中的常量怎么定義?
class Test(object):
def __init__(self):
self.__property = "property"
def get_property(self):
return self.__property
test = Test()
print(test.get_property())
# 運(yùn)行結(jié)果
# property
通過私有屬性構(gòu)造 Python中的常量, 和其它語言中的不一樣?再來
class Test(object):
def __init__(self):
self.__property = "property"
@property
def get_property(self):
return self.__property
test = Test()
print(test.get_property)
# 運(yùn)行結(jié)果
# property
這樣是不是有點(diǎn)感覺了?再來
class Test(object):
def __init__(self):
self.__PI = 3.1415926
@property
def PI(self):
return self.__PI
test = Test()
print(test.PI)
# 運(yùn)行結(jié)果
# 3.1415926
是不是很有感覺了?那么property[1] 能干嘛?
class Test(object):
def __init__(self):
self.__PI = 3.1415926
@property
def PI(self):
return self.__PI
@PI.setter
def PI(self, arg):
self.__PI = arg
@PI.deleter
def PI(self):
del self.__PI
test = Test()
print(test.PI)
test.PI = 3.14
print(test.PI)
del test.PI
# print(test.PI)
# 運(yùn)行結(jié)果
# 3.1415926
# 3.14
魔法屬性/魔法方法[2]/[3]
__new__(cls[, ...]) / __init__(self[, ...]) / __str__(self) / __del__(self)
class Animal(object):
instance = None
is_init = False
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object().__new__(cls)
print("cls.instance = %s" % cls.instance)
return cls.instance
def __init__(self, name):
if not Animal.is_init:
self.name = name
Animal.is_init = True
print("self.name = %s" % self.name)
def __str__(self):
return "__str__ 被調(diào)用"
def __del__(self):
print("[%s] 被刪除" % self)
animal = Animal("DragonFang")
animal2 = Animal("fang")
# 運(yùn)行結(jié)果:
# cls.instance = __str__ 被調(diào)用
# self.name = DragonFang
# cls.instance = __str__ 被調(diào)用
# self.name = DragonFang
# [__str__ 被調(diào)用] 被刪除
通過Python 單例模式觀察 __new__(cls[, ...]) / __init__(self[, ...]) / __str__(self) / __del__(self) 魔法方法的調(diào)用過程以及作用
- __new__(cls[, ...]) : 實(shí)例對象創(chuàng)建時(shí)被調(diào)用,可以控制實(shí)例對象的創(chuàng)建
- __init__(self[, ...]) : 實(shí)例對象創(chuàng)建后,初始化時(shí)被調(diào)用,可以控制實(shí)例對象的初始化
- __str__(self) : 打印對象時(shí)被調(diào)用, 可以返回對象的描述信息
- __del__(self) : 對象被銷毀時(shí)調(diào)用, 可以做一些關(guān)閉操作
__module__ 和 __class__
import threading
my_thread = threading.Thread()
print(my_thread.__module__)
print(my_thread.__class__)
# 運(yùn)行結(jié)果
# threading 表示當(dāng)前操作的對象來自哪一個(gè)模塊
# <class 'threading.Thread'> 表示當(dāng)前操作對象屬于哪一個(gè)類
__dict__ 類或?qū)ο笾械乃袑傩?/h5>
上面已經(jīng)使用過了這里不做贅述.
魔法屬性或 方法就說到這里, 有興趣的可以通過角注了解其它的魔法屬性 或者方法.
with
with open("DragonFang.txt", "w") as f:
f.write("DragonFang")
這種操作文件的方式很簡潔, 那么with 內(nèi)部做了什么?討論這個(gè)問題之前, 先要明白另一個(gè)概念上下文管理器
上下文管理器
上下文管理器, 對當(dāng)前的環(huán)境進(jìn)行一定的自動(dòng)處理, 如文件的關(guān)閉操作.
作用: 使用上下文管理器可以避免一些重復(fù)的 / 瑣碎的操作.
怎么自定義個(gè)上下文管理器? 包含 __enter__() 和 __exit__()方法的類,就是一個(gè)上下文管理器.
自定義上下文管理器
class OpenDB(object):
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with OpenDB() as db:
pass
通過簡單的骨架,可以找到一個(gè)上下文管理器的必備方法, 完善一下
from pymysql import connect
class OpenDB(object):
def __init__(self, dbname):
print("__init__")
self.conn_sql = connect(host="localhost", port=3306, user="root", password="mysql", database=dbname,
charset="utf8")
self.cursor_sql = self.conn_sql.cursor()
def __enter__(self):
print("__enter__")
return self.cursor_sql
def __exit__(self, exc_type, exc_val, exc_tb):
print("__exit__")
self.conn_sql.commit()
self.cursor_sql.close()
self.conn_sql.close()
with OpenDB("fang") as db:
rows = db.execute("select * from emp;")
result_data = db.fetchall()
print("有%s條數(shù)據(jù)" % rows)
print("內(nèi)容如下")
for tmp in result_data:
print(tmp)
# 運(yùn)行結(jié)果:
# __init__
# __enter__
# 有10條數(shù)據(jù)
# 內(nèi)容如下
# (0, 'name0', 'm')
# (1, 'name1', 'w')
# (2, 'name2', 'w')
# (3, 'name3', 'm')
# (4, 'name4', 'w')
# (5, 'name5', 'w')
# (6, 'name6', 'm')
# (7, 'name7', 'm')
# (8, 'name8', 'w')
# (9, 'name9', 'w')
# __exit__
通過自定義上下文管理器, 可以得知 with 后跟的是一個(gè)對象, 通過init 可以進(jìn)行一些初始化操作 ( 比如連接數(shù)據(jù)庫 / 得到cursor 對象) , 通過 as 得到 __enter__ 方法返回的對象, 進(jìn)行一下操作 ( 比如查詢數(shù)據(jù)庫) , 執(zhí)行結(jié)束自動(dòng)調(diào)用__exit__方法, 可以將一些瑣碎的操作放到方法體中 ( 比如關(guān)閉數(shù)據(jù)庫連接)
到此結(jié)?DragonFangQy 2018.5.23