如何向python中的任意对象添加属性?

2024-10-01 09:28:18 发布

您现在位置:Python中文网/ 问答频道 /正文

对于我正在处理的项目,我希望能够将名称与对象关联起来。我希望这样做的方式是将对象的.name属性设置为我想要的名称。我真正需要的是一个函数,它获取一个对象的实例,并返回在各个方面都相同但带有.name属性的内容。问题是,我不知道对象将提前出现什么类型的数据,所以我不能使用子类化

我尝试过的每一种方法都遇到了问题。尝试直接为其指定.name属性无效,例如:

>>> cats = ['tabby', 'siamese']
>>> cats.name = 'cats'
Traceback (most recent call last):
  File "<pyshell#197>", line 1, in <module>
    cats.name = 'cats'
AttributeError: 'list' object has no attribute 'name'

使用setattr也有同样的问题

我尝试创建一个新类,该类在init上复制实例中的所有属性,并且还有一个.name属性,但这也不起作用。如果我尝试:

class NamedThing:
  def __init__(self, name, thing):
    thing_dict = {#not all types have a .__dict__ method
      name: getattr(thing, name) for name in dir(thing)
    }
    self.__dict__ = thing_dict
    self.name = name

它在dict上复制没有问题,但由于某种原因,除非我直接调用新方法,否则python无法找到它们,因此对象失去了所有功能。例如:

>>> cats = ['tabby', 'siamese']
>>> named_thing_cats = NamedThing('cats', cats)

>>> named_thing_cats.__repr__()#directly calling .__repr__()
"['tabby', 'siamese']"
>>> repr(named_thing_cats)#for some reason python does not call the new repr method
'<__main__.NamedThing object at 0x0000022814C1A670>'

>>> hasattr(named_thing_cats, '__iter__')
True
>>> for cat in named_thing_cats:
    print(cat)
Traceback (most recent call last):
  File "<pyshell#215>", line 1, in <module>
    for cat in named_thing_cats:
TypeError: 'NamedThing' object is not iterable

我还尝试通过直接设置类来设置类型和属性:

class NamedThing:
  def __init__(self, name, thing):
    thing_dict = {#not all types have a .__dict__ method
      name: getattr(thing, name) for name in dir(thing)
    }
    self.__class__ = type('NamedThing', (type(thing),), thing_dict)
    self.name = name

但这会遇到一个问题,这取决于事物的类型:

>>> cats = ['tabby', 'siamese']
>>> named_thing_cats = NamedThing('cats', cats)
Traceback (most recent call last):
  File "<pyshell#217>", line 1, in <module>
    named_thing_cats = NamedThing('cats', cats)
  File "C:/Users/61490/Documents/Python/HeirachicalDict/moduleanalyser.py", line 12, in __init__
    self.__class__ = type('NamedThing', (type(thing),), thing_dict)
TypeError: __class__ assignment: 'NamedThing' object layout differs from 'NamedThing'

我真的被困住了,帮忙会很好的


Tags: 对象nameinselffor属性calldict
3条回答

为什么不使用yield from创建一个__iter__魔术方法呢:

class NamedThing():
    def __init__(self, name, thing):
        self.thing = thing
        self.name = name
    def __iter__(self):
        yield from self.thing

cats = ['tabby', 'siamese']
named_thing_cats = NamedThing('cats', cats)
for cat in named_thing_cats:
    print(cat)

产出

tabby
siamese

您需要的是对象代理。这是一些非常复杂的东西,因为您正在进入python的数据模型,并以有趣的方式操作一些非常基本的dunder(双下划线)方法

class Proxy:

    def __init__(self, proxied):
        object.__setattr__(self, '_proxied', proxied)

    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self, name)
        except AttributeError:
            p = object.__getattribute__(self, '_proxied')
            return getattr(p, name)
        
    def __setattr__(self, name, value):
        p = object.__getattribute__(self, '_proxied')
        if hasattr(p, name):
            setattr(p, name, value)
        else:
            setattr(self, name, value)
        
    def __getitem__(self, key):
        p = object.__getattribute__(self, '_proxied')
        return p[key]
        
    def __setitem__(self, key, value):
        p = object.__getattribute__(self, '_proxied')
        p[key] = value
        
    def __delitem__(self, key):
        p = object.__getattribute__(self, '_proxied')
        del p[key]

这里发生的最明显的事情是,在内部,这个类必须使用dunders的object实现来避免无限递归。这样做的目的是保存对代理对象的引用,然后如果您尝试获取或设置属性,它将检查代理对象,如果代理对象具有该属性,它将使用该属性,否则它将在自身上设置该属性。对于索引,就像列表一样,它直接作用于代理对象,因为代理本身不允许索引

如果您需要在生产中使用它,那么您可能应该查看一个名为wrapt的包

这行吗

class Thingy(list):
    def __init__(self, name, thing):
        list.__init__(self, thing)
        self.name = name

cats = Thingy('cats', ['tabby', 'siamese'])

print(cats.name) # shows 'cats'

for cat in cats:
    print(cat) # shows tabby, siamese

或者你可以:

class Thingy:
    def __init__(self, name, thing):
        self.thing = thing
        self.name = name

相关问题 更多 >