我最近一直在进行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解压并不会绕过它需要知道它需要分配给自己的属性名称。最终我想要做的是能够创建此事件,然后使用此范例随后根据需要创建/更新其不同的属性集。有可能吗?
答案 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
Class1
和Class2
并没有太多分享:
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'(如果它存在)并返回默认值(如果不存在)。我的坏:))