【问题标题】:what's the right way to put *arg in a tuple that can be sorted?将 *arg 放入可以排序的元组中的正确方法是什么?
【发布时间】:2011-11-17 15:26:57
【问题描述】:

我想要一个字典或元组,我可以根据我用作 *arg 的参数的对象的属性进行排序。我一直在尝试这样做的方式只是给了我 AttributeErrors,这让我相信我这样做很奇怪。

def function(*arg):
    items = {}
    for thing in arg:
        items.update({thing.name:thing})


    while True:
        for thing in items:
        ## lots of other code here, basically just a game loop.
        ## Problem is that the 'turn order' is based on whatever
        ## Python decides the order of arguments is inside "items".
        ## I'd like to be able to sort the dict based on each object's
        ## attributes (ie, highest 'thing.speed' goes first in the while loop)

问题是当我尝试根据放入函数()的对象的属性对“项目”进行排序时,它给了我“AttributeError:'str'对象没有属性'attribute'”。这让我相信我要么以糟糕的方式解包 *arg,要么试图以错误的方式做某事。

while True:
    for thing in sorted(items, key=attrgetter('attribute')):

...也不起作用,一直告诉我我正在尝试操作“str”对象。我不在这里做什么?

【问题讨论】:

  • 不要使用update 将项目一个一个地添加到dict - 它是为了从序列/迭代器更新现有的dict。有关如何创建新的dict(这也是您使用update 添加到现有dict 的方式),请参阅我的答案,或者稍后使用items[thing.name] = thing 向其中添加单个项目。
  • 你能描述一下你的函数的参数吗?对我来说,AttributeError 与非法输入类型相关联(如 str)。

标签: python sorting dictionary tuples


【解决方案1】:

{edit} 感谢 agf,我明白了这个问题。所以,我在下面写的内容本身就是一个很好的答案,但与上面的问题无关……我把它放在这里是为了追踪。


查看答案,我可能还没有理解这个问题。但这是我的理解:由于args 是您为函数提供的参数元组,因此这些参数很可能都不是具有name 属性的对象。但是,查看您报告的错误,您正在提供字符串参数。

也许一些插图将有助于我的描述:

>>> # defining a function using name attribute
>>> def f(*args):
...      for arg in args:
...           print arg.name
>>> # defining an object with a name attribute
>>> class o(object):
...     def __init__(self, name):
...          self.name = name
>>> # now applying the function on the previous object, and on a string
>>> f( o('arg 1'), 'arg 2' )
arg 1

Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    f(o('arg 1'), 'ets')
  File "<pyshell#3>", line 3, in f
    print arg.name
AttributeError: 'str' object has no attribute 'name'

这是失败的,因为字符串没有这样的属性。

对我来说,在您的代码中存在一个错误:您尝试在输入中使用属性name,而从未验证它们是否具有这样的属性。也许你应该先用hasattr 测试:

>>> if hasattr(arg, 'name'):
...     print arg.name
... else:
...     print arg

或者对输入进行一些检查,以验证它是否是给定类的实例,已知具有请求的属性。

【讨论】:

  • 您已经错过了他收到错误的原因。我们知道每个arg 都有一个name,因为他创建dict 的代码的第一部分不会在thing.name 处给出属性错误。当他遍历字典时,他只是在遍历键。键是字符串,所以没有他正在寻找的属性。然而,值是参数,属性也是如此,所以迭代值解决了他的问题。
  • mmh 好的,通过将所有内容重新阅读三遍,我现在明白了。显然,for thing in items 是错误的,它应该是 for name, thing in items.items() 加上你写的一些排序。所以现在,你的答案对我来说很有意义:)
【解决方案2】:

arg已经tuple你可以按每个项目的属性排序:

def function(*args):
    for thing in sorted(args, key=attrgetter('attribute')):

当您迭代 dict 时,正如 sorted 所做的那样,您只会得到键,而不是值。所以,如果你想使用dict,你需要这样做:

def function(*args):
    # or use a dict comprehension on 2.7+ 
    items = dict((thing.name, thing) for thing in args)

    # or just items.values on 3+
    for thing in sorted(items.itervalues(), key=attrgetter('attribute')):

实际按属性对参数进行排序。如果您希望dict 的键也可用(此处不需要,因为键也是项目的属性),请使用类似:

for name, thing in sorted(items.iteritems(), key=lambda item: item[1].attribute):

【讨论】:

  • 我很确定这是我的答案,尽管现在我有一个游戏循环几乎可以完全重写呵呵。谢谢
【解决方案3】:

您的items 是一个字典,您无法正确排序一个字典。当您尝试将其用作可迭代对象时,它会静默返回其键列表,即字符串列表。而且你在创建一个字典后不要使用你的arg

如果您不需要 dict 查找,只需遍历它,您可以将 dict 替换为 2 元组列表 (thing.name, thing),按任何属性对其进行排序并遍历它。如果您确实需要 dict 查找和排序,也可以使用 Python 2.7 中的 collections.OrderedDict(对于早期版本,它作为单独的 ordereddict 包存在)。

【讨论】:

  • 他不想对dict 进行排序,他希望能够根据情况对dict 的值进行排序。 OrderedDict 对此毫无帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多