我對某些Python類中的多重繼承設計有些疑問。此Python代碼中多重繼承的最佳實踐
問題是我想擴展ttk按鈕。這是我最初的建議(我省略了所有的源代碼在縮短的方法,除了初始化方法):
import tkinter as tk
import tkinter.ttk as ttk
class ImgButton(ttk.Button):
"""
This has all the behaviour for a button which has an image
"""
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
self._img = kw.get('image')
def change_color(self, __=None):
"""
Changes the color of this widget randomly
:param __: the event, which is no needed
"""
pass
def get_style_name(self):
"""
Returns the specific style name applied for this widget
:return: the style name as a string
"""
pass
def set_background_color(self, color):
"""
Sets this widget's background color to that received as parameter
:param color: the color to be set
"""
pass
def get_background_color(self):
"""
Returns a string representing the background color of the widget
:return: the color of the widget
"""
pass
def change_highlight_style(self, __=None):
"""
Applies the highlight style for a color
:param __: the event, which is no needed
"""
pass
但後來我意識到,我也希望這個ImgButton的一個子類,如下所示:
import tkinter as tk
import tkinter.ttk as ttk
class MyButton(ImgButton):
"""
ImgButton with specifical purpose
"""
IMG_NAME = 'filename{}.jpg'
IMAGES_DIR = os.path.sep + os.path.sep.join(['home', 'user', 'myProjects', 'myProject', 'resources', 'images'])
UNKNOWN_IMG = os.path.sep.join([IMAGES_DIR, IMG_NAME.format(0)])
IMAGES = (lambda IMAGES_DIR=IMAGES_DIR, IMG_NAME=IMG_NAME: [os.path.sep.join([IMAGES_DIR, IMG_NAME.format(face)]) for face in [1,2,3,4,5] ])()
def change_image(self, __=None):
"""
Changes randomly the image in this MyButton
:param __: the event, which is no needed
"""
pass
def __init__(self, master=None, value=None, **kw):
# Default image when hidden or without value
current_img = PhotoImage(file=MyButton.UNKNOWN_IMG)
super().__init__(master, image=current_img, **kw)
if not value:
pass
elif not isinstance(value, (int, Die)):
pass
elif isinstance(value, MyValue):
self.myValue = value
elif isinstance(value, int):
self.myValue = MyValue(value)
else:
raise ValueError()
self.set_background_color('green')
self.bind('<Button-1>', self.change_image, add=True)
def select(self):
"""
Highlights this button as selected and changes its internal state
"""
pass
def toggleImage(self):
"""
Changes the image in this specific button for the next allowed for MyButton
"""
pass
繼承感覺自然是正確的。問題出現的時候,我也注意到ImgButton中的大多數方法都可以重用於我將來可能創建的任何Widget。
所以我想製作:
class MyWidget(ttk.Widget):
爲把它與色彩幫助小部件,然後我需要ImgButton既從進myWidget和ttk.Button繼承所有方法:
class ImgButton(ttk.Button, MyWidget): ???
or
class ImgButton(MyWidget, ttk.Button): ???
編輯:另外我希望我的目標是爲loggable,所以我做了這個類:
class Loggable(object):
def __init__(self) -> None:
super().__init__()
self.__logger = None
self.__logger = self.get_logger()
self.debug = self.get_logger().debug
self.error = self.get_logger().error
self.critical = self.get_logger().critical
self.info = self.get_logger().info
self.warn = self.get_logger().warning
def get_logger(self):
if not self.__logger:
self.__logger = logging.getLogger(self.get_class())
return self.__logger
def get_class(self):
return self.__class__.__name__
所以現在:
class ImgButton(Loggable, ttk.Button, MyWidget): ???
or
class ImgButton(Loggable, MyWidget, ttk.Button): ???
or
class ImgButton(MyWidget, Loggable, ttk.Button): ???
# ... this could go on ...
我來自Java和我不知道多重繼承的最佳做法。我不知道應該如何按照最佳順序排序父母,或者對設計這種多重繼承有用。
我已經搜索了關於該主題,發現了很多解釋MRO的資源,但沒有提到如何正確設計多重繼承。我不知道,即使我的設計是錯誤的,但我認爲這感覺很自然。
我將不勝感激的一些建議,以及對這個主題的一些鏈接或資源以及。
非常感謝。
我已經想到用Tkinter的同樣的危險,但對做一個新的視覺控制感覺自然延伸現有的。我知道mixins,我沒有理由反對使用它們。我認爲現在我會使用繼承方法,並將父類Loggable和ttk.Widget創建爲MyWidget子類。 ImgButton將與父母MyWidget和ttk.Button一起成爲孩子。每個級別都有兩位父母,但進一步下去就不再需要多重繼承。 – madtyn