【问题标题】:typecast classes in python: how?python中的类型转换类:如何?
【发布时间】:2015-02-18 07:03:07
【问题描述】:

在这里,我试图将社交媒体个人资料模拟为“个人资料”类,其中您有姓名、一群朋友以及添加和删除朋友的能力。我想做一个方法,调用时会按字母顺序打印朋友列表。

问题:我收到一条警告,提示我无法对不可排序的类型进行排序。 Python 将我的实例变量视为“配置文件对象”,而不是我可以排序和打印的列表。

这是我的代码:

class Profile(object):
    """
    Represent a person's social profile

    Argument:
    name (string): a person's name - assumed to uniquely identify a person

    Attributes:
    name (string): a person's name - assumed to uniquely identify a person
    statuses (list): a list containing a person's statuses - initialized to []
    friends (set): set of friends for the given person.
                   it is the set of profile objects representing these friends.
    """

    def __init__(self, name):
        self.name = name
        self.friends = set()
        self.statuses = []

    def __str__(self):
        return self.name + " is " + self.get_last_status()

    def update_status(self, status):
        self.statuses.append(status)
        return self

    def get_last_status(self):
        if len(self.statuses) == 0:
            return "None"
        else:
            return self.statuses[-1]

    def add_friend(self, friend_profile):
        self.friends.add(friend_profile)
        friend_profile.friends.add(self)
        return self

    def get_friends(self):
        if len(self.friends) == 0:
            return "None"
        else:
            friends_lst = list(self.friends)
            return sorted(friends_lst)

在我填写朋友列表(来自测试模块)并调用 get_friends 方法后,python 告诉我:

 File "/home/tjm/Documents/CS021/social.py", line 84, in get_friends
    return sorted(friends_lst)
TypeError: unorderable types: Profile() < Profile()

为什么我不能简单地将对象类型转换为列表形式?我应该怎么做才能让 get_friends 返回按字母顺序排序的朋友列表?

【问题讨论】:

  • 简单解决方案:return sorted(friends_lst, key=lambda x:x.name)
  • 除此之外,list([])set({}) 是多余的,[]set() 就足够了
  • @AshwiniChaudhary 我确实在使用 python3。您上面的建议仍然会打印对象及其在内存中的位置,而不是列表。为什么会这样?
  • @ThomasMatthew 因为你还没有定义__repr__ 方法。 list、tuple、dict 等容器通常显示对象的repr() 版本。
  • @ThomasMatthew 也正如 IfLoop 指出的那样,不要将 {} 与集合混淆。这是一个非常常见的错误,要获得一个空集,请使用set()。虽然set({}) 有效,但这不是正确的方法。

标签: python class oop


【解决方案1】:

排序算法在类定义中查找 __eq____ne____lt____le____gt____ge__ 方法的存在,以比较从它们创建的实例。您需要重写这些方法以调整它们的行为。

出于性能原因,我建议您为您的类定义一些 integer 属性,例如 id 并将其用于比较,而不是使用具有字符串比较开销的 name

class Profile(object):
    def __eq__(self, profile):
        return self.id == profile.id # I made it up the id property.

    def __lt__(self, profile):
        return self.id < profile.id

    def __hash__(self):
        return hash(self.id)

    ...

或者,如果您不想打扰自己覆盖这些方法,您可以传递 key 函数来排序算法:

>>> friend_list = [<Profile: id=120>, <Profile: id=121>, <Profile: id=115>]
>>> friend_list.sort(key=lambda p: p.id, reverse=True)

使用operator.attrgetter;

>>> import operator
>>> new_friend_list = sorted(friend_list, key=operator.attrgetter('id')) 

【讨论】:

  • @Cthulhu OP 显然在使用 Python 3,而 __cmp__ 不再可用。
  • 请注意,此解决方案将不起作用,因为现在实例不再可散列,因此以下行 self.friends.add(friend_profile);friend_profile.friends.add(self) 将引发错误。
  • @ozgur 感谢您为我的问题提供了这么多替代方案,并为我介绍了操作员模块。看起来我有一些阅读要做。再次感谢
【解决方案2】:

我想我会解决这个问题。首先,这是代码:

from collections import namedtuple

class Profile(namedtuple("Profile", "name")):
    def __init__(self, name):
        # don't set self.name, it's already set!
        self.friends = set({})
        self.statuses = list([])

    # ... and all the rest the same.  Only the base class changes.

我们在这里所做的是用元组的 shape 创建一个类。因此,它是可排序的、可散列的,以及所有的东西。你甚至可以放弃你的__str__() 方法,namedtuple 提供了一个不错的方法。

【讨论】:

  • 这给了我一个非常接近我想要的输出。谢谢你!有一个 KeyError: Profile(name='Bob'),这很奇怪。这是否意味着鲍勃正试图从他不是朋友的个人资料中删除?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 2019-04-08
  • 1970-01-01
  • 2013-06-14
相关资源
最近更新 更多