关于python:如何创建对象并为其添加属性?

How can I create an object and add attributes to it?

我想在python中创建一个动态对象(在另一个对象内部),然后向它添加属性。

我尝试过:

1
2
3
obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')

但这不起作用。

有什么想法吗?

编辑:

我正在设置for循环的属性,该循环通过一系列值进行循环,例如

1
2
3
4
5
6
params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable

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

我使用了setattr函数,因为我不知道如何从for循环中执行obj.a.NAME

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


内置的object可以实例化,但不能在其上设置任何属性。(我希望它可以,为了这个确切的目的。)它没有用于保存属性的__dict__

我通常只是这样做:

1
2
3
4
5
class Object(object):
    pass

a = Object()
a.somefield = somevalue

如果可以的话,我会给object类一个更有意义的名称,这取决于我放入的是哪种数据。

有些人做的是另一件事,他们使用dict的子类,允许属性访问获取密钥。(用d.key代替d['key'])

编辑:对于你的问题,使用setattr是可以的。你不能在object()实例上使用setattr

1
2
3
params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)


您可以使用我的古老的束配方,但是如果您不想创建一个"束类",在Python中已经存在一个非常简单的类——所有函数都可以有任意的属性(包括lambda函数)。因此,以下工作:

1
2
3
obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')

与古老的Bunch配方相比,是否会失去清晰度,这是一个风格决定,我当然会留给你。


python 3.3+中有types.SimpleNamespace类:

1
2
3
4
5
obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtupletyping.NamedTuple可用于不可变对象。PEP557——数据类提出了一个可变的选择。

为了获得更丰富的功能,您可以尝试attrs软件包。请参阅示例用法。


实现这一目标有几种方法。基本上,您需要一个可扩展的对象。

1
2
3
4
5
6
7
8
obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()


mock模块基本上就是为此而设计的。

1
2
3
import mock
obj = mock.Mock()
obj.a = 5


现在你可以这样做了(不确定这是否与Evilpie的答案相同):

1
2
3
MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42


请尝试以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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']


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

1
2
3
class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')


正如医生所说:

Note: object does not have a __dict__, so you can’t assign arbitrary attributes to an instance of the object class.

您可以使用虚拟类实例。


这些解决方案在测试期间非常有用。基于其他人的答案,我在python 2.7.9中这样做(没有staticmethod,我会得到一个typeerror(unbound method…):

1
2
3
4
In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

您使用的是哪些对象?刚用一个示例类尝试过,它运行得很好:

1
2
3
4
5
6
7
8
9
class MyClass:
  i = 123456
  def f(self):
    return"hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

我得到了123作为答案。

我看到的唯一失败的情况是,如果您在一个内置对象上尝试setattr

更新:从注释中可以重复:为什么不能在Python中向对象添加属性?


如果我们可以在创建嵌套对象之前确定并聚合所有属性和值,那么我们可以创建一个新类,在创建时使用字典参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# python 2.7

class NestedObject():
    def __init__(self, initial_attrs):
        for key in initial_attrs:
            setattr(self, key, initial_attrs[key])

obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'

我们还可以允许关键字参数。看看这篇文章。

1
2
3
4
5
6
7
8
9
10
class NestedObject(object):
    def __init__(self, *initial_attrs, **kwargs):
        for dictionary in initial_attrs:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])


obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')


今天晚些时候来到这里,但这里是我的一本小册子,上面有一个对象刚好在应用程序中保留了一些有用的路径,但是你可以将它调整为任何你想要的信息,你可以用getattr和dot符号访问的排序口述(这就是我认为这个问题真正的目的):

1
2
3
4
5
6
7
8
import os

def x_path(path_name):
    return getattr(x_path, path_name)

x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
    setattr(x_path, name, os.path.join(x_path.root, name))

这很酷,因为现在:

1
2
3
4
5
In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

因此,它使用类似上述答案的函数对象,但使用函数来获取值(如果愿意,您仍然可以使用(getattr, x_path, 'repository')而不是x_path('repository'))。


1
2
3
4
5
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name],"attr","value")


我看到的另一种方式是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)