Python类开发报错:'RestaurantReview'对象无'_RestaurantReview__name'属性排查
你遇到的这个'RestaurantReview' object has no attribute '_RestaurantReview__name'错误,核心原因是Python的**名称修饰(name mangling)**机制在搞鬼,我来给你拆解清楚:
问题根源
Python中,以双下划线__开头的属性是私有属性,Python会自动把这类属性重命名为_类名__属性名的格式。比如你在Review类里定义的__name,实际会被转换成_Review__name,而不是_RestaurantReview__name。
当你在子类RestaurantReview里直接写self.__name时,Python会去寻找_RestaurantReview__name这个属性,但这个属性根本不存在——父类的私有属性是_Review__name,所以就会抛出找不到属性的错误。另外,如果你的RestaurantReview子类没有调用父类的__init__方法,那父类的私有属性甚至都没被初始化,自然也会找不到。
具体解决方案
根据你的代码,我给你两种可行的解决方式:
方案1:使用父类提供的getter方法(推荐,符合封装原则)
你的Review类已经定义了get_name()、get_date()这些getter方法,子类直接调用这些方法就能获取父类的私有属性,不需要直接访问私有变量。同时记得在子类构造函数里调用父类的__init__来初始化属性:
class Review: def __init__(self, nm, dt, strs): self.__name = nm self.__date = dt self.__stars = strs def set_name(self, name): self.__name = name def set_date(self, date): self.__date = date def set_stars(self,stars): self.__stars = stars def get_name(self): return self.__name def get_date(self): return self.__date def get_stars(self): return self.__stars # 补充你没写完的getter class RestaurantReview(Review): def __init__(self, nm, dt, strs, restaurant_name): # 必须调用父类构造,初始化父类的私有属性 super().__init__(nm, dt, strs) self.__restaurant = restaurant_name def get_full_review(self): # 用父类的getter方法获取属性 return f"{self.get_name()} reviewed {self.__restaurant} on {self.get_date()} with {self.get_stars()} stars"
方案2:将父类属性改为“受保护”的单下划线格式
如果希望子类能直接访问这些属性,可以把父类里的双下划线改成单下划线_——这是Python里约定俗成的“受保护”属性,子类可以访问,同时提醒外部代码不要直接修改:
class Review: def __init__(self, nm, dt, strs): self._name = nm # 单下划线,受保护属性 self._date = dt self._stars = strs # 可以保留getter/setter,也可以直接让子类访问属性 def set_name(self, name): self._name = name def get_name(self): return self._name def set_date(self, date): self._date = date def get_date(self): return self._date def set_stars(self,stars): self._stars = stars def get_stars(self): return self._stars class RestaurantReview(Review): def __init__(self, nm, dt, strs, restaurant_name): super().__init__(nm, dt, strs) self.__restaurant = restaurant_name def get_full_review(self): # 直接访问父类的受保护属性 return f"{self._name} reviewed {self.__restaurant} on {self._date} with {self._stars} stars"
总结
- 双下划线开头的属性是真正的私有属性,子类无法直接访问,只能通过父类提供的公共方法(比如getter/setter)操作
- 单下划线开头的属性是受保护属性,子类可以访问,但这只是代码约定,Python不会强制限制
- 子类必须调用父类的
__init__方法,才能确保父类的属性被正确初始化
内容的提问来源于stack exchange,提问作者chris madden

