我想在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函数是因为我不知道如何从obj.a.NAME循环中执行for

我将如何基于p中的值来设置属性上面的例子吗?

评论

你“没用”是什么意思?我认为它引发了AttributeError异常,对吧?

是的'object'对象没有属性'somefield'

你为什么做这个?通用“对象”没有实际含义。您正在创造的东西是什么意思?为什么它不是适当的类或命名元组?

该示例对我来说不是最小且令人困惑的,或者我只是不明白为什么不使用某些=对象()并且需要obj.a = object()。我再次在谈论这个示例,在您的实际代码中,对象内部的对象可能很有用。

#1 楼

您可以使用我古老的Bunch配方,但是如果您不想创建“绑定类”,则Python中已经存在一个非常简单的类-所有函数都可以具有任意属性(包括lambda函数)。因此,下面的作品:与古老的Bunch食谱相比,透明度的降低是否还可以,这是我当然会决定的风格决定。

评论


正如我提到的,@ FogleBird是一种样式决定。一些CS专家培训了例如在Church的lambda演算中,习惯于将函数(lambda)视为所有数据的基本类型(例如,整数23,可以看作等同于lambda:23),因此对于使用lambda的此类专家而言,大概感觉不到像“ hack”。就我个人而言,我不太喜欢Python中的lambda -但这完全是个人喜好问题。

– Alex Martelli
2010年5月13日在16:26

在某些情况下,考虑lambda模式是否适合您的用例可能会使您认识到,您原本认为是数据的东西实际上实际上更像是一个函数,或者无论如何是函子。

–凯尔·斯特兰德(Kyle Strand)
2014年7月30日在20:45



@ naught101,在Python中,函数是对象,因此您的反对是难以置信的。

– Alex Martelli
15年1月26日在6:02

@ naught101,避免了创建新类型(重用现有类型)的复杂性,它简化了。如今,实际上我可能更喜欢使用argparse import命名空间,尽管我希望它可以存在于其他地方(例如collection)-再次重用现在存在的类型,只是一种更好的类型,而仍然避免创建新类型。但是,那时还不存在:-)。

– Alex Martelli
15年1月26日在14:58

有关类型模块中的SimpleNamespace,请参见下面的“ J F Sebastian”中的答案。如果您的python版本支持它,那么这是最好的解决方案(这正是SimpleNamespace的设计目标)

–蒂姆·理查森(Tim Richardson)
16-2-4在23:40



#2 楼

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

我通常只是这样做:

class Object(object):
    pass

a = Object()
a.somefield = somevalue


我会尽可能给Object类一个更有意义的名称,具体取决于我要输入的数据类型。

有些人在不同的地方使用它们dict的子类,允许属性访问获取键。 (用d.key代替d['key']

编辑:对于您的问题,使用setattr很好。您只是不能在setattr实例上使用object()

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


评论


它可以被实例化,一旦完成就不会用于任何有用的事情。 foo = object()可以,但是您不能做很多事

–Daniel DiPaolo
2010年5月13日14:43



你好感谢你的回答。我已经在上面更新了我的问题。看到编辑。你知道答案吗?

–约翰
2010年5月13日下午14:55

抱歉,我仍然想在对象上进行设置。请参阅上面的更新。

–约翰
2010年5月13日15:06

我真的很喜欢您的回答,我认为将来我会朝这个方向发展。除了这种非常简单,可理解和易读的方法外,我已经使用了本文中的所有其他内容。我从来都不喜欢使用type ....或lambda,就像我的代码中的文本呕吐一样。但是,这种想法非常适合使用对象来保存属性。当我看到lambda时,使代码更具可读性b / c,我的阅读速度减慢了25%,而您的方式完全有意义!谢谢。

– Marc
16-10-14在0:31

好的答案,我唯一改变的是使用Struct作为类的名称,以使其更明显。救了我一大堆[[和]],干杯!

– Pragman
16-10-22在14:16



#3 楼

Python 3.3+中有types.SimpleNamespace类:

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


collections.namedtupletyping.NamedTuple可用于不可变对象。 PEP 557-数据类建议使用可变的替代方法。

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

评论


如果您需要适用于Python 2.7的功能,也可以尝试argparse.Namespace类

–罗尔考
16年8月26日在20:09

同意-我很好奇这里是否有缺点,但这是python 3.3+提供的功能,非常方便。

– ghukill
17年7月28日在18:31

该死的!这在2.7上不可用?

– Roel
'18 Sep 11'在8:00

@Roel attrs软件包支持Python 2.7

– jfs
18年9月11日在17:27

对我来说,这似乎比unittest.mock更好。后者有点太重,也更具延展性。对于模拟对象,只需将其赋值给一个属性即可使其变为现实。 SimpleNamespace将抵制这一点。

– jdzions
20-2-4在0:14

#4 楼

mock模块基本上就是为此而制成的。

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


评论


缺点是外部依赖

–甘古尔
17年3月16日在17:17

自Python 3.3(docs.python.org/3/library/unittest.mock.html)以来,unittest.Mock是标准库的一部分。

– illagrenan
17年12月18日在13:03

我认为取决于代码的用法。如果它是生产代码,则我不希望在其中进行模拟。对我来说很奇怪。

–迈克·德·克莱克(Mike de Klerk)
19年2月28日在19:18

#5 楼

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

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

obj.b = lambda:None

class Test:
  pass
obj.c = Test()


评论


obj.a = type('',(),{})

– iman
2014年1月30日15:37



#6 楼

现在,您可以执行操作(不确定答案是否与Evilpie相同):

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


评论


@evilpie的答案直接在MyObject(类)上设置属性,而不是像您的实例一样设置属性。

– jfs
15年11月30日在15:04

#7 楼

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

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


#8 楼

请尝试以下代码:

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


评论


您能解释一下这是什么吗?尽管代码对于解决此问题可能很有用,但对它的解释远不止一个问题。

– DeadChex
15年7月23日在20:52

@DeadChex显然,它将创建一个新的Class(object),这是一个具有对象属性的空类,并将属性存储在该类中。这甚至比安装更多模块或依靠lambda更好。

– m3nda
17年5月15日在23:08

不知道为什么没有更多的投票。是否有理由不将其用于基本容器类?似乎可以在Python 2.7、2.6和3.4中正常工作

–user5359531
17年6月14日在17:21

#9 楼

如文档所述:


注意:object没有__dict__,因此您不能将任意属性分配给object类的实例。


您可以只使用虚拟类实例。

#10 楼

这些解决方案在测试过程中非常有帮助。基于其他人的答案,我在Python 2.7.9中执行此操作(没有静态方法,我得到TypeError(未绑定方法...):

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


#11 楼

您正在使用哪些对象?只是尝试了一个示例类,它运行良好:

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

评论


b.c设置为object()而不是定义的类

–约翰
2010年5月13日在15:08

#12 楼

如果我们可以在创建嵌套对象之前确定所有属性和值并将它们聚合在一起,则可以创建一个在创建时带有字典参数的新类。

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


#13 楼

到今天晚了,这是我的一分钱,它的对象恰好在应用程序中保留了一些有用的路径,但是您可以将其适应于任何您希望通过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'))。

#14 楼

我认为最简单的方法是通过collections模块。
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


#15 楼

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


#16 楼

我以这种方式看到的其他方式:

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)


评论


您可以在名称中添加attr这个di [name] .append([at,cmds.getAttr(name +'。'+ at)[0]])

– Pablo Emmanuel De Leo
16年5月13日在18:08

这增加了非常大的非标准依赖关系,而简单的类a:pass提供了所需的全部功能。

– Alexis Paques
18年6月28日在13:43