Discuss / Python / 关于__slots__的一点小坑

关于__slots__的一点小坑

Topic source

本来只是想实践一下__slots__的,结果发现一点小坑

首先是正常的猜想:

class Student(object):
    __slots__ = ('age')

class Ming(Student):
    __slots__ = ()

bart = Student()
bart.age = 15 # 正常
bart.score = 99 # 报错

ming = Ming()
ming.age = 16 # 正常
ming.score = 99 # 报错

然后我稍微改了下:

class Student(object):
    __slots__ = ('age', '__name')

    def __init__(self, name):
        self.__name = name

class Ming(Student):
    __slots__ = ()

    def __init__(self, name):
        self.__name = name

bart = Student('lisa') # 正常

ming = Ming('Ming') # 报错,报错???嗯???

报错内容:

AttributeError: 'Ming' object has no attribute '_Ming__name'

这个报错内容很明白了,Ming 没有 __name 这个属性,也就是说 Ming__slots__ 里面并没有拿到 __name

猜想:以双下划线 __ 开头的属性为私有,可能是这个原因导致的这个错误 但是猜想只是猜想,还没找到一个令人信服的答案

然后我在 Ming 对象的 __slots__ 加上了 __name 之后就解决了

另:查阅过程中发现 __slots__ 貌似挺强大的,有兴趣可以查一查

ky倾心

#2 Created at ... [Delete] [Delete and Lock User]

报错了是因为你的 class Ming(Student) 子类里面的 slots = () 是空的啊,说明你不能往这个子类里面加任何属性,你试试别的属性肯定也不行,和私有属性没有关系。

补充:

class Student(object):
    __slots__ = ('age', '__name')

class Ming(Student):
    __slots__ = ()

    def __init__(self, age):
        self.age = age

这样是可行的哦,我这里 __slots__ 为空 tuple 就是想知道他是不是可以从父类全盘继承下来,结果发现其他属性都可以,就这个 __name 不行

双下滑线开头的属性会自动变形

感谢上面的老铁,原来如此!

class Student(object):
    __slots__ = ('age', '__name')

class Ming(Student):
    __slots__ = ()

    def __init__(self, name):
        self._Student__name = name

ming = Ming('name') # 正确

ky倾心

#6 Created at ... [Delete] [Delete and Lock User]

class Student(object): slots = ('age', 'name') def init(self, name): self.name = name class Ming(Student): slots = () def init(self, name): self.name = name class Li(Student): slots = ('name') def init(self, name): self.__name = name

dir(Student) ['_Studentname', 'class', 'delattr', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'slots', 'str', 'subclasshook', 'age'] dir(Ming) ['_Studentname', 'class', 'delattr', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'slots', 'str', 'subclasshook', 'age'] dir(Li) ['_Liname', '_Studentname', 'class', 'delattr', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'slots', 'str', 'subclasshook', 'age']

恩,我也刚刚发现。。。

GOGOGO-枼子

#7 Created at ... [Delete] [Delete and Lock User]

很棒,顺便复习了下

你可以尝试一下这样定义: class Student(object): slots = ('age', '__name')

    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self, name):
        self.__name = name


class Ming(Student):
    __slots__ = ()

    def __init__(self, name):
        self.set_name(name)


bart = Student('lisa')

ming = Ming('Ming')

print(bart.get_name())
print(ming.get_name())

青铜神裔

#9 Created at ... [Delete] [Delete and Lock User]

双下划线声明这是一个私有属性,python编译器会将其变形为_类名__属性,在这里就是将__name变为_Student__name,所以子类继承的__slots__为age和_Student__name。 在创建一个子类对象时,以你的代码会试图创建一个_Ming__name,这是不被__slots__允许的

__变形后的变量最好不要用 _类名__变量,因为老师说不同的编辑器变形不一样,即使是这样,在两个类中写相同的__name最后结果一定是不一样的,所以要么起了__这样的名字就别让别的类用,要么就别起这样的名字。


  • 1
  • 2

Reply