0

我最近一直在进行 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()任何数量/组合的实例 future class2,class3等;因此我希望Event()'sinit()方法能够优雅地处理它们,以便e.attributes返回所有适当的属性。给Event.__init__一个 *param 来解包似乎并没有绕过它知道它需要分配给自己的属性名称的需要。最终,我想要做的是能够创建此事件,然后使用此范例在以后根据需要创建/更新其不同的属性集。可能吗?

4

3 回答 3

1

我想,没有完全干净的方法可以只获取python 对象的用户定义属性,这是您在示例中需要的,以便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'}
于 2013-08-14T00:32:55.703 回答
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”,如果不存在则返回默认值。我的错 :)

于 2013-08-14T01:29:14.790 回答
0

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

于 2013-08-14T01:06:12.413 回答