我对某些Python类中的多重继承的设计有疑问。
问题是我想扩展ttk按钮。这是我最初的建议(我省略了用于缩短方法的所有源代码,但init方法除外):
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): ???
编辑:此外,我希望我的对象是可记录的,所以我做了这个课:
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的资源,但没有关于如何正确设计多重继承的内容。我什至不知道我的设计是否做错了,但我认为那感觉很自然。
我将感谢您提供一些建议,以及有关此主题的一些链接或资源。
非常感谢你。
这些天来,我一直在阅读有关多重继承的文章,并且学到了很多东西。最后,我已链接了我的资源,资源和参考。
我最主要和最详细的资料来源是“ Fluent python”一书,我发现该书可免费在线阅读。
这描述了具有多重继承的方法解析顺序和设计场景,以及可以正常执行的步骤:
标识并分离接口代码。定义方法但不一定实现的类(应该覆盖这些类)。这些通常是ABC(抽象基类)。它们为子类定义一种类型,从而创建“ IS-A”关系
识别并分离mixin的代码。mixin是一个类,应在子级中使用捆绑的相关新方法实现,但不定义适当的类型。根据这个定义,ABC可能是一个混音,但并非相反。mixin既不定义也不接口,既不是类型
在使用ABC或类以及mixins继承时,您应该仅从一个具体的超类继承,并应继承多个ABC或mixins:
例:
class MyClass(MySuperClass, MyABC, MyMixin1, MyMixin2):
就我而言:
class ImgButton(ttk.Button, MyWidget):
例:
class Widget(BaseWidget, Pack, Grid, Place):
pass
我认为Loggable将是一个Mixin,因为它收集了功能的便捷实现,但没有定义真实类型。所以:
class MyWidget(ttk.Widget, Loggable): # May be renamed to LoggableMixin
优先考虑对象的组成而不是继承:如果可以想到通过将类保留在属性中而不是对其进行扩展或继承来使用类的任何方式,则应避免继承。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句