如何将属性添加到任意对象 python?
How to add attribute to arbitrary object python?
对于我正在进行的项目,我希望能够将名称与对象相关联。我想这样做的方法是将对象的 .name 属性设置为我想要的名称。我真正需要的是一个接受对象实例的函数,以及 returns 在各个方面都相同但具有 .name 属性的东西。问题是我提前不知道对象会是什么类型的数据,所以不能用subclassing 例如
我试过的每一种方法都遇到了问题。试图直接给它一个 .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也有同样的问题
我尝试创建一个新的 class,它在 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来设置类型和属性:
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'
我真的卡住了,帮助会很好
这个有用吗?
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
为什么不直接用 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 的数据模型并以有趣的方式操作一些非常基本的双下划线(双下划线)方法
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]
这里发生的最明显的事情是在内部这个 class 必须使用 dunders 的 object
实现以避免无限递归。它所做的是保存对代理对象的引用,然后如果您尝试获取或设置属性,它将检查代理对象,如果代理对象具有该属性,则使用它,否则它会在自身上设置属性。对于索引,就像列表一样,它只是直接作用于代理对象,因为代理本身不允许索引。
如果您需要在生产中使用它,有一个名为 wrapt 的包您应该看看。
对于我正在进行的项目,我希望能够将名称与对象相关联。我想这样做的方法是将对象的 .name 属性设置为我想要的名称。我真正需要的是一个接受对象实例的函数,以及 returns 在各个方面都相同但具有 .name 属性的东西。问题是我提前不知道对象会是什么类型的数据,所以不能用subclassing 例如
我试过的每一种方法都遇到了问题。试图直接给它一个 .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也有同样的问题
我尝试创建一个新的 class,它在 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来设置类型和属性:
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'
我真的卡住了,帮助会很好
这个有用吗?
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
为什么不直接用 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 的数据模型并以有趣的方式操作一些非常基本的双下划线(双下划线)方法
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]
这里发生的最明显的事情是在内部这个 class 必须使用 dunders 的 object
实现以避免无限递归。它所做的是保存对代理对象的引用,然后如果您尝试获取或设置属性,它将检查代理对象,如果代理对象具有该属性,则使用它,否则它会在自身上设置属性。对于索引,就像列表一样,它只是直接作用于代理对象,因为代理本身不允许索引。
如果您需要在生产中使用它,有一个名为 wrapt 的包您应该看看。