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

问题描述 投票:0回答:19

我想在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.attr1
obj.a.attr2
obj.a.attr3

我使用了

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

如何根据上例中

p
的值设置属性?


有关为什么不起作用的详细信息,请参阅无法在“对象”类的实例上设置属性

python class object attributes
19个回答
455
投票

内置的

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)

260
投票

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

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

与古老的

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


188
投票

Python 3.3+中有

types.SimpleNamespace
:

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

collections.namedtuple
typing.NamedTuple
可用于不可变对象。 PEP 557——数据类提出了一种可变的替代方案。

想要更丰富的功能,您可以尝试

attrs
。请参阅示例用法
pydantic
也可能值得一看


59
投票

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

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

58
投票

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

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

35
投票

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

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

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

25
投票

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

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

22
投票

尝试下面的代码:

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

10
投票

正如文档所说

注意

object
not
__dict__
,所以你不能将任意属性分配给
object
类的实例。

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


4
投票

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

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

3
投票

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

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

1
投票

您使用哪些对象?刚刚尝试了一个示例类,效果很好:

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
投票

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

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

1
投票

如果您正在寻找链分配,可以执行诸如 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'}

它允许您将模型作为

target
传递,并为其分配结束属性。


0
投票

今天晚些时候来到这里,但这是我的便士,它有一个对象,它恰好在应用程序中保存了一些有用的路径,但您可以将其调整为任何您想要的信息字典,您可以使用 getattr 和 dot 访问这些信息符号(这就是我认为这个问题的真正含义):

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


0
投票

从字典创建对象:

class Struct(object):
    def __init__(self, d):
        for key in d.keys():
            self.__setattr__(key, d[key])

用途:

>>> x = Struct({'a': 1, 'b': 2})
>>> x.a
1

-1
投票

这个效果很好:

    exec("obj.a."+p)

如果要将属性设置为某个值,请执行以下操作:

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

对于字符串值,您必须使用这些 \" 而不是引号,除非您将值存储在变量中。


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

-3
投票

我看到的另一种方式,这样:

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)
© www.soinside.com 2019 - 2024. All rights reserved.