如何创建对象并向其添加属性?

Joh*_*ohn 279 python attributes class object

我想在Python中创建一个动态对象(在另一个对象内),然后为其添加属性.

我试过了:

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')
Run Code Online (Sandbox Code Playgroud)

但这没用.

有任何想法吗?

编辑:

我从for循环中设置属性,循环遍历值列表,例如

params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,我会得到obj.a.attr1,obj.a.attr2,obj.a.attr3.

我使用了这个setattr函数因为我不知道怎么做obj.a.NAME一个for循环.

如何根据p上面示例中的值设置属性?

Fog*_*ird 317

内置object可以实例化,但不能在其上设置任何属性.(我希望它可以,出于这个目的.)它没有__dict__保持属性.

我通常只是这样做:

class Object(object):
    pass

a = Object()
a.somefield = somevalue
Run Code Online (Sandbox Code Playgroud)

当我可以的时候,我会给这个Object班级一个更有意义的名字,这取决于我投入的数据类型.

有些人做了不同的事情,他们使用dict允许属性访问的子类来获取密钥.(d.key而不是d['key'])

编辑:对于您的问题的添加,使用setattr很好.你不能setattrobject()实例上使用.

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)
Run Code Online (Sandbox Code Playgroud)

  • 它*可以*实例化,一旦完成就不用于任何有用的东西.`foo = object()`有效,但你不能用它做很多事情 (8认同)
  • 很好的答案,我唯一改变的是使用“Struct”作为类的名称以使其更加明显。节省了我大量输入 `["` 和 `"]`,干杯! (2认同)

Ale*_*lli 194

你可以使用我古老的Bunch配方,但如果你不想制作一个"束类",Python中已经存在一个非常简单的 - 所有函数都可以有任意属性(包括lambda函数).所以,以下工作:

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')
Run Code Online (Sandbox Code Playgroud)

与古老的Bunch食谱相比,是否失去清晰度是否合适,是一种风格决定,我当然会留给你.

  • @FogleBird,一个风格决定,正如我所提到的.一些在教会的lambda演算中受过训练的CS专家习惯于将函数(lambdas)视为所有数据的基本类型(例如,整数23可以看作等同于`lambda:23`),所以对于这样的专家为此目的使用`lambda`s可能会感觉不像"黑客".就个人而言,我不太喜欢"lambda"_in Python_中的那个 - 但这是个人品味的问题. (25认同)
  • @ naught101,函数**是一个对象,在Python中,所以你的异议是不可思议的. (5认同)
  • @naught101,避免创建新类型(重用现有类型)并不复杂,它简化了.现在可能实际上更喜欢`来自argparse import Namespace`虽然我希望它生活在其他地方*例如,`collection`) - 再次重用现有类型,只是一个更好的类型,并且仍然避免新类型创建.但是,它当时不存在:-). (5认同)

jfs*_*jfs 123

types.SimpleNamespacePython 3.3+中:

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1
Run Code Online (Sandbox Code Playgroud)

collections.namedtuple,typing.NamedTuple可用于不可变对象.PEP 557 - 数据类 建议了一个可变的替代方案.

要获得更丰富的功能,您可以尝试attrs打包.查看示例用法.

  • 如果您需要适用于Python 2.7的工具,也可以尝试argparse.Namespace类。 (2认同)

evi*_*pie 31

有几种方法可以实现这一目标.基本上你需要一个可扩展的对象.

obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()
Run Code Online (Sandbox Code Playgroud)

  • `obj.a = type('',(),{})` (13认同)

Dun*_*tos 23

mock模块基本上是为此而制作的.

import mock
obj = mock.Mock()
obj.a = 5
Run Code Online (Sandbox Code Playgroud)

  • `unittest.Mock`是自Python 3.3以来标准库的一部分(https://docs.python.org/3/library/unittest.mock.html) (5认同)
  • 缺点是外部依赖 (3认同)
  • 我认为取决于您的代码的用法。如果它是生产代码,我不想要一些“模拟”。只是让我觉得很奇怪。 (2认同)

and*_*ini 18

现在你可以做(​​不确定它是否与evilpie一样):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42
Run Code Online (Sandbox Code Playgroud)


小智 15

请尝试以下代码:

$ python
>>> class Container(object):
...     pass 
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',     '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']
Run Code Online (Sandbox Code Playgroud)

  • @DeadChex显然它创建了一个新的Class(对象),它是一个具有对象属性的空类,并将属性存储在类中。这甚至比安装更多模块或依赖 lambda 更好。 (2认同)
  • 不知道为什么这没有更多的赞成票。是否有理由不将其用于基本容器类?在 Python 2.7、2.6 和 3.4 中似乎运行良好 (2认同)

Ern*_*sto 12

您也可以直接使用类对象; 它创建一个命名空间:

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么这不是最佳答案? (2认同)

Sil*_*ost 8

正如文档所说:

注意:object__dict__,所以你不能指定任意属性的实例object类.

你可以使用虚拟类实例.