You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python双下划线属性触发AttributeError,如何实现对象列表排序?

保留双下划线命名属性并实现Patient对象列表排序

我尝试按姓氏对Patient对象列表排序,代码中使用了双下划线开头的__surname属性,但运行时抛出AttributeError,提示对象没有__surname属性。将属性名改为非双下划线开头(如xyzsurname)后代码可正常运行,想知道如何保留双下划线属性同时实现排序。

原始代码

class Patient:
    def __init__(self, first_name, surname, age, mobile, postcode):
        self.__first_name = first_name
        self.__surname = surname
        self.__doctor = "None"
        self.__age = age
        self.__mobile = mobile
        self.__postcode = postcode
        self.__symptoms = ""
        
    def full_name(self) :
        return "{} {}".format(self.__first_name, self.__surname)
        
    def __str__(self):
        return f'{self.full_name():^20}|{self.__doctor:^6}|{self.__age:^4}|{self.__mobile:^15}|{self.__postcode:^10}'
    
patients = [Patient('Sara','Cath', 20, '07012345678','B1 234'),
            Patient('Mike','Abe', 37,'07555551234','L2 2AB'), 
            Patient('Daivd','Barr', 15, '07123456789','C1 ABC'), 
            Patient('Gerald','Abe', 21, '07012345678','L2 2AB'), 
            Patient('Sara','Abe', 19, '07012345678','L2 2AB'), 
            Patient('Jane','Barr', 35, '07123456789','C1 ABC')]

patients.sort(key=lambda y: y.__surname)
print(patients[0])
print(patients[1])
print(patients[2])
print(patients[3])
print(patients[4])
print(patients[5])
print()
newPat = sorted(patients, key=lambda y: y.__surname)
print(newPat[0])
print(newPat[1])
print(newPat[2])
print(newPat[3])
print(newPat[4])
print(newPat[5])

错误信息

File "c:\users\mundane\downloads\pythonfiles\files\untitled0.py", line 25, in <lambda>
    patients.sort(key=lambda y: y.__surname)

AttributeError: 'Patient' object has no attribute '__surname'

问题原因

Python中,以双下划线__开头的属性会被自动执行名称修饰(name mangling),Python会将__surname重命名为_Patient__surname(格式为_类名__属性名),目的是避免子类意外覆盖父类属性。因此在类外部(比如lambda表达式中)直接访问y.__surname会找不到该属性。


解决方案

方案1:使用名称修饰后的属性名(不推荐)

直接在lambda中使用Python重命名后的属性名_Patient__surname,可以绕过名称修饰限制,但这种写法依赖Python内部实现,可读性差且不符合封装原则,不建议使用。

修改后的排序代码:

patients.sort(key=lambda y: y._Patient__surname)
newPat = sorted(patients, key=lambda y: y._Patient__surname)

方案2:添加获取姓氏的方法(推荐,符合封装)

在Patient类中添加一个公开方法返回姓氏,既保留内部属性封装,又能在外部安全获取属性值。

修改后的Patient类:

class Patient:
    def __init__(self, first_name, surname, age, mobile, postcode):
        self.__first_name = first_name
        self.__surname = surname
        self.__doctor = "None"
        self.__age = age
        self.__mobile = mobile
        self.__postcode = postcode
        self.__symptoms = ""
        
    def full_name(self) :
        return "{} {}".format(self.__first_name, self.__surname)
    
    # 添加获取姓氏的方法
    def get_surname(self):
        return self.__surname
        
    def __str__(self):
        return f'{self.full_name():^20}|{self.__doctor:^6}|{self.__age:^4}|{self.__mobile:^15}|{self.__postcode:^10}'

排序代码改为:

patients.sort(key=lambda y: y.get_surname())
newPat = sorted(patients, key=lambda y: y.get_surname())

方案3:使用@property装饰器(更优雅的封装方式)

通过@property装饰器将姓氏封装为只读属性,外部可以像访问普通属性一样获取,内部依然保留双下划线命名。

修改后的Patient类:

class Patient:
    def __init__(self, first_name, surname, age, mobile, postcode):
        self.__first_name = first_name
        self.__surname = surname
        self.__doctor = "None"
        self.__age = age
        self.__mobile = mobile
        self.__postcode = postcode
        self.__symptoms = ""
        
    def full_name(self) :
        return "{} {}".format(self.__first_name, self.__surname)
    
    # 使用@property装饰器
    @property
    def surname(self):
        return self.__surname
        
    def __str__(self):
        return f'{self.full_name():^20}|{self.__doctor:^6}|{self.__age:^4}|{self.__mobile:^15}|{self.__postcode:^10}'

排序代码改为:

patients.sort(key=lambda y: y.surname)
newPat = sorted(patients, key=lambda y: y.surname)

内容的提问来源于stack exchange,提问作者Tariq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:50:21