有没有办法同时设置对象的值和属性?

时间:2016-03-06 19:16:45

标签: python python-3.x

问题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'和#39; my_attr')并且没有属性,或

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

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

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

要回答Sven的问题,我正在努力扩展优秀的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

除了能够使用属性标记它之外,我不需要使用自定义dict的任何特殊内容,并且能够在{{1下清理我那些丑陋的3行代码会很好所以它在视觉上匹配其他情况:-)。我可能会做的是将该标记单独传递给properties函数。

2 个答案:

答案 0 :(得分: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关键字参数的行为与所有其他关键字参数的行为不同。 (您也可以选择不将kwargs传递给dict构造函数。)

答案 1 :(得分: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'))

这是完全按照你在三条线上所做的那样直截了当的方式。但是,建造者可能会更加智能。它可以测试参数的值和类型,并根据情况,可以创建,初始化和返回其他类型的对象作为结果。这就是类工厂模式的设计目标 - 为您工作的代理。 (这里的问题是你在执行obj之后抛弃了myfunc(),但你可能意味着要对对象做一些其他事情 - 将它传递到某处或其他任何地方。)