内置在__dict__中的是返回属性的名称,类名作为前缀

时间:2018-03-03 07:52:15

标签: python python-3.x python-2.7 dictionary instance-variables

class Enrollment(object):

    def __init__(self,enrollmentId=None, enrollmentReference=None):
        self.enrollmentId = enrollmentId
        self.enrollmentReference = enrollmentReference

    @property
    def enrollmentId(self):
        return self.__enrollmentId

    @enrollmentId.setter
    def enrollmentId(self, enrollmentId):
        self.__enrollmentId = enrollmentId

    @property
    def enrollmentReference(self):
        return self.__enrollmentReference

    @enrollmentReference.setter
    def enrollmentReference(self, enrollmentReference):
        self.__enrollmentReference = enrollmentReference

如果我现在尝试打印上述类的属性:

print(Enrollment().__dict__)

它打印前缀为类名的属性,如下所示:

{'_Enrollment__enrollmentId': None, '_Enrollment__enrollmentReference': None}

注意:如果我将对象删除为超类,则一切正常并且正确打印属性,如下所示:

{'enrollmentId': None, 'enrollmentReference': None}

我一直在我身边缠绕了2天,没有运气。 无法理解为什么类名称以属性为前缀。我需要将Enrollment对象序列化为JSON。

2 个答案:

答案 0 :(得分:1)

在类定义中,Python将__x转换为_classname__x。这称为name mangling。它的目的是支持类本地引用,以便子类不会无意中破坏父类的内部逻辑。

答案 1 :(得分:0)

原因

这是因为Python的name mangling类属性名称以__开头,后缀最多只有一个_。这表明这些属性的隐私更加严格。

注意:这仍然是一种启发式方法,不应该被用于访问预防。

来自文档:

  

__spam形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上用_classname__spam替换,其中classname是当前的类名,其中前导下划线被剥离。

class A:
    def __foo_(self): pass

print(vars(A))

输出

{'__module__': '__main__', '_A__foo_': <function A.__foo_ at 0x1118c2488>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

请注意,__foo_已被误导为_A__foo_

用途

为什么这会有用?那么来自文档的例子非常引人注目:

  

名称修改有助于让子类覆盖方法而不破坏类内方法调用。例如:

class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)

tldr

阅读the docs on name mangling