Python?動(dòng)態(tài)創(chuàng)建一個(gè)類的示例代碼
Python 動(dòng)態(tài)創(chuàng)建一個(gè)類的示例代碼:
# 動(dòng)態(tài)創(chuàng)建類
# class_body 里是類里邊的函數(shù),可以寫在文件里,從文件中讀取
class_body = """
def running_function(self):
print(self.name)
print("running function")
def set_name(self,name):
self.name = name
"""
class_dict = {}
# 加載類方法到class_dict里
exec(class_body,globals(),class_dict)
# 把class_dict中的方法加載到類里邊
Customer = type("Customer",(object,),class_dict)
# 實(shí)例化類,調(diào)用類方法
c = Customer()
c.set_name("12")
c.running_function()補(bǔ)充:python動(dòng)態(tài)實(shí)例化
python動(dòng)態(tài)實(shí)例化
前言
最近在查一個(gè)服務(wù)的問題時(shí),看到有一段代碼if .. elif ... 寫了近百行,類似
if command == "xxx":
obj = CommandX()
obj.run()
# ...
elif command == "yyy":
obj = CommandY()
obj.run()
# ...
elif command == "zzz":
obj = CommandZ()
obj.run()
# ...
# ...翻了下git記錄,最開始其實(shí)只有兩三個(gè)條件判斷,后來(lái)command越加越多,就這么延續(xù)下來(lái)了。
代碼邏輯其實(shí)沒什么問題,也很簡(jiǎn)單明了,就是看起來(lái)有點(diǎn)丑,而且我還開了比較高的桌面縮放,導(dǎo)致一屏幕幾乎都是這段if ... elif
看來(lái)看去越發(fā)覺得丑,先寫個(gè)demo看看能不能跑通代碼。
方式1, 字典映射
如果需要判斷的條件比較少,用字典做映射還是挺方便的,但如果條件多,看起來(lái)還是挺丑的。
from abc import ABC, abstractmethod
class AbstractCommand(ABC):
@abstractmethod
def run(self):
pass
class CommandA(AbstractCommand):
def run(self):
return "this is command A"
class CommandB(AbstractCommand):
def run(self):
return "this is command B"
class CommandC(AbstractCommand):
def run(self):
return "this is command C"
class CommandFactory:
@staticmethod
def create_command(command_type: str) -> AbstractCommand:
command_mapping = {
"cmda": CommandA,
"cmdb": CommandB,
"cmdc": CommandC
}
cls = command_mapping.get(command_type.lower())
if not cls:
raise ValueError(f"Unknown command type: {command_type}")
return cls()
if __name__ == "__main__":
cmd = CommandFactory.create_command("cmda")
assert cmd.run() == "this is command A"
cmd = CommandFactory.create_command("cmdb")
assert cmd.run() == "this is command B"
cmd = CommandFactory.create_command("cmdc")
assert cmd.run() == "this is command CD" # should be exception
cmd = CommandFactory.create_command("cmdd") # should be exception
assert cmd.run() == "this is command D"方式2, __init_subclass__
《流暢的Python(第2版)》的最后一章提到了這個(gè)__init__subclass__,根據(jù)python官方文檔:
當(dāng)所在類派生子類時(shí)此方法就會(huì)被調(diào)用。cls 將指向新的子類。如果定義為一個(gè)普通實(shí)例方法,此方法將被隱式地轉(zhuǎn)換為類方法。傳給一個(gè)新類的關(guān)鍵字參數(shù)會(huì)被傳給上級(jí)類的
__init_subclass__。 為了與其他使用__init_subclass__的類兼容,應(yīng)當(dāng)去掉需要的關(guān)鍵字參數(shù)再將其他參數(shù)傳給基類。
借助這個(gè)機(jī)制,可以在實(shí)現(xiàn)抽象基類時(shí)自動(dòng)注冊(cè)子類,避免手動(dòng)維護(hù)注冊(cè)表。
from abc import ABCMeta, abstractmethod
from threading import Lock
from collections import UserDict
class ThreadSafeDict(UserDict):
"""線程安全的字典"""
def __init__(self):
super().__init__()
self._lock = Lock()
def __setitem__(self, key, item):
with self._lock:
super().__setitem__(key, item)
class Command(metaclass=ABCMeta):
registry = ThreadSafeDict()
def __init__(self):
pass
@abstractmethod
def run(self):
pass
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.registry[cls.__name__.lower()] = cls # 自動(dòng)注冊(cè)子類
# 子類定義即自動(dòng)注冊(cè)
class CommandA(Command):
def run(self):
return "this is command a!"
class CommandB(Command):
def run(self):
return "this is command b!"
class CommandC(Command):
def run(self):
return "this is command b!"
def create_command(command_type: str) -> Command:
"""工廠函數(shù)"""
cls = Command.registry.get(command_type.lower())
if not cls:
raise ValueError(f"Unknown command type: {command_type}")
return cls()
if __name__ == "__main__":
cmd = create_command("CommandA")
assert cmd.run() == "this is command a!"
cmd = create_command("CommandB")
assert cmd.run() == "this is command b!"
cmd = create_command("CommandC")
assert cmd.run() == "this is command cc!" # should be exception
cmd = create_command("CommandD")
assert cmd.run() == "this is command b!" # should be exception乍一看還是挺不錯(cuò)的,但是也有個(gè)缺點(diǎn),那就是如果各個(gè)類分散在不同模塊中,那么工廠函數(shù)所在的模塊就要寫一堆from xxx import ...
如果module和類命名比較規(guī)范,也可以這么動(dòng)態(tài)加載類
import importlib
def create_class(module_name, class_name):
module = importlib.import_module(module_name)
cls = getattr(module, class_name)
return cls()補(bǔ)充
自動(dòng)注冊(cè)類看起來(lái)炫,但是對(duì)代碼閱讀來(lái)說(shuō)不是很直觀。易讀還是美觀?這是一個(gè)問題。
到此這篇關(guān)于Python 動(dòng)態(tài)創(chuàng)建一個(gè)類的文章就介紹到這了,更多相關(guān)Python 動(dòng)態(tài)創(chuàng)建一個(gè)類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python-pymysql如何實(shí)現(xiàn)更新mysql表中任意字段數(shù)據(jù)
這篇文章主要介紹了python-pymysql如何實(shí)現(xiàn)更新mysql表中任意字段數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
Python使用窮舉法求兩個(gè)數(shù)的最大公約數(shù)問題
這篇文章主要介紹了Python使用窮舉法求兩個(gè)數(shù)的最大公約數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
基于Python實(shí)現(xiàn)加強(qiáng)版煙花
這篇文章主要為大家詳細(xì)介紹了如何利用Python制作一個(gè)加強(qiáng)版煙花景,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定幫助,需要的可以參考一下2022-02-02
pytest自動(dòng)化測(cè)試中的fixture的聲明和調(diào)用
這篇文章主要為大家介紹了pytest自動(dòng)化測(cè)試中的fixture的聲明和調(diào)用,文中含有詳細(xì)示例操作有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
python調(diào)用自定義函數(shù)的實(shí)例操作
在本文里我們給大家整理了關(guān)于python調(diào)用自定義函數(shù)的實(shí)例操作相關(guān)內(nèi)容,有此需要的朋友們可以學(xué)習(xí)參考下。2019-06-06
Python3實(shí)現(xiàn)的簡(jiǎn)單三級(jí)菜單功能示例
這篇文章主要介紹了Python3實(shí)現(xiàn)的簡(jiǎn)單三級(jí)菜單功能,涉及Python用戶交互以及針對(duì)json格式數(shù)據(jù)的遍歷、讀取、判斷等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
Python網(wǎng)絡(luò)爬蟲之Web網(wǎng)頁(yè)基礎(chǔ)
我們?cè)趯W(xué)習(xí)爬蟲之前,要先了解網(wǎng)頁(yè)的組成,只有我們了解其組成嗎,才可以方能百戰(zhàn)百勝,文章中有詳細(xì)的代碼示例,需要的朋友可以參考一下2023-04-04

