首页 文章

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

提问于
浏览
232

我想在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 的值设置属性?

16 回答

  • -2

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

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

    这些解决方案在测试期间非常有用 . 基于其他人的答案我在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
    
  • 6

    你使用的是哪些物品?刚尝试使用示例类,它运行良好:

    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 .

    更新:从评论中重复:Why can't you add attributes to object in python?

  • 0

    你可以使用我古老的Bunch食谱,但如果你不想制作一个"bunch class",Python中已经存在一个非常简单的 - 所有函数都可以有任意属性(包括lambda函数) . 所以,以下工作:

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

    与古老的 Bunch 食谱相比,是否会失去清晰度是一种风格决定,我当然会留给你 .

  • 0

    内置的 object 可以实例化,但可以 __dict__ 来保存属性 .

    我通常只是这样做:

    class Object(object):
        pass
    
    a = Object()
    a.somefield = somevalue
    

    当我可以的时候,我给 Object 类一个更有意义的名字,这取决于我放入的数据类型 .

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

    Edit :对于您的问题的补充,使用 setattr 就可以了 . 你不能在 object() 实例上使用 setattr .

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

    types.SimpleNamespace class in 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 -- Data Classes提出了一个可变的替代方案 .

    要获得更丰富的功能,您可以try attrs package . 见an example usage .

  • 2

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

    obj.a = type('Test', (object,), {})  
    obj.a.b = 'fun'  
    
    obj.b = lambda:None
    
    class Test:
      pass
    obj.c = Test()
    
  • 7

    现在你可以做(不确定它是否与evilpie一样):

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

    mock 模块基本上是为此而制作的 .

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

    请尝试以下代码:

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

    as docs say

    注意:对象没有__dict__,因此您无法将任意属性分配给对象类的实例 .

    你可以使用虚拟类实例 .

  • 90

    在这一天晚些时候来到这里,但是我的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))
    

    这很酷,因为现在:

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

  • 15

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

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

    我们还可以允许关键字参数 . 见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')
    
  • 30
    di = {}
    for x in range(20):
        name = '_id%s' % x
        di[name] = type(name, (object), {})
        setattr(di[name], "attr", "value")
    
  • 268

    我这样看的其他方式:

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

    这一切都在docs .

    TLDR:你需要断言mock的 return_value 属性,其余的是'Magic' .

    例:

    SomeConstructor = MagicMock()
    
    SomeConstructor.return_value. \
        some_class_method.assert_called_once_with('cool!')
    
      SomeConstructor.return_value. \
            some_inner_property. \
            some_inner_method.assert_called_once_with('super cool!')
    

相关问题