Python 3.x 此Python代码中多重继承的最佳实践
我对某些Python类中的多重继承设计有一些疑问 问题是我想扩展ttk按钮。这是我最初的建议(除了init方法之外,我省略了缩短方法中的所有源代码): 但后来我意识到我还需要这个ImgButton的一个子类,如下所示:Python 3.x 此Python代码中多重继承的最佳实践,python-3.x,tkinter,multiple-inheritance,ttk,method-resolution-order,Python 3.x,Tkinter,Multiple Inheritance,Ttk,Method Resolution Order,我对某些Python类中的多重继承设计有一些疑问 问题是我想扩展ttk按钮。这是我最初的建议(除了init方法之外,我省略了缩短方法中的所有源代码): 但后来我意识到我还需要这个ImgButton的一个子类,如下所示: import tkinter as tk import tkinter.ttk as ttk class MyButton(ImgButton): """ ImgButton with specifical purpose """ IMG_NA
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从MyWidget和ttk继承。按钮:
class ImgButton(ttk.Button, MyWidget): ???
or
class ImgButton(MyWidget, ttk.Button): ???
编辑:我也希望我的对象可以记录,所以我做了这个类:
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的资源,但没有找到关于如何正确设计多重继承的内容。我不知道我的设计是不是做错了,但我觉得感觉很自然
如果您能提供一些建议,以及关于这个主题的一些链接或资源,我将不胜感激
非常感谢。原则上,多重继承的使用增加了复杂性,所以除非我确定它的需要,否则我会避免它。从您的帖子中,您已经了解了super()和MRO的用法 一个常见的建议是在可能的情况下使用组合而不是多重继承 另一种方法是仅从一个可实例化父类生成子类,使用抽象类作为其他父类。也就是说,他们将方法添加到这个子类中,但从未自己实例化过。就像在Java中使用接口一样。这些抽象类也称为mixin,但它们的使用(或滥用)也有争议。看
至于你的tkinter代码,除了日志代码缩进,我看不出有什么问题。也许小部件可以有一个记录器,而不是从中继承。我认为tkinter的危险在于它错误地覆盖了数百种可用方法中的一种。这些天我一直在阅读有关多重继承的文章,我学到了很多东西。最后,我将我的资料来源、资源和参考资料链接起来 我的主要和最详细的资料来源是《流畅的python》,我发现这本书可以在网上免费阅读 这描述了方法解析顺序和多重继承的设计场景,以及确定的步骤:
class MyClass(MySuperClass, MyABC, MyMixin1, MyMixin2):
class Widget(BaseWidget, Pack, Grid, Place):
pass
就我而言:
class ImgButton(ttk.Button, MyWidget):
class MyClass(MySuperClass, MyABC, MyMixin1, MyMixin2):
class Widget(BaseWidget, Pack, Grid, Place):
pass
我认为Loggable应该是一个Mixin,因为它为一个功能收集了方便的实现,但没有定义真正的类型。因此:
class MyWidget(ttk.Widget, Loggable): # May be renamed to LoggableMixin
我已经想到了tkinter同样的危险,但是对于制作一个新的视觉控件来说,扩展一个现有控件感觉很自然。我知道mixin,我没有理由不使用它们。说句心里话,我想现在我应该使用继承,让我的Widget子代具有Loggable和ttk.Widget父代。ImgButton将是具有父母MyWidget和ttk.Button的子项。每个级别有两个父级,但再往下就不需要多重继承了。