设置类组成对象的属性的功能

时间:2019-02-10 20:45:22

标签: python python-3.x class composition keyword-argument

我想构造一个类组合,其中包括一个用于设置组件实例变量的函数set_props。 此应用程序是在matplotlib中定义要绘制的新对象。一个示例是我想拥有一个函数drawMyArrow,该函数为其头部,尾部和弧线绘制可能具有不同颜色(和其他规格)的箭头。我希望能够通过drawMyArrow中的关键字参数传递有关头,尾和弧的各种规范。我以前没有使用过类,但是在网上阅读了此书后,我认为解决我的问题的最好方法是定义一个类MyArrow和{ {1}}。

为说明我的问题,我使用一个玩具示例(我也将其用于上一个问题here)。让我们定义一个类ArrowHead,该类由类ArrowArcRoomwall组成。

window

如果我想为door提供一个可以设置其组件属性的函数,则可以执行以下操作:

class Door:
    def __init__(self, color='white', height=2.3, width=1.0, locked=True):
        self.color = color
        self.height = height
        self.width = width
        self.locked=locked

class Window:
    def __init__(self, color='white', height=1.0, width=0.8):
        self.color = color
        self.height = height
        self.width = width

class Wall:
    def __init__(self, color='white', height=2.5, width=4.0):
        self.color = color
        self.height = height
        self.width = width

class Room:
    def __init__(self):
        self.door = Door()
        self.window = Window()
        self.wall = Wall()

但是,如果我决定向Room添加更多实例变量,则必须回到该函数并添加新的实例变量。我可以编写def set_windowprops(r, color=None, width=None, height=None): if not color==None: r.window.color=color if not width==None: r.window.widht=width if not height==None: r.window.height=height return r 使其自动接受Window的所有实例变量作为关键字吗?

理想情况下,我想编写一个这样的函数:

set_windowprops

,但无需将组件的所有实例变量硬编码到函数中。

我一直在研究使用像这样的关键字词典:

Window

两个问题使我无法正常工作:

(1)在最后一行中,我假装def set_props(r, windowcolor=None, windowwidth=None, windowheight=None, doorcolor=None, doorwidth=None, doorheight=None, doorlocked=None, wallcolor=None, wallwidth=None, wallheight=None): if not windowcolor==None: r.window.color=windowcolor if not windowwidth==None: r.window.widht=windowwidth if not windowheight==None: r.window.height=windowheight if not doorcolor==None: r.door.color=doorcolor if not doorwidth==None: r.door.widht=doorwidth if not doorheight==None: r.door.height=dooorheight if not doorlocked==None: r.door.locked=doorlocked if not wallcolor==None: r.wall.color=wallcolor if not wallwidth==None: r.wall.widht=wallwidth if not wallheight==None: r.wall.height=wallheight return r 是(词典)字典,并使用字典语法为window_vars = getNamesOfInstanceVariables(Window) #TODO window_kwargs = {} for v in window_vars: window_kwargs[v] = None def set_windowprops(r, **kwargs): for kw in kwargs: if not kwargs[kw]==None: r["window"][kw] = kwargs[kw] #TODO return r 分配值。但这不起作用,因为rr.window.kw的实例,而不是字典。如果组件类的名称和实例变量的名称以字符串形式给出,那么设置实例变量的语法将是什么?

(2)我曾尝试使用r来编写Room,但无法使其正常运行。 inspect中的许多类都是从基类继承的。我希望getNamesOfInstanceVariables返回用户可以为此类对象设置的 all 实例变量。例如,matplotlib中的类getNamesOfInstanceVariables具有FancyArrow作为基类,实例变量matplotlibPatch。所以我会head_length返回head_width

编辑

让我为为什么我要求一种动态方式编写这些功能添加一些背景知识。假设我已经完成了脚本,它包括类getNamesOfInstanceVariables(FancyArrow)['head_length','head_width', *listOfInstanceVarsForPatch]Window以及这三个类的许多类组成。 Door是许多类组成之一。此类Wall具有十个硬编码的Room函数,如下所示:

Room

我现在决定要向类set_中添加另一个实例变量。例如,

def set_windowcolor(r, color):
    r.window.color = color
    return r

类似于window的所有其他实例变量,Window的这个新属性应在包含class Window: def __init__(self, color='white', height=1.0, width=0.8, open=False): self.color = color self.height = height self.width = width self.open = open # new attribute of Window 的所有类组合中进行自定义。因此,我将遍历代码,找到类Window并添加一个函数

Window

我还必须查找包含Room的所有其他类组合,并手动进行更新。我不想这样做,因为这需要大量工作,而且我可能会忽略过程中的某些类依赖关系,并将错误引入我的代码中。我正在寻找一种解决方案

  • def set_windowopen(r, open): r.window.open = open return r

  • 的所有实例变量自动在Window中为单个属性(例如set)生成set_windowcolor函数
  • 自动调整RoomWindow中的关键字参数列表。

2 个答案:

答案 0 :(得分:1)

这就是我要做的

class Room:
    def __init__(self, kw_door=None, kw_window=None, kw_wall=None):
        if kw_door:
            self.door = Door(**kw_door)
        else:
            self.door = Door()
        if kw_window:
            self.window = Window(**kw_window)
        else:
            self.window = Window()
        if kw_wall:
            self.wall = Wall(**kw_wall)
        else:
            self.wall = Wall()

实际上,您接受的字典将被解包到实例创建中,并且当类定义获得新属性时,如果在传递的字典中找到它们,它们也将被解包。

答案 1 :(得分:0)

回答您的第一个问题。如果要像示例中那样设置Windows的window的{​​{1}}属性和该窗口的r属性,则可以执行以下操作:

kw

您获得名为setattr(getattr(r, "window"), kw, kwargs[kw]) 的{​​{1}}的属性。为此,window属性将其自己的名称(在变量r中的名称)设置为来自windows的新值。正如您的线路尝试那样。

但是,老实说,为什么拥有许多可能参数的函数比仅访问/设置属性本身更受青睐?换句话说,从表面上看,它看起来比需要的复杂。

关于您的第二个问题。您还应该可以只使用kw来获取实例属性的列表,但是是的,继承的属性将以您的方式出现,我不确定是否有一种优雅的方法(即,不走继承树并自行修剪)。但是,如果您确实希望动态遍历实例的属性(例如通过函数进行设置),则可以添加一个(类)属性,该属性定义每种类型的属性,并将其作为已定义的接口。


旁注:kwargs[kw](以及dir()None)只有一个实例,可以对其进行身份验证(而不仅仅是相等性),因为它的读法更好一些。您通常会看到True而不是False