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

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

我试着:

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

但这并不奏效。

什么好主意吗?

编辑:

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

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"实例上设置属性;类< / >。

495877 次浏览

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

我通常是这样做的:

class Object(object):
pass


a = Object()
a.somefield = somevalue

当我可以时,我给Object类一个更有意义的名字,这取决于我在其中放入什么样的数据。

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

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

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

医生说:

请注意: object确实有,所以你不能将任意属性赋给object类的实例。

你可以使用伪类实例。

有一些方法可以达到这个目标。 基本上你需要一个可扩展的对象

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


obj.b = lambda:None


class Test:
pass
obj.c = Test()

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

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

与古老的Bunch食谱相比,是否失去清晰度是可以的,这是一个风格决定,当然,我将留给你。

您正在使用哪些对象?刚刚尝试了一个样例类,它工作得很好:

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中为对象添加属性?

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

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42
di = {}
for x in range(20):
name = '_id%s' % x
di[name] = type(name, (object), {})
setattr(di[name], "attr", "value")

试试下面的代码:

$ 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']

types.SimpleNamespace类在Python 3.3+:

obj = someobject
obj.a = SimpleNamespace()
for p in params:
setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtupletyping.NamedTuple可用于不可变对象。PEP 557—数据类建议一个可变的替代。

为了更丰富的功能,你可以尝试attrs。看到示例用法pydantic可能也值得一看

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

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

今天晚了,但这是我的一文不值的一个对象,恰好在应用程序中保存了一些有用的路径,但你可以将它用于任何你想要的信息字典,你可以通过getattr和点符号访问(这是我认为这个问题真正的问题):

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))

这很酷,因为:

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'),如果你喜欢)。

另一种方式,我认为是这样的:

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)

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

import mock
obj = mock.Mock()
obj.a = 5

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

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

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

# 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'

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

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')

我认为最简单的方法是通过集合模块。

import collections
FinanceCtaCteM = collections.namedtuple('FinanceCtaCte', 'forma_pago doc_pago get_total')
def get_total(): return 98989898
financtacteobj = FinanceCtaCteM(forma_pago='CONTADO', doc_pago='EFECTIVO',
get_total=get_total)


print financtacteobj.get_total()
print financtacteobj.forma_pago
print financtacteobj.doc_pago

如果你正在寻找链赋值,要做的事情,如django模型模板抽象属性赋值:

from types import SimpleNamespace




def assign(target, *args, suffix):
ls = target
for i in range(len(args) - 1):
a = args[i]
ns = SimpleNamespace()
setattr(ls, a, ns)
ls = ns
setattr(ls, args[-1], suffix)
return ls




a = SimpleNamespace()
assign(a, 'a', 'b', 'c', suffix={'name': 'james'})
print(a.a.b.c)
# {'name': 'james'}

它允许你将model作为target传递,并将end属性分配给它。

这很好:

    exec("obj.a."+p)

如果你想将属性设置为某个值,可以这样做:

    exec("obj.a."+p+"=(the value here)")

如果值是一个字符串,你必须使用这些\"而不是引号,除非你把值存储在变量中。