简体   繁体   English

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

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

I want to create a dynamic object (inside another object) in Python and then add attributes to it.我想在 Python 中创建一个动态 object (在另一个对象内),然后为其添加属性。

I tried:我试过了:

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

but this didn't work.但这没有用。

Any ideas?有任何想法吗?

edit:编辑:

I am setting the attributes from a for loop which loops through a list of values, eg我正在从循环值列表的for循环中设置属性,例如

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

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

In the above example I would get obj.a.attr1 , obj.a.attr2 , obj.a.attr3 .在上面的例子中,我会得到obj.a.attr1obj.a.attr2obj.a.attr3

I used the setattr function because I didn't know how to do obj.a.NAME from a for loop.我使用了setattr function 因为我不知道如何从for循环中执行obj.a.NAME

How would I set the attribute based on the value of p in the example above?如何根据上面示例中的p值设置属性?


For details on why it doesn't work, see Can't set attributes on instance of "object" class .有关它为什么不起作用的详细信息,请参阅Can't set attributes on instance of "object" class

The built-in object can be instantiated but can't have any attributes set on it.内置object可以实例化,但不能在其上设置任何属性。 (I wish it could, for this exact purpose.) It doesn't have a __dict__ to hold the attributes. (为了这个确切的目的,我希望它可以。)它没有__dict__来保存属性。

I generally just do this:我通常只是这样做:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

When I can, I give the Object class a more meaningful name, depending on what kind of data I'm putting in it.如果可以,我会给Object类一个更有意义的名称,这取决于我放入的数据类型。

Some people do a different thing, where they use a sub-class of dict that allows attribute access to get at the keys.有些人做不同的事情,他们使用dict的子类,允许属性访问来获取键。 ( d.key instead of d['key'] ) d.key而不是d['key']

Edit : For the addition to your question, using setattr is fine.编辑:对于您的问题,使用setattr很好。 You just can't use setattr on object() instances.您不能在object()实例上使用setattr

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

You could use my ancient Bunch recipe, but if you don't want to make a "bunch class", a very simple one already exists in Python -- all functions can have arbitrary attributes (including lambda functions).您可以使用我古老的Bunch配方,但如果您不想创建一个“bunch 类”,Python 中已经存在一个非常简单的类——所有函数都可以具有任意属性(包括 lambda 函数)。 So, the following works:因此,以下工作:

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

Whether the loss of clarity compared to the venerable Bunch recipe is OK, is a style decision I will of course leave up to you.与古老的Bunch食谱相比,清晰度的降低是否可以接受,这是我当然会留给您的风格决定。

There is types.SimpleNamespace class in Python 3.3+ : 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 could be used for immutable objects. collections.namedtupletyping.NamedTuple可用于不可变对象。 PEP 557 -- Data Classes suggests a mutable alternative. PEP 557——数据类建议了一个可变的替代方案。

For a richer functionality, you could try attrs package .对于更丰富的功能,您可以尝试attrs package See an example usage .请参阅示例用法

The mock module is basically made for that. mock模块基本上就是为此而制作的。

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

There are a few ways to reach this goal.有几种方法可以达到这个目标。 Basically you need an object which is extendable.基本上你需要一个可扩展的对象。

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

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

You can also use a class object directly;也可以直接使用类对象; it creates a namespace:它创建了一个命名空间:

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

Now you can do (not sure if it's the same answer as evilpie):现在你可以做(​​不确定它是否与 evilpie 相同的答案):

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

Try the code below:试试下面的代码:

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

as docs say :正如文档所说

Note : object does not have a __dict__ , so you can't assign arbitrary attributes to an instance of the object class.object没有一个__dict__ ,所以你不能指定任意属性的实例object类。

You could just use dummy-class instance.你可以只使用 dummy-class 实例。

These solutions are very helpful during testing.这些解决方案在测试过程中非常有用。 Building on everyone else's answers I do this in Python 2.7.9 (without staticmethod I get a TypeError (unbound method...):基于其他人的答案,我在 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

If we can determine and aggregate all the attributes and values together before creating the nested object, then we could create a new class that takes a dictionary argument on creation.如果我们可以在创建嵌套对象之前确定并将所有属性和值聚合在一起,那么我们可以创建一个在创建时接受字典参数的新类。

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

We can also allow keyword arguments.我们也可以允许关键字参数。 See this post .看到这个帖子

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

Which objects are you using?您在使用哪些对象? Just tried that with a sample class and it worked fine:刚刚用一个示例类尝试过,效果很好:

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

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

And I got 123 as the answer.我得到了123作为答案。

The only situation where I see this failing is if you're trying a setattr on a builtin object.我看到这种失败的唯一情况是,如果您在内置对象上尝试setattr

Update: From the comment this is a repetition of: Why can't you add attributes to object in python?更新:从评论中,这是重复: 为什么不能在 python 中向对象添加属性?

Coming to this late in the day but here is my pennyworth with an object that just happens to hold some useful paths in an app but you can adapt it for anything where you want a sorta dict of information that you can access with getattr and dot notation (which is what I think this question is really about):今天晚些时候,但这是我的 pennyworth 对象,它恰好在应用程序中保存了一些有用的路径,但您可以将其调整为任何您想要某种信息字典的地方,您可以使用 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))

This is cool because now:这很酷,因为现在:

In [1]: x_path.projects
Out[1]: '/home/x/projects'

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

So this uses the function object like the above answers but uses the function to get the values (you can still use (getattr, x_path, 'repository') rather than x_path('repository') if you prefer).因此,这使用与上述答案类似的函数对象,但使用该函数来获取值(如果您愿意(getattr, x_path, 'repository')您仍然可以使用(getattr, x_path, 'repository')而不是x_path('repository') )。

I think the easiest way is through the collections module.我认为最简单的方法是通过 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

问题 - 为什么不改用字典?

obj = { "a": { "somefield" : "somevalue" } }

if you are looking for chain assignment, to do things such as django model template abstract attribute assigning:如果你正在寻找链式分配,做诸如 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'}

which allows you to pass model as a target , and assign end attribute to it.它允许您将模型作为target传递,并为其分配 end 属性。

This works just fine:这工作得很好:

    exec("obj.a."+p)

If you want to set the attribute to some value, do this:如果要将属性设置为某个值,请执行以下操作:

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

For the value to be a string you will have to use these \" instead of quotation marks unless you have the value stored in a variable.对于要成为字符串的值,您必须使用这些 \" 而不是引号,除非您将值存储在变量中。

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

Other way i see, this way:我看到的其他方式,这样:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM