我想构造一个类组合,其中包括一个用于设置组件实例变量的函数set_props
。
此应用程序是在matplotlib中定义要绘制的新对象。一个示例是我想拥有一个函数drawMyArrow
,该函数为其头部,尾部和弧线绘制可能具有不同颜色(和其他规格)的箭头。我希望能够通过drawMyArrow
中的关键字参数传递有关头,尾和弧的各种规范。我以前没有使用过类,但是在网上阅读了此书后,我认为解决我的问题的最好方法是定义一个类MyArrow
和{ {1}}。
为说明我的问题,我使用一个玩具示例(我也将其用于上一个问题here)。让我们定义一个类ArrowHead
,该类由类ArrowArc
,Room
和wall
组成。
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
分配值。但这不起作用,因为r
是r.window.kw
的实例,而不是字典。如果组件类的名称和实例变量的名称以字符串形式给出,那么设置实例变量的语法将是什么?
(2)我曾尝试使用r
来编写Room
,但无法使其正常运行。 inspect
中的许多类都是从基类继承的。我希望getNamesOfInstanceVariables
返回用户可以为此类对象设置的 all 实例变量。例如,matplotlib
中的类getNamesOfInstanceVariables
具有FancyArrow
作为基类,实例变量matplotlib
和Patch
。所以我会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
函数
自动调整Room
或Window
中的关键字参数列表。
答案 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
。