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

不使用类外属性实现归并排序的排序键动态切换问题

解决Person类归并排序时的TypeError及封装需求

你遇到的TypeError: 'Person' object is not subscriptable是因为你在lambda里用x[0]这种下标方式访问Person对象,但Person类没有实现__getitem__方法,无法像列表一样通过下标取值。同时你要求不能在Person类外部直接访问其私有属性(_name、_age等),可以通过给Person类提供合法的访问接口来实现需求。

可行方案:通过只读属性暴露排序字段

使用Python的@property装饰器,将私有属性封装成只读的公开属性,这样外部可以通过属性名访问(而非直接访问私有变量),既满足封装要求,又能为排序lambda提供合法的取值方式。

另外,原代码中Person类的__len__方法引用了不存在的self.data,需要修复或移除该方法,否则创建Person对象时会报错。

修改后的完整代码

import numpy as np
from merge_sort import mergesort

NAMES = ["Alice", "Bob", "Charlie", "David", "Eve", "Frank", "Grace", "Hank", "Ivy", "Jack"]

class Person():
    def __init__(self, name, age, height, weight):
        self._name = name
        self._age = age
        self._height = height
        self._weight = weight

    # 修复__len__方法,返回属性数量
    def __len__(self):
        return 4

    def __repr__(self):
        return f"{self._name}, {self._age} years, {self._height} cm, {self._weight} kg\n"

    def __eq__(self, other):
        return (self._age, self._height, self._weight) == (other._age, other._height, other._weight)

    def __lt__(self, other):
        return (self._age, self._height, self._weight) < (other._age, other._height, other._weight)

    def __le__(self, other):
        return (self._age, self._height, self._weight) <= (other._age, other._height, other._weight)

    def __gt__(self, other):
        return (self._age, self._height, self._weight) > (other._age, other._height, other._weight)

    def __ge__(self, other):
        return (self._age, self._height, self._weight) >= (other._age, other._height, other._weight)

    def __int__(self):
        return int(self._age)

    def __float__(self):
        return float(self._age)

    def __str__(self):
        return f"{self._name}, {self._age} years, {self._height} cm, {self._weight} kg"

    # 添加只读属性,封装私有变量
    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    @property
    def height(self):
        return self._height

    @property
    def weight(self):
        return self._weight


def create_persons_list(n=10, sort_key='weight'):
    person_objects = [Person(np.random.choice(NAMES), np.random.randint(18, 101), np.random.randint(150, 201), np.random.randint(45, 101)) for _ in range(n)]
    
    # 根据sort_key使用对应的只读属性
    if sort_key == 'name':
        return mergesort(person_objects, key=lambda x: x.name)
    elif sort_key == 'age':
        return mergesort(person_objects, key=lambda x: x.age)
    elif sort_key == 'height':
        return mergesort(person_objects, key=lambda x: x.height)
    elif sort_key == 'weight':
        return mergesort(person_objects, key=lambda x: x.weight)
    else:
        raise ValueError("Invalid sort_key. Supported values are 'name', 'age', 'height', and 'weight'.")


sorted_persons_by_name = create_persons_list(sort_key='name')
sorted_persons_by_age = create_persons_list(sort_key='age')
sorted_persons_by_height = create_persons_list(sort_key='height')
sorted_persons_by_weight = create_persons_list(sort_key='weight')

print("Sorted by name: \n")
print(sorted_persons_by_name)
print("Sorted by age: \n")
print(sorted_persons_by_age)
print("Sorted by height: \n")
print(sorted_persons_by_height)
print("Sorted by weight: \n")
print(sorted_persons_by_weight)

其他可选方案

  • 添加getter方法:给Person类添加get_name()、get_age()等方法,lambda写成lambda x: x.get_name(),效果和@property类似,只是调用方式不同。
  • 实现__getitem__方法:让Person支持通过键或下标访问属性,比如:
    def __getitem__(self, key):
        if key == 0 or key == 'name':
            return self._name
        elif key == 1 or key == 'age':
            return self._age
        elif key == 2 or key == 'height':
            return self._height
        elif key == 3 or key == 'weight':
            return self._weight
        else:
            raise IndexError("Invalid key for Person")
    
    这样原来的lambda x: x[0]就能正常工作,但需要维护下标和属性的对应关系,不如@property直观。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:09:58