如何创建一个对象并为其添加属性?
- 2025-03-18 08:55:00
- admin 原创
- 46
问题描述:
我想在 Python 中创建一个动态对象,然后为其添加属性。这不起作用:
obj = object()
obj.somefield = "somevalue"
AttributeError:'object' 对象没有属性 'somefield'
有关其不起作用的原因的详细信息,请参阅无法在“对象”类的实例上设置属性。
解决方案 1:
内置函数object
可以实例化,但不能设置任何属性。(我希望它可以,就为了这个目的。)这是因为它没有一个可以__dict__
保存属性的函数。
我通常只是这样做:
class Object(object):
pass
obj = Object()
obj.somefield = "somevalue"
但是请考虑Object
根据该类所保存的数据赋予其一个更有意义的名称。
另一种可能性是使用允许属性访问的子类dict
来获取键:
class AttrDict(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
obj = AttrDict()
obj.somefield = "somevalue"
使用字典实例化对象属性:
d = {"a": 1, "b": 2, "c": 3}
for k, v in d.items():
setattr(obj, k, v)
解决方案 2:
你可以使用我古老的Bunch配方,但如果你不想创建“bunch 类”,Python 中已经有一个非常简单的类——所有函数都可以具有任意属性(包括 lambda 函数)。因此,以下方法有效:
obj = lambda: None
obj.somefield = 'somevalue'
与古老的菜谱相比,清晰度的降低是否Bunch
可以接受,这是一个风格决定,我当然会把它留给你来决定。
解决方案 3:
types.SimpleNamespace
Python 3.3+ 中有一个类:
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
也许也值得一看。
解决方案 4:
您也可以直接使用类对象;它会创建一个命名空间:
class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')
解决方案 5:
该mock
模块基本上就是为此制作的。
import mock
obj = mock.Mock()
obj.a = 5
解决方案 6:
有几种方法可以实现此目标。基本上,您需要一个可扩展的对象。
obj = type('Test', (object,), {})
obj.b = 'fun'
obj = lambda:None
obj.b = 'fun'
class Test:
pass
obj = Test()
obj.b = 'fun'
解决方案 7:
现在您可以这样做(不确定这是否与 evilpie 的答案相同):
MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42
解决方案 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']
解决方案 9:
正如文档所述:
注意:
object
没有,所以不能将任意属性分配给类的实例。__dict__
`object`
您可以只使用虚拟类实例。
解决方案 10:
这些解决方案在测试过程中非常有用。基于其他人的答案,我在 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
解决方案 11:
如果我们可以在创建嵌套对象之前确定并聚合所有属性和值,那么我们就可以创建一个在创建时采用字典参数的新类。
# 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')
解决方案 12:
要从字典创建对象:
class Struct(object):
def __init__(self, d):
for key in d.keys():
self.__setattr__(key, d[key])
用法:
>>> obj = Struct({'a': 1, 'b': 2})
>>> obj.a
1
解决方案 13:
您正在使用哪些对象?刚刚用示例类尝试了一下,效果很好:
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 中向对象添加属性?
解决方案 14:
我认为最简单的方法是通过收藏模块。
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:
如果你正在寻找链式分配,来执行诸如 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
,并为其分配结束属性。
解决方案 16:
你可以使用Alex Martelli 的经典Bunch
类。我最喜欢的类是
class Bunch(dict):
def __init__(self, **kwds):
self.update(kwds)
self.__dict__ = self
与此处的其他答案相比,此解决方案允许您以表达式形式构建这样的内联类:
map_data = Bunch(
directions=[d for d in parsed_data.directions],
connections={c.start: Bunch(L=c.left, R=c.right) for c in parsed_data.connections})
print(map_data)
而且,因为Bunch
是,所以dict
这会打印出一些好的东西!
{'directions': ['R', 'L'], 'connections': {'AAA': {'L': 'BBB', 'R': 'CCC'}, 'BBB': {'L': 'DDD', 'R': 'EEE'}, 'CCC': {'L': 'ZZZ', 'R': 'GGG'}, 'DDD': {'L': 'DDD', 'R': 'DDD'}, 'EEE': {'L': 'EEE', 'R': 'EEE'}, 'GGG': {'L': 'GGG', 'R': 'GGG'}, 'ZZZ': {'L': 'ZZZ', 'R': 'ZZZ'}}}
相比之下,自定义Object
类(例如当前的最佳答案)打印的内容不太好看:
<__main__.Object object at 0x7025cae62b90>
事实上,你可以将其用作Bunch
表达式,同时也允许你将其用作列表或字典理解的一部分,如上所述:
connections={c.start: Bunch(L=c.left, R=c.right) for c in parsed_data.connections})`
使用这里发布的任何其他解决方案来实现这一点都非常困难。
您也可以直接从字典构造这样的对象:
my_dict = {'directions': 'LRLRLL', 'connections': []}
map_data = Bunch(**my_dict)
print(map_data)
与其他已发布的解决方案相比,此解决方案的另一大优势是,您的对象既是字典,又是对象。这意味着:
如果您现有的代码使用字典语法(
map_data['directions']
),您可以迁移到Bunch
,并逐步更新现有代码。调试太棒了!你可以打印、漂亮打印、遍历键/值,以及你想用字典做的一切!
解决方案 17:
虽然已经很晚了,但这是我对一个对象的看法,这个对象恰好保存了应用程序中的一些有用路径,但你可以将它调整为任何你想要的信息,你可以使用 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')
解决方案 18:
di = {}
for x in range(20):
name = '_id%s' % x
di[name] = type(name, (object), {})
setattr(di[name], "attr", "value")
解决方案 19:
我看到的另一种方式是这样的:
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)
扫码咨询,免费领取项目管理大礼包!