设置类组成对象的属性的功能 [英] Function to set properties of an object of a class composition

查看:85
本文介绍了设置类组成对象的属性的功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

为了说明我的问题,我使用一个玩具示例(我也将它用于上一个问题

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

(1)在最后一行中,我假装r是(词典)字典,并使用字典语法为r.window.kw分配值.但这不起作用,因为rRoom的实例,而不是字典.如果组件类的名称和实例变量的名称以字符串形式给出,那么设置实例变量的语法将是什么?

(2)我尝试使用inspect编写getNamesOfInstanceVariables,但是无法使其稳定运行. matplotlib中的许多类都从基类继承.我希望getNamesOfInstanceVariables返回用户可以为此类对象设置的 all 实例变量.例如,matplotlib中的类FancyArrow具有Patch作为基类,并且实例变量head_lengthhead_width.所以我会getNamesOfInstanceVariables(FancyArrow)返回['head_length','head_width', *listOfInstanceVarsForPatch].

编辑

让我为为什么我要求一种动态的方式编写这些功能添加一些背景知识.假设我已经完成了脚本,它包括类WindowDoorWall以及这三个类的许多类.这些许多类组成之一是Room.此类Room具有十个硬编码的set_函数,如下所示:

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

我现在决定要向类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的所有类组合中可自定义.因此,我将遍历代码,找到类Room并添加一个函数

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

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

  • Room中为Window

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

解决方案

这就是我要做的

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()

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

I would like construct a class composition that includes a function set_props for setting the instance variables of components. The application for this is in defining new objects for drawing in matplotlib. One example is that I would like to have a function drawMyArrow that draws an arrow with possibly different colors (and other specifications) for its head, tail, and arc. I would like to be able to pass various specifications for the head, tail, and arc via keyword arguments in drawMyArrow. I haven't worked with classes before, but reading up on this online, I believe that the best way to solve my problem is to define a class MyArrow that is a composition of some classes ArrowHead and ArrowArc.

To illustrate my problem, I am using a toy example (that I also used for a previous question here). Let's define a class Room that is a composition of the classes wall, window, and 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()

If I want to have a function for Room that can set properties of its components, I can do something like this:

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

But if I decide to add more instance variables to Window, I would have to go back to this function and add the new instance variables. Can I write set_windowprops so that it automatically accepts all instance variables of Window as keywords?

Ideally, I would like to write a function like this:

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

but without the need of hardcoding all instance variables of components into the function.

I was looking into using keyword dictionaries like so:

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

Two issues keep me from getting this to work:

(1) In the last line, I am pretending that r is a dictionary (of dictionaries) and using dictionary syntax to assign a value to r.window.kw. But that doesn't work because r is an instance of Room and not a dictionary. What would be the syntax for setting instance variables if the name of the component class and the name of the instance variable are given as strings?

(2) I have tried using inspect to write getNamesOfInstanceVariables, but I am unable to get it to work robustly. Many classes in matplotlib inherit from base classes. I would like getNamesOfInstanceVariables to return all instance variables that a user can set for an object of this class. For example, the class FancyArrow in matplotlib has Patch as base class and instance variables head_length and head_width. So I would getNamesOfInstanceVariables(FancyArrow) to return ['head_length','head_width', *listOfInstanceVarsForPatch].

EDIT

Let me add a bit of background on why I am asking for a dynamical way to write these functions. Let's say I have finished my script and it includes the classes Window, Door, Wall and many class compositions of these three. One of these many class compositions is Room. This class Room has ten hardcoded set_ functions that look like this:

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

I now decide that I want to add another instance variable to the class Window. For example,

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

Similar to all the other instance variables of window, this new attribute of Window should be customizable in all classe compositions that contain a Window. So I would go through my code, find the class Room and add a function

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

I would also have to look for all other class compositions that contain a Window and update them manually as well. I don't want to do this because it is a lot of work and I am likely going to overlook some class dependencies in the process and introduce bugs into my code. I am looking for a solution that either

  • generates set functions for single properties (e.g. set_windowcolor) automatically in Room for all instance variables of Window or

  • automatically adjusts the list of keyword arguments in set_windowprops or set_props.

解决方案

Here is what I would do

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()

effectively you are accepting a dictionary that will be unpacked into the instance creation, and when the class definition gets new attributes, they too will be unpacked if they are found in the passed dictionary.

这篇关于设置类组成对象的属性的功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆