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

问题描述 投票:0回答:2
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。

python python-3.x python-2.7 dictionary instance-variables
2个回答
1
投票

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


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

© www.soinside.com 2019 - 2024. All rights reserved.