2016-03-06 61 views
2

问题Adding an attribute to a python dictionary from the standard library显示了如何将属性添加到内置数据类型。但是,有没有办法一个属性在一个步骤中添加一个变量,以便它可以在一个函数调用中使用,等同于以下:有没有办法同时设置一个对象的值和属性?

>>> class Adict(dict): 
     pass 

>>> def myfunc(x): 
     print(x, x.my_attr) 

>>> v = {'a':'cat'} 
>>> var = Adict(v) 
>>> var.my_attr = 'whatever' 
>>> myfunc(var) 
{'a': 'cat'} whatever 

我想减少近3线单线,类似:

>>> myfunc(Adict(v, my_attr='whatever')) 

其中穿过的字典两个项目(“a”和“my_attr”)和任何属性,或

>>> myfunc(Adict(v).my_attr='whatever') 

其解析为一个关键字参数,而不是一个属性设置搜索G。有没有办法在一个步骤中设置一个值和一个属性?

-------- ----------编辑

要回答斯文的问题,我的工作延长优秀genson JSON架构处理器,其中包括以下代码:

# parse properties and add them individually 
    for prop, val in schema.items(): 
     if prop == 'type': 
      self._add_type(val) 
     elif prop == 'required': 
      self._add_required(val) 
     elif prop in ['properties', 'patternProperties']: 
      v = Adict(val) 
      v._ptype = prop 
      self._add_properties(v, 'add_schema') 
     elif prop == 'items': 
      self._add_items(val, 'add_schema') 
     elif prop not in self._other: 
      self._other[prop] = val 

我不需要特殊的事情,除了自定义字典能够与一个属性标记它,这将是很好能够清理我的屁股丑陋的3行代码properties下以便它在视觉上匹配其他情况:-)。我可能会做的是将该标签单独传递给self._add_properties()函数。

+0

让我们重新启动。这一行'{'a':'猫'}无论如何都会把我抛弃。你能解释一下那是什么吗? – idjaw

+0

将该信息作为属性添加到该值是一​​种相当不常见的方法。使用单独的参数似乎好得多,或者甚至可能是单独的函数。 (这两个函数可以调用通用的帮助函数。) –

+0

'genson'数据结构嵌套到任意深度并递归处理。我需要一种方法来处理,例如,一个字典列表字典的字典,同时跟踪每个类型(独立或合并)。一个属性(如在getattr()中)似乎是在每个字典上标记类型的最直接方式,即使它不常见。在JSON术语中,“属性”是字典的键/值,因此将标签附加到字典而不添加键/值是目标。 – Dave

回答

1

您可以引入所谓的构建器(或类工厂模式),它可以获取所有必要的参数并返回结果对象。这是你想要的吗?

class Adict(dict): 
    pass 

def myfunc(x): 
    print(x, x.my_attr) 

def my_builder(v, **kvargs): 
    obj = Adict(v) 
    obj.__dict__.update(kvargs) # internal dictionary with attributes 
    return obj     # return the created object 

# Your original code.  
v = {'a':'cat'} 
var = Adict(v) 
var.my_attr = 'whatever' 
myfunc(var) 

print('------------') 

v2 = {'d': 'dog'} 
myfunc(my_builder(v2, my_attr='whatever_dog')) 

print('------------') 

myfunc(my_builder({'c': 'crocodile'}, my_attr='whatever_croc')) 

这是相当直接的方法来做到你在三条线上所做的。然而,建造者可能后来更聪明。它可以测试参数的值和类型,并根据情况创建,初始化和返回其他类型的对象。这就是类工厂模式的设计目的 - 为您完成工作的代理商。 (这里的问题是,在执行myfunc()之后,您会丢掉obj,但是您可能的意思是在该对象上执行其他操作 - 将它传递到某处或其他地方)。

+0

太棒了!总是很好地学习一种新的设计模式。现在我所需要做的就是研究魔术'obj .__ dict __。update()'咒语。 – Dave

+0

'__dict__'属性是每个对象的内部字典。它保留属于该对象的所有属性,并且对于该类/对象的基本功能而言,该属性不是以某种方式修复的。这意味着任何变量或方法名称都存储在此处,并且该值是该字典项目的值部分。 '.update()'是一个字典方法,它用参数字典的内容更新字典。 '** kvargs'是由键/值参数构建的字典。 – pepr

1

您可以覆盖的Adict构造函数接受关键字参数,并设置基于它的属性:

class Adict(dict): 
    def __init__(*args, my_attr=None, **kwargs): 
     self = args[0] 
     self.my_attr = my_attr 
     dict.__init__(*args, **kwargs) 

这给了你是在一个有些奇怪的方式改变了一本字典,因为my_attr关键字参数将表现出与所有其他关键字参数不同的行为。 (您也可以选择不通过kwargsdict的构造函数。)

+0

谢谢,但如果没有Pythonic'非奇怪'的语法来做到这一点,我只需要在程序中添加额外的行。用三条线更具可读性,但我希望有一个小巧的成语。 – Dave

+2

@Dave将自定义属性添加到字典中是不常见的。如果你需要类似的东西,你通常想要使用自定义类,而不是内置的字典,所以编写自定义构造函数将是一种方法。这变得很奇怪的唯一原因是我尽量保持自定义类与内置字典的兼容。也许你可以对你想要达到的目标给出更多的背景。 –

相关问题