【问题标题】:How to define a default list of attributes for instances of a class?如何为类的实例定义默认属性列表?
【发布时间】:2012-06-11 11:36:29
【问题描述】:

我的程序中有几个对象,每个对象都有大约 10-15 个属性。这些属性设置在程序各个阶段的代码中的各个位置。由于无需在 Python 的类中定义它们就可以将它们设置在对象上,因此在我的程序中没有很好的权威列表来说明使用了哪些属性。

我想要以下内容:

class MyObject(object):
    attr1
    attr2

我查看了内置的 property(),但每个属性至少有 6 行代码。有没有一种简单的方法来定义默认属性列表而无需在 Python 中初始化它们?

更新:我忘了说,大多数值没有合理的默认值,在使用之前实际上等于None

【问题讨论】:

  • 你想要那些没有添加默认值的None吗?不确定如何处理更新中的信息...
  • 我真的不知道最pythonic的方式是什么,我只知道我不能在对象创建时给所有属性一个值。
  • 通常它们都在__init__() 方法中定义,即使只是将它们设置为0None'' 作为记录它们的一种方式。另一方面,除非对象处于某种状态,否则完全允许不定义一个,但其他人可能更难理解。
  • 还有隐含的,来自使用对象的代码,而不是类定义。将它们设置为 None 就可以满足我的目的。
  • PEP 20 -- The Zen of Python 中的第二件事是“显式优于隐式”。只是说... ;-)

标签: python properties attributes


【解决方案1】:

我认为 Hugh Bothwell 走在正确的轨道上,但可以做得更简洁:

class MyClass(object):
    _defaults = "attr1", "attr2", "attr3"
    _default_value = None

    def __init__(self, **kwargs):
        self.__dict__.update(dict.fromkeys(self._defaults, self._default_value))
        self.__dict__.update(kwargs)


my_object = MyClass(attr3='overridden', attr4='added')

print(vars(my_object))

输出:

{'attr4': 'added', 'attr2': None, 'attr3': 'overridden', 'attr1': None}

我制作了_defaults_default_value 类属性(可以在运行时更改)。 (但是,提供可变的默认值可能需要额外的代码来防止它被创建的每个实例共享。)

这很容易扩展以允许为每个默认属性定义不同的(不可变的)默认值:

class MyClass(object):
    _defaults = {
        "attr1": None,
        "attr2": 0,
        "attr3": ""
    }

    def __init__(self, **kwargs):
        self.__dict__.update(self._defaults)
        self.__dict__.update(kwargs)


my_object = MyClass(attr3='overridden', attr4='added')

print(vars(my_object))

输出:

{'attr4': 'added', 'attr2': 0, 'attr3': 'overridden', 'attr1': None}

【讨论】:

  • 太棒了!我忘了 self.__dict__ - 这绝对是一种更简洁的方式。
【解决方案2】:

像这样?

class MyObject(object):
    def __init__(self, attr1 = default1, attr2 = default2):
        self.attr1 = attr1
        self.attr2 = attr2

您可以实例化 MyObject 指定或不指定属性

myObject1 = MyObject() # gets default values 
myObject2 = MyObject(foo, bar) # overrides defaults

如果您有可变数量的属性,您也可以使用关键字参数 (kwargs),例如,请参阅 here

【讨论】:

  • 查看我上面的更新,我没有所有属性的默认值。
【解决方案3】:

如果你有很多属性要传递,这样可能更易读:

class Myclass(object):
    def __init__(self, **kwargs):
        defaults = {
            "attr1": None,
            "attr2": 0,
            "attr3": ""
        }
        defaults.update(kwargs)
        for attr,value in defaults.iteritems():
            self.__setattr__(attr, value)

编辑:查看@martineau 和@kosii 的建议,这是另一种可能性:

class MyClass(object):
    defaults = {
        "attr1": None,
        "attr2": 0,
        "attr3": ""
    }

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __getattr__(self, key):
        try:
            # return a default value
            return MyClass.defaults[key]
        except KeyError:
            raise AttributeError("don't recognize .{}".format(key))

...在这种情况下,识别的对象属性如果尚未实际设置,则返回默认值。

【讨论】:

  • 您的更新是一个有趣的想法——有点像拥有“虚拟属性”。但是,我会对此持怀疑态度,因为一个潜在的问题可能是,如果默认属性具有通过一个实例更改的可变值(例如附加到列表),那么该更改将显示在所有其他现有的实例以及随后创建的任何新实例。另一方面,也许这是一个“特征”,尽管它可能与最小意外原则背道而驰......
【解决方案4】:

__getattr__一起玩一下怎么样?

class A(object):
    def __init__(self, special_attrs=[]):
        self.__dict__['_special_attrs_dict'] = dict.fromkeys(special_attrs)

    def __getattr__(self, key):
        if key in self._special_attrs_dict:
            return self._special_attrs_dict[key]
        raise AttributeError('')

    def __setattr__(self, key, value):
        if key in self._special_attrs_dict:
            self._special_attrs_dict[key] = value
        else:
            super(A, self).__setattr__(key, value)

【讨论】:

    【解决方案5】:

    如果您愿意,您可以使用默认值创建类属性。如果一个类可以有许多属性但其中许多属性通常未设置,或者如果实例被序列化,您可以确保只序列化/反序列化非默认属性而忽略具有默认值的属性,这将特别有用价值观。

    例如

    class MyObject(object):
        attr1 = 42
        attr2 = ()
    
    instance = MyObject()
    for x in instance.attr2:
        print(x)
    

    现在任何MyObject 实例都有attr1attr2 属性,无论它们是否被显式设置。请注意,如果您希望默认值是一个序列,您应该确保使用一个元组,这样它就不会被意外改变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-12
      • 2012-11-11
      • 2015-02-27
      • 1970-01-01
      • 1970-01-01
      • 2015-06-29
      相关资源
      最近更新 更多