Python 2.7:object.\uuu setattr\uuuu在引擎盖下做什么?

Python 2.7:object.\uuu setattr\uuuu在引擎盖下做什么?,python,python-2.7,class,attributes,python-internals,Python,Python 2.7,Class,Attributes,Python Internals,在Python 2.7中,我可以声明一个新样式的类,并使用对象设置属性 class A (object): def __init__ (self): object.__setattr__(self, 'foo', 'bar') A().foo # 'bar' 但是,这在旧式类中不起作用: class B: def __init__ (self): object.__setattr__(self, 'foo', 'bar') B().foo

在Python 2.7中,我可以声明一个新样式的类,并使用
对象设置属性

class A (object):
    def __init__ (self):
        object.__setattr__(self, 'foo', 'bar')

A().foo # 'bar'
但是,这在旧式类中不起作用:

class B:
    def __init__ (self):
        object.__setattr__(self, 'foo', 'bar')

B().foo
TypeError:无法将此设置属性应用于实例对象

我知道老式的类不支持这种行为,但我不知道为什么它不起作用

当我调用
object.\uuuu setattr\uuuuu
一个新样式的类时,引擎盖下面发生了什么事情,而旧样式的类不能这样做


请注意,我并没有将此代码用于任何事情,我只是试图理解它。

对象。

setattr\uuuu
方法包括一个特定的检查,以确保传入的
self
确实是对象(或直接重用相同C函数的另一个对象)的一个子类。该测试不允许传入任何其他内容,包括旧式实例

该检查用于防止对象被用来修改内置类型(在发现者之后称为Carlo Verre hack)

如果没有显式检查(或者编译Python以禁用它),您可以执行以下操作:

>>> object.__setattr__(str, 'lower', str.upper)
>>> "This is why we can't have nice things".lower()
"THIS IS WHY WE CAN'T HAVE NICE THINGS"
看到了,和

旧式实例对象无法通过测试只是一个副作用


请注意,调用
对象的唯一原因是如果您有一个基类实现了一个需要绕过的
\uuuuuu setattr\uuuuuuuuuu
方法。对于旧式实例,您可以只使用
self.\uuuuu dict\uuuu[name]=value

所有旧式实例的类型-不是旧式类,而是类型-是
类型。InstanceType
。此类型用C编写,并实现自己的
\uuuuu setattr\uuuuuu
。Python将拒绝将一种C类型的
\uuu setattr\uuuuuuuu
应用于具有不同C级别
的C类型实例__setattr\uuuuuuuuuuuuuuuuuuu,作为保护C数据结构一致性的安全措施。

对象是新样式类的基础,因此不,您不能使用
对象。\uuuuuAttr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc>用于非继承自该基础的实例。@MartijnPieters我不明白请注意,我知道只有在非常特殊的情况下才会使用object。uuuu setattr_uuuuu而不是setattr。请告诉我们,在什么情况下您不想使用
setattr()
此处?@MartijnPieters请查看。您也可以找到。如果您不继承
对象
,则一种情况不适用。例外情况是,MRO中的一个中间类被跳过。然而,C数据结构在此处是相同的;对于旧式属性,没有可以连接到
集中的描述符__
无论如何,设置属性总是一个
\uuuu dict\uuuu[attrname]=attrvalue
操作。@MartijnPieters:它们实际上并不完全相同-例如,InstanceType不提供元数据
对象。\uuuuu setattr\uuuuuu
首先需要定位实例的
\uu dict\uuuuu
偏移量。没错,一个实例在\udict
中有
,另一个是
tp dictoffset
偏移量插槽。不过,可以在内部进行抽象处理。这是一个很好的答案,谢谢。从技术上讲,我看不出这个调用会失败的任何原因。现在我明白了。当然,您仍然可以执行
gc.get\u referents(str.\u dict\uuu)[0]['lower']=str.upper
来生成
str.lower
大写的东西,所以如果你真的想使用内置类型还是很容易的。@user2357112:是的,还有其他漏洞需要利用,也许这些漏洞也应该被关闭。想把它放到开发列表中,看看它是否值得关闭吗?@user2357112:事实上,就是这样e对我不起作用,至少在2.7中不起作用。在3.6中,它会导致一个segfault!@MartijnPieters:你可以对比看你是否做了与我不同的事情。