[英]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.