Python 对于私有属性,setattr和assignment不等效

Python 对于私有属性,setattr和assignment不等效,python,python-3.x,attributes,cpython,setattr,Python,Python 3.x,Attributes,Cpython,Setattr,使用CPython 3.4.3(GCC 5.3.1 20160406(Red Hat 5.3.1-6)),在私有属性上使用setattr和getattr时,我遇到了一个非常奇怪的行为: class Short: def __init__(self): setattr(self, '__myatt', None) self.__myatt = 42 assert getattr(self, '__myatt') is None Short()

使用CPython 3.4.3(GCC 5.3.1 20160406(Red Hat 5.3.1-6)),在私有属性上使用
setattr
getattr
时,我遇到了一个非常奇怪的行为:

class Short:
    def __init__(self):
        setattr(self, '__myatt', None)
        self.__myatt = 42
        assert getattr(self, '__myatt') is None
Short()
最后一段代码从不引发任何
断言错误
,尽管在断言语句之前有矫揉造作的行为。 但是,使用
myattr
而不是
\uuu myatt
的相同代码会正确引发异常:

class Short:
    def __init__(self):
        setattr(self, 'myatt', None)
        self.myatt = 42
        assert getattr(self, 'myatt') is 42
Short()

以下是两种情况(私有与公共)的比较,以及注释和断言,表明3种访问方式中有2种没有返回预期值:

class Private:

    def __init__(self):
        print('############### PRIVATE ###############')
        print('Assign __fa with None using setattr.')
        setattr(self, '__fa', None)


        print("Set __fa to 42 using regular affectation.")
        new_value = 42
        self.__fa = new_value

        print("\nPrint the new values. Expected to be all 42:")
        print("new value:", new_value)
        print("self.__fa:", self.__fa)
        print("getattr(self, '__fa'):", getattr(self, '__fa'))
        print("self.__dict__['__fa']:", self.__dict__['__fa'])

        assert self.__dict__['__fa'] is None  # this is unexpected
        assert getattr(self, '__fa') is None  # this is unexpected

        print("\nNow modify __fa using setattr")
        # Maintenant, on utilise la notation «équivalente» (d'après la doc)
        setattr(self, '__fa', new_value)

        print("\nPrint the new values. Expected to be all 42:")
        # et tout va bien !
        # WTF !
        print("new value:", new_value)
        print("self.__fa:", self.__fa)
        print("getattr(self, '__fa'):", getattr(self, '__fa'))
        print("self.__dict__['__fa']:", self.__dict__['__fa'])

        assert self.__fa is not None


class Public:

    def __init__(self):
        print('\n############### PUBLIC ###############')
        print('Assign fa with None using setattr.')
        setattr(self, 'fa', None)


        print("Set fa to 42 using regular affectation.")
        new_value = 42
        self.fa = new_value

        print("\nPrint the new values. Expected to be all 42:")
        print("new value:", new_value)
        print("self.fa:", self.fa)
        print("getattr(self, 'fa'):", getattr(self, 'fa'))
        print("self.__dict__['fa']:", self.__dict__['fa'])

        assert self.__dict__['fa'] is not None  # this is expected
        assert getattr(self, 'fa') is not None  # this is expected


Private()
Public()

这是预期的行为吗?为什么以及它的起源是什么?

这是意料之中的。在编译时执行的名称篡改使字符串文本保持不变,因此您应该在
getattr
setattr
hasattr
中明确提供被篡改的名称:

class Short:
    def __init__(self):
        self.__myatt = 42
        # print(getattr(self, '__myatt'))  # Fails with a NameError 
        print(getattr(self, '_{0.__qualname__}__myatt'.format(type(self))))  # Succeeds
现在打印出
42
。类似地,要设置
setattr
hasattr
进行检查,需要提供损坏的名称

这是在一个相关的hasattr中提出的。如果是,则明确表示为预期行为