如何创建具有属性的内联对象?

84

在 JavaScript 中,代码应该是:

var newObject = { 'propertyName' : 'propertyValue' };
newObject.propertyName;  // returns "propertyValue"

但在Python中,相同的语法会创建一个字典,而这不是我想要的。

new_object = {'propertyName': 'propertyValue'}
new_object.propertyName  # raises an AttributeError

可能是重复的问题:如何创建一个对象并为其添加属性? - undefined
9个回答

127

5
这个翻译的意思是:这个东西为什么会被混淆?它是一个经过适当记录的行为。 - SilentGhost
19
记录但不常见的行为。我非常确定99.9%的Python程序员看到这在真实代码中时,他们的初始反应会是“什么鬼!?” - Laurence Gonsalves
19
实际上,@Laurence,我的反应是,“哇,我打赌那会创建一个继承自object且具有名为'propertyName'成员的值为'propertyValue'的虚构'obj'类的新实例。”而你知道吗?我是正确的!我认为这并不太不直观。 - Chris Lutz
4
正是像这样灵活、简洁且易读的代码使我选择了 Python。 - Tom Leys
29
为了完整性,在创建类型的实际实例而不仅仅是一个类型对象时,需要添加括号 (): obj = type('obj', (object,), {'propertyName' : 'propertyValue'})() - Greg Hewgill
显示剩余15条评论

70

Python 3.3增加了SimpleNamespace类,用于实现这个精确的目的:

>>> from types import SimpleNamespace

>>> obj = SimpleNamespace(propertyName='propertyValue')
>>> obj
namespace(propertyName='propertyValue')

>>> obj.propertyName
'propertyValue'

除了适当的构造函数来构建对象外,SimpleNamespace还定义了__repr____eq__(在3.4文档中记录),以表现出预期的行为。


3
这应该是被接受的答案。比创建一个新的“type”更易读和直观。 - Chris Collett

38

Peter的回答

obj = lambda: None
obj.propertyName = 'propertyValue'

@ManelClos 正在创建一个返回 None 的函数对象,你可以通过 obj() 看到它。这个函数对象可以有属性。 - jeremyjjbrown
1
@jeremyjjbrown 你想说什么? - Sam

14

我不知道是否有内置的方法可以这样做,但您始终可以定义一个类似于以下内容的类:

class InlineClass(object):
    def __init__(self, dict):
        self.__dict__ = dict

obj = InlineClass({'propertyName' : 'propertyValue'})

7

我喜欢Smashery的想法,但Python似乎满足于让你自己修改类:

>>> class Inline(object):
...     pass
...
>>> obj = Inline()
>>> obj.test = 1
>>> obj.test
1
>>>

对我来说,在Python 2.5中完全正常。请注意,您必须将其应用于从 object 派生的类 - 如果您将该行更改为 obj = object ,它将无法工作。


2
是的,你可以这样做 - 但出于某种奇怪的原因,你不能使用object() - 你必须创建自己的类。 - Smashery
6
如果你想要一个内联类,你可以使用 obj = lambda: None 这个奇怪的语法,但是它会执行必要的任务... - Peter
@Peter - 我不知道这一点。然而,既然我看到了它,我更喜欢SilentGhost的答案。 - Chris Lutz
我删除了构造函数以展示实现它的最短方式。 - Jader Dias
@Jader - 好的,没问题。没有它看起来更好。 - Chris Lutz
@Smashery: "奇怪的原因"在于类型object是对象继承树的根,如果它有一个关联的字典来保存属性,那么Python中的所有对象都必须有一个关联的字典。实际上,我希望有一种标准类型,可以创建一个空的容器类,但自己声明一个相当容易。 - steveha

5
SilentGhost提供了一个很好的答案,但他的代码实际上创建了一个新的元类类型的对象,也就是创建了一个类。而在Python中,类也是对象!
obj = type('obj', (object,), {'propertyName' : 'propertyValue'})
type(obj) 

提供。
<class 'type'>

为了一行代码创建一个具有字典属性(也称为属性)的自定义或内置类的新对象,我建议直接调用它:
new_object = type('Foo', (object,), {'name': 'new object'})()

现在

type(new_object) 

is

<class '__main__.Foo'>

这意味着它是Foo类的一个对象。

希望能帮助那些初学Python的人。


4
在Python中,声明一个类并使用__init__()函数来设置实例非常容易,并且可以使用可选参数。如果不指定参数,则得到一个空实例,如果指定一些或所有参数,则初始化实例。
我在这里(截至目前为止我的最高评分答案)进行了解释,因此我不会重新输入解释。但是,如果您有问题,请问,我会回答。
如果您只想要一个一般的对象,其类并不重要,可以这样做:
class Generic(object):
    pass

x = Generic()
x.foo = 1
x.bar = 2
x.baz = 3

一个明显的扩展是添加一个__str__()函数,以打印出有用的信息。
有时候,这个技巧很方便,当你想要一个更方便的字典时。我发现键入x.foox["foo"]更容易。

2

另一个可行的选择是使用namedtuple

from collections import namedtuple

message = namedtuple('Message', ['propertyName'], verbose=True)
messages = [
    message('propertyValueOne'),
    message('propertyValueTwo')
]

-1
class test:
    def __setattr__(self,key,value):
        return value


myObj = test()
myObj.mykey = 'abc' # set your property and value

没有必要定义__setattr__,请参考Chris的回复。 - Jader Dias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接