将实例作为可选参数传递给另一个类

时间:2013-08-14 00:18:54

标签: python oop

我最近一直在进行OOP探索。

我有两个类:一个用于事件,另一个用于计算该事件的一些属性集。

class Event(object):
    def __init__(self,name,info):
        self.name = name
        self.category = info.category
        self.classification = info.classification

    @property
    def attributes(self):
        return dict((k,v) for k,v in self.__dict__.items())

class class1(object):
    def __init__(self,some_number):
        self.number = some_number

    @property
    def category(self):
        #stuff
        return category

    @property
    def classification(self):
        #stuff
        return classification

现在我可以做类似

的事情
e = Event('myevent', class1(42))
e.attributes
{'category': 1,
 'classification': None,
 'name': 'myevent'}

但我希望可以选择提供任意数量/未来Event()class2等组合的class3个实例;因此我希望Event()的{​​{1}}方法优雅地处理它们,以便init()将返回所有适当的属性。给e.attributes a * param解压并不会绕过它需要知道它需要分配给自己的属性名称。最终我想要做的是能够创建此事件,然后使用此范例随后根据需要创建/更新其不同的属性集。有可能吗?

3 个答案:

答案 0 :(得分:1)

我想,有一个python对象的no totally clean way to get only user defined attributes,这是你的例子中所需要的,使Event完全不知道info的结构。如果一个设计只能用黑客实现,它可能不是最强大的 - 即使它看起来像是OOD-ish。


下面是一个Event类的示例,它不知道传入的info对象的实际属性:

class Event(object):
    # instead of accepting attributes, just deal with a single object 'info'
    def __init__(self, name, info):
        self.name = name
        self.info = info

    @property
    def attributes(self):
        # attributes will consist of
        # A) Event's name - fixed
        # B) info objects hopefully 'public' attributes, which we need
        #    to lookup at runtime
        attrs = {'name': self.name}
        for attr in [name for name in dir(self.info) 
                     if not name.startswith('_')]:
            attrs[attr] = getattr(self.info, attr)
        return attrs

Class1Class2并没有太多分享:

class Class1(object):
    def __init__(self, some_number):
        # some initial attribute
        self.number = some_number

    @property
    def category(self):
        # stuff
        return 'category value'

    @property
    def classification(self):
        # stuff
        return 'classification value'

class Class2(object):
    @property
    def i_am_totally_different(self):
        return 'yes, indeed'

现在你可以将任何类传递给Event,但我不确定,如果这确实是你的问题:

e = Event('myevent', Class1(42))
print(e.attributes)
# {'category': 'category value', 'name': 'myevent', 
#  'classification': 'classification value', 'number': 42}

e = Event('myevent', Class2())
print(e.attributes)
# {'i_am_totally_different': 'yes, indeed', 'name': 'myevent'}

答案 1 :(得分:0)

你说'我有两个类:一个用于事件,一个用于计算该事件的一些属性。'你有充分理由这样做吗?如果您有事件类,为什么不将这些计算的属性作为事件的属性?

答案 2 :(得分:0)

对此的替代方法不是在不知道它们是什么的情况下转储class2,class3等的全部内容。您可以要求期望该类以某种方式发布它的“公共”属性,例如使用“get_attributes”方法。从编码方便的角度来看,如果class2,class3等继承自共同的祖先,那么它的工作就会减少,但是对它们进行“访问”是完全可以的:

class Event(object):
    def __init__(self, name, info):
        self.Name = name
        self.Info = info

    @property 
    def attributes():
        result = { k: getattr(info, k) for k in info.get_attributes() } 
        return result

class Class1(object):
    def __init__ (name, classification, other)
        self.Name = name
        self.Other = other
        self.Classification = classification

    def get_attributes(self):
        return ("Name", "Classification" ) # in this case not "Other"...

class Class2(object):
    def __init__(self, privateName, orivateData, publicName):
        self.Name = privateName
        self.Data = privateData
        self.Public = publicName

    def get_attributes(self):
        return ("Public",)

这是@miku的想法的'选择'替代方案 - 它可能是一个更安全的赌注,除非你确定你是唯一一个在事件的两端创建代码的人>信息关系。一个很好的技巧是提供一个装饰器来使用get_attributes方法调整现有的类。

除了意图的清晰度之外,这也是一个小小的保护,防止在其中一个字段中遇到一千个文本行的奇怪类:)

编辑响应@ mike的观察:如果get_attributes刚从info对象返回一个字典,这将更加清晰,这将是一个更纯粹的解耦而没有反射负担。我按原样离开代码或讨论没有意义,但正确的方法是在子代码上调用'get_attributes'(如果它存在)并返回默认值(如果不存在)。我的坏:))