设置 class 组合对象属性的函数
Function to set properties of an object of a class composition
我想构造一个 class 组合,其中包含一个函数 set_props
用于设置组件的实例变量。
其应用是在 matplotlib 中定义用于绘图的新对象。一个例子是我想要一个函数 drawMyArrow
来绘制一个箭头,其头部、尾部和弧线可能具有不同的颜色(和其他规格)。我希望能够通过 drawMyArrow
中的关键字参数传递头部、尾部和圆弧的各种规范。我以前没有使用过 classes,但是在网上阅读这个,我相信解决我的问题的最好方法是定义一个 class MyArrow
的组合一些 classes ArrowHead
和 ArrowArc
.
为了说明我的问题,我使用了一个玩具示例(我也将其用于上一个问题 )。让我们定义一个 class Room
,它是 classes 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
的所有实例变量作为关键字吗?
理想情况下,我想编写这样的函数:
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
有两个问题使我无法正常工作:
(1) 在最后一行中,我假装 r
是一个(字典的)字典,并使用字典语法为 r.window.kw
赋值。但这不起作用,因为 r
是 Room
的实例而不是字典。如果组件名称 class 和实例变量名称以字符串形式给出,设置实例变量的语法是什么?
(2) 我曾尝试使用 inspect
编写 getNamesOfInstanceVariables
,但我无法使其正常工作。 matplotlib
中的许多 classes 继承自基础 classes。我想要 getNamesOfInstanceVariables
到 return 所有 用户可以为此 class 的对象设置的实例变量。例如,matplotlib
中的 class FancyArrow
有 Patch
作为基础 class 和实例变量 head_length
和 head_width
。所以我会 getNamesOfInstanceVariables(FancyArrow)
到 return ['head_length','head_width', *listOfInstanceVarsForPatch]
.
编辑
让我补充一些背景知识,说明为什么我要求以动态方式编写这些函数。假设我已经完成了我的脚本,它包括 classes Window
、Door
、Wall
和这三者的许多 class 组合。 class 的作品之一是 Room
。这个 class Room
有十个硬编码的 set_
函数,如下所示:
def set_windowcolor(r, color):
r.window.color = color
return r
我现在决定要向 class 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
的这个新属性应该可以在包含 Window
的所有 classe 组合中自定义。所以我会检查我的代码,找到 class Room
并添加一个函数
def set_windowopen(r, open):
r.window.open = open
return r
我还必须寻找包含 Window
的所有其他 class 作品并手动更新它们。我不想这样做,因为它需要大量工作,而且我可能会忽略过程中的一些 class 依赖项并将错误引入我的代码中。我正在寻找一种解决方案
为Window
或[=65=的所有实例变量自动在Room
中为单个属性(例如set_windowcolor
)生成set
函数]
自动调整set_windowprops
或set_props
中的关键字参数列表。
先回答你的问题。如果你想设置 r
的 window
属性和那个 `windows 的 kw
属性,就像你的例子一样,你可以执行以下操作:
setattr(getattr(r, "window"), kw, kwargs[kw])
您获得 r
的名为 window
的属性。对于 windows
属性,将其名称在变量 kw
中的属性设置为来自 kwargs[kw]
的新值。正如您所尝试的那样。
但老实说,为什么具有许多可能参数的函数比 accessing/setting 属性本身更受欢迎?或者换句话说,从表面上看,它看起来比需要的更复杂。
关于你的第二个问题。您也应该能够只使用 dir()
来获取实例属性列表,但是是的,继承的属性会妨碍您,我不确定是否有一种优雅的方法(即不走继承树并自己进行修剪)。但是,如果您真的想动态遍历实例的属性,例如通过函数进行设置,我会说添加一个 (class) 属性,定义每种类型的属性依赖于它作为定义的接口。
旁注:None
(以及 True
和 False
)只有一个实例,可以测试其身份(而不仅仅是相等性),因为它读取你通常会看到 if somevar is not None
而不是 if not somevar == None
.
好一点
这是我会做的
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()
实际上,您正在接受一个将被解压到实例创建中的字典,并且当 class 定义获得新属性时,如果在传递的字典中找到它们,它们也会被解压。
我想构造一个 class 组合,其中包含一个函数 set_props
用于设置组件的实例变量。
其应用是在 matplotlib 中定义用于绘图的新对象。一个例子是我想要一个函数 drawMyArrow
来绘制一个箭头,其头部、尾部和弧线可能具有不同的颜色(和其他规格)。我希望能够通过 drawMyArrow
中的关键字参数传递头部、尾部和圆弧的各种规范。我以前没有使用过 classes,但是在网上阅读这个,我相信解决我的问题的最好方法是定义一个 class MyArrow
的组合一些 classes ArrowHead
和 ArrowArc
.
为了说明我的问题,我使用了一个玩具示例(我也将其用于上一个问题 Room
,它是 classes 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
的所有实例变量作为关键字吗?
理想情况下,我想编写这样的函数:
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
有两个问题使我无法正常工作:
(1) 在最后一行中,我假装 r
是一个(字典的)字典,并使用字典语法为 r.window.kw
赋值。但这不起作用,因为 r
是 Room
的实例而不是字典。如果组件名称 class 和实例变量名称以字符串形式给出,设置实例变量的语法是什么?
(2) 我曾尝试使用 inspect
编写 getNamesOfInstanceVariables
,但我无法使其正常工作。 matplotlib
中的许多 classes 继承自基础 classes。我想要 getNamesOfInstanceVariables
到 return 所有 用户可以为此 class 的对象设置的实例变量。例如,matplotlib
中的 class FancyArrow
有 Patch
作为基础 class 和实例变量 head_length
和 head_width
。所以我会 getNamesOfInstanceVariables(FancyArrow)
到 return ['head_length','head_width', *listOfInstanceVarsForPatch]
.
编辑
让我补充一些背景知识,说明为什么我要求以动态方式编写这些函数。假设我已经完成了我的脚本,它包括 classes Window
、Door
、Wall
和这三者的许多 class 组合。 class 的作品之一是 Room
。这个 class Room
有十个硬编码的 set_
函数,如下所示:
def set_windowcolor(r, color):
r.window.color = color
return r
我现在决定要向 class 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
的这个新属性应该可以在包含 Window
的所有 classe 组合中自定义。所以我会检查我的代码,找到 class Room
并添加一个函数
def set_windowopen(r, open):
r.window.open = open
return r
我还必须寻找包含 Window
的所有其他 class 作品并手动更新它们。我不想这样做,因为它需要大量工作,而且我可能会忽略过程中的一些 class 依赖项并将错误引入我的代码中。我正在寻找一种解决方案
为
Window
或[=65=的所有实例变量自动在Room
中为单个属性(例如set_windowcolor
)生成set
函数]自动调整
set_windowprops
或set_props
中的关键字参数列表。
先回答你的问题。如果你想设置 r
的 window
属性和那个 `windows 的 kw
属性,就像你的例子一样,你可以执行以下操作:
setattr(getattr(r, "window"), kw, kwargs[kw])
您获得 r
的名为 window
的属性。对于 windows
属性,将其名称在变量 kw
中的属性设置为来自 kwargs[kw]
的新值。正如您所尝试的那样。
但老实说,为什么具有许多可能参数的函数比 accessing/setting 属性本身更受欢迎?或者换句话说,从表面上看,它看起来比需要的更复杂。
关于你的第二个问题。您也应该能够只使用 dir()
来获取实例属性列表,但是是的,继承的属性会妨碍您,我不确定是否有一种优雅的方法(即不走继承树并自己进行修剪)。但是,如果您真的想动态遍历实例的属性,例如通过函数进行设置,我会说添加一个 (class) 属性,定义每种类型的属性依赖于它作为定义的接口。
旁注:None
(以及 True
和 False
)只有一个实例,可以测试其身份(而不仅仅是相等性),因为它读取你通常会看到 if somevar is not None
而不是 if not somevar == None
.
这是我会做的
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()
实际上,您正在接受一个将被解压到实例创建中的字典,并且当 class 定义获得新属性时,如果在传递的字典中找到它们,它们也会被解压。