简体   繁体   English

在 Python 中创建具有任意属性的对象的最短方法?

[英]Shortest way of creating an object with arbitrary attributes in Python?

Hey, I just started wondering about this as I came upon a code that expected an object with a certain set of attributes (but with no specification of what type this object should be).嘿,我刚开始想知道这个,因为我遇到了一个代码,它期望一个具有特定属性集的对象(但没有指定这个对象应该是什么类型)。

One solution would be to create a new class that has the attributes the code expects, but as I call other code that also needs objects with (other) attributes, I'd have to create more and more classes.一种解决方案是创建一个具有代码期望属性的新类,但是当我调用其他代码也需要具有(其他)属性的对象时,我必须创建越来越多的类。

A shorter solution is to create a generic class, and then set the attributes on instances of it (for those who thought of using an instance of object instead of creating a new class, that won't work since object instances don't allow new attributes).一个较短的解决方案是创建一个通用类,然后在它的实例上设置属性(对于那些想使用object实例而不是创建新类的人来说,这是行不通的,因为object实例不允许 new属性)。

The last, shortest solution I came up with was to create a class with a constructor that takes keyword arguments, just like the dict constructor, and then sets them as attributes:我想出的最后一个最短的解决方案是创建一个类,该类带有一个接受关键字参数的构造函数,就像dict构造函数一样,然后将它们设置为属性:

class data:
    def __init__(self, **kw):
        for name in kw:
            setattr(self, name, kw[name])

options = data(do_good_stuff=True, do_bad_stuff=False)

But I can't help feeling like I've missed something obvious... Isn't there a built-in way to do this (preferably supported in Python 2.5)?但我不禁觉得我错过了一些明显的东西......难道没有内置的方法来做到这一点(最好在 Python 2.5 中支持)?

type('', (), {})() will create an object that can have arbitrary attributes. type('', (), {})()将创建一个可以具有任意属性的对象。

Example:例子:

obj = type('', (), {})()
obj.hello = "hello"
obj.world = "world"
print obj.hello, obj.world   # will print "hello world"

type() with three arguments creates a new type.带有三个参数的type()创建一个新类型。

  • The first argument '' is the name of the new type.第一个参数''是新类型的名称。 We don't care about the name, so we leave it empty.我们不关心名字,所以我们把它留空。

  • The second argument () is a tuple of base types.第二个参数()是基本类型的元组。 Here object is implicit.这里的object是隐式的。

  • The third argument is a dictionary of attributes of the new object.第三个参数是新对象的属性字典。 We start off with no attributes so it's empty {} .我们从没有属性开始,所以它是空的{}

In the end we instantiate a new instance of this new type with () .最后,我们使用()实例化这种新类型的新实例。

The original code can be streamlined a little by using __dict__ :使用__dict__可以稍微简化原始代码:

In [1]: class data:
   ...:     def __init__(self, **kwargs):
   ...:         self.__dict__.update(kwargs)
   ...: 

In [2]: d = data(foo=1, bar=2)

In [3]: d.foo
Out[3]: 1

In [4]: d.bar
Out[4]: 2

In Python 3.3 and greater, this syntax is made available by the types.SimpleNamespace class.在 Python 3.3 及更高版本中,此语法由types.SimpleNamespace类提供。

Use collections.namedtuple .使用collections.namedtuple

It works well.它运作良好。

from collections import namedtuple
Data = namedtuple( 'Data', [ 'do_good_stuff', 'do_bad_stuff' ] )
options = Data( True, False )

This is the shortest way I know这是我知道的最短路径

>>> obj = type("myobj",(object,),dict(foo=1,bar=2))
>>> obj.foo
1
>>> obj.bar
2
>>> 

using dict instead of {} insures your attribute names are valid使用 dict 而不是 {} 确保您的属性名称有效

>>> obj = type("myobj",(object,),{"foo-attr":1,"bar-attr":2})
>>> obj.foo-attr
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'myobj' has no attribute 'foo'
>>>

This works in 2.5, 2.6, and 3.1:这适用于 2.5、2.6 和 3.1:

class Struct(object):
    pass

something = Struct()
something.awesome = abs

result = something.awesome(-42)

EDIT: I thought maybe giving the source would help out as well.编辑:我认为也许提供来源也会有所帮助。 http://docs.python.org/tutorial/classes.html#odds-and-ends http://docs.python.org/tutorial/classes.html#odds-and-ends

EDIT: Added assignment to result, as I was using the interactive interpreters to verify, and you might not be.编辑:为结果添加了分配,因为我正在使用交互式解释器进行验证,而您可能不是。

A function is an object.函数是一个对象。 So you could assign attributes to a function.因此,您可以为函数分配属性。 Or make one.或者做一个。 This is the simplest way in terms of lines of code, I think.我认为,就代码行而言,这是最简单的方法。

def hello():
    pass


hello.chook = 123

but the easiest and most elegant way (but Python 3.3+) is to use the standard libary's SimpleNamespace :但最简单和最优雅的方法(但 Python 3.3+)是使用标准库的SimpleNamespace

>>> from types import SimpleNamespace
>>> foo = SimpleNamespace()
>>> foo.hello = "world"

Use a combination between lambda and type build-in, I think is the smallest way to do that:使用 lambda 和内置类型之间的组合,我认为是做到这一点的最小方法:

obj = lambda **kwargs: type('obj', (object,), kwargs)()

options = obj(do_good_stuff=True, do_bad_stuff=False)

print options.do_good_stuff
print options.do_bad_stuff

If you don't need to pass values in the constructor, you can do this:如果您不需要在构造函数中传递值,您可以这样做:

class data: pass

data.foo = 1
data.bar = 2

You use the class static member variables to hold your data.您使用类静态成员变量来保存您的数据。

If I understand your question correctly, you need records.如果我正确理解你的问题,你需要记录。 Python classes may be used this way, which is what you do. Python 类可能会以这种方式使用,这就是您所做的。

I believe the most pythonic way of dealing with "records" is simply... dictionaries !我相信处理“记录”的最pythonic方式就是......字典 A class is a sort of dictionary on steroids.类是一种类固醇词典。

Your class example data is essentially a way of converting a dictionary into a class.您的类示例data本质上是一种将字典转换为类的方法。

(On a side note, I would rather use self.__setattr__(name, kw[name]) .) (附带说明,我宁愿使用self.__setattr__(name, kw[name]) 。)

You might be interested in the "Struct", which is part of the IPython package.您可能对“Struct”感兴趣,它是 IPython 包的一部分。 It does what you want to do, with lots of useful methods.它做你想做的事,有很多有用的方法。

http://ipython.org/ipython-doc/rel-0.13/api/generated/IPython.utils.ipstruct.html http://ipython.org/ipython-doc/rel-0.13/api/generated/IPython.utils.ipstruct.html

这通常是您会使用 dict 的东西,而不是创建一个类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM