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
相关产品推荐
相关产品推荐

