ChatGPT解决这个技术问题 Extra ChatGPT

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

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

“没有工作”是什么意思?我认为它引发了 AttributeError 异常,对吧?
是的。 “object”对象没有属性“somefield”
你为什么做这个?一个通用的“对象”没有实际意义。你正在创造的东西的意义是什么?为什么它不是一个适当的类或命名元组?
该示例对我来说不是最小且令人困惑的,或者我只是不明白为什么您不使用某些 a = object() 而您需要 obj.a = object()。我再次谈论这个例子,在你的实际代码中,一个对象内的一个对象可能是有用的。

F
FogleBird

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

我通常只是这样做:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

如果可以,我会给 Object 类起一个更有意义的名称,具体取决于我放入其中的数据类型。

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

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

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

可以被实例化,只是一旦完成就不能用于任何有用的事情。 foo = object() 有效,但你不能用它做很多事情
你好。感谢你的回答。我已经更新了我上面的问题。见编辑。你知道这个问题的答案吗?
抱歉,我仍然想在对象上设置它。见上面的更新。
我真的很喜欢你的回答,我想我将来会倾向于这个方向。除了这个非常简单、易于理解和可读的方法之外,我在这篇文章中使用了所有其他内容。使用 type.... 或 lambda 从来都不是我的最爱,就像我的代码中的文本呕吐一样。但是这个想法非常适合使用对象来保存属性。当我看到 lambda 时,让代码更具可读性 b/c 我将阅读速度减慢到 25%,而你的方式完全有意义!谢谢。
很好的答案,我唯一改变的是使用 Struct 作为类的名称,以使其更明显。为我节省了大量的输入 [""],干杯!
A
Alex Martelli

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

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

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


在某些情况下,考虑 lambda 模式是否适合您的用例可能会让您意识到,您最初认为是数据的东西实际上更像是一个函数——或者,无论如何,一个函子。
@naught101,函数是一个对象,在 Python 中,所以你的反对是深不可测的。
@naught101,避免创建新类型(重用现有类型)并不复杂,它简化了。现在可能实际上更喜欢 from argparse import Namespace 虽然我希望它存在于其他地方 *例如,collection) - 再次重用现在存在的类型,只是一个更好的类型,并且仍然避免创建新类型。但是,那时它不存在:-)。
请参阅“JF Sebastian”下面关于类型模块中的 SimpleNamespace 的答案。如果您的 python 版本支持它,这是最好的解决方案(并且正是 SimpleNamespace 的设计目的)
@AlexMartelli 除了动态地将更多属性添加到某个恰好是可调用对象的对象上,这与 lambda 演算无关,而且绝对是“hacky”——滥用一些无意成为您的字典的随机对象,而只是所以碰巧工作。并不是说我不喜欢 lambda 演算。我真的。
j
jfs

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 usagepydantic may be worth a look too


如果您需要适用于 Python 2.7 的内容,也可以尝试 argparse.Namespace
同意 - 我很好奇这里是否有缺点,但这是一个非常方便的 python 3.3+ 可供性。
该死!这在 2.7 上不可用?
@Roel attrs 包支持 Python 2.7
这对我来说似乎比 unittest.mock 更好;后者有点太重了,更具延展性。使用模拟对象,简单地分配给一个属性就会让它出现; SimpleNamespace 会抵制这种情况。
D
Dunatotatos

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

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

缺点是这是一个外部依赖
unittest.Mock 是 Python 3.3 (docs.python.org/3/library/unittest.mock.html) 以来标准库的一部分
我认为取决于您的代码的使用情况。如果它是生产代码,我不想在其中添加一些 mock。只是让我觉得很奇怪。
M
MD. Khairul Basar

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

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

我不明白为什么这不是最佳答案?
简单有效👍
m
mbarkhau

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

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

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

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

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

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

@evilpie 的答案直接在 MyObject (类)上设置属性,而不是像你这样的实例。
E
Ellis Percival

试试下面的代码:

$ 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 显然它创建了一个新的 Class(object) ,它是一个具有对象属性的空类,并将属性存储在类中。这甚至比安装更多模块或依赖 lambdas 更好。
不知道为什么这没有更多的赞成票。是否有理由不将其用于基本容器类?似乎在 Python 2.7、2.6 和 3.4 中运行良好
那么这如何设置名称包含在单独变量中的属性的值呢?
S
SilentGhost

作为docs say

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

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


R
Robpol86

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

H
HarlemSquirrel

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

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

C
Community

您正在使用哪些对象?刚刚使用示例类进行了尝试,并且效果很好:

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?


bc 设置为 object() 不是定义的类
P
Pjl

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

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

P
Paul Whipp

到了今天晚些时候,但这是我的 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'))。


W
Weilory

如果你正在寻找链式分配,做诸如 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 传递,并为其分配 end 属性。


V
Vinsplayer

这工作得很好:

    exec("obj.a."+p)

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

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

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


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

l
leota

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

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 this di[name].append([at,cmds.getAttr(name+'.'+at)[0]])
这增加了一个非常大的非标准依赖项,而简单的 class a: pass 提供了所需的所有功能。