【问题标题】:TypeError with Python zip() after Select Statements to Generate Pairs在选择语句生成对之后使用 Python zip() 出现 TypeError
【发布时间】:2016-01-13 04:36:18
【问题描述】:

这是我创建瑞士配对系统的代码,该系统会为比赛生成配对球员:

def swissPairings():
    db = psycopg2.connect("dbname=tournament")
    c = db.cursor()
    c.execute("select PlayerID from Scores order by Wins;")
    ids = c.fetchall()
    c.execute("select Players.Name from Players join Scores\
        on Players.PlayerID = Scores.PlayerID\
        order by Wins;")
    names = c.fetchall()
    standings = playerStandings()
    pairs = zip(ids,names)
    print pairs
    db.close()

当我为实际配对运行测试时,我确实得到了一个如下列表(但它看起来有点有趣,它应该生成两对,因为有四个玩家,但它却生成了一个长列表):

[((291,), ('Fluttershy',)), ((293,), ('Pinkie Pie',)), ((290,),
('Twilight Sparkle',)), ((292,), ('Applejack',))]

但是后面跟着错误信息:

Traceback (most recent call last):
  File "/Users/Rebecca/fullstack/vagrant/tournament/tournament_test.py", line 136, in <module>
    testPairings()
  File "/Users/Rebecca/fullstack/vagrant/tournament/tournament_test.py", line 116, in testPairings
    if len(pairings) != 2:
TypeError: object of type 'NoneType' has no len() 

如何解决此错误?似乎我必须附加一些东西,但我不知道是什么...我需要使 len(pairings) == 2,现在它似乎是 1。

【问题讨论】:

    标签: python database list postgresql typeerror


    【解决方案1】:

    正如您在回溯中看到的,错误源自 testPairings 函数。也许您可以包含它的源代码?

    在没有看到的情况下,我冒昧地认为您的错误可能是由 testPairings 调用 swissPairings 并期望收到返回值引起的;但 swissPairings 不返回任何内容,而是打印结果。尝试删除 print pairs 行并在对 db.close() 的调用下方添加 return pairs

    至于您的结果结构,我认为不使用 zip() 并使用单个 SQL 查询生成对会更容易、更安全、更高效:

    SELECT Players.PlayerID, Players.Name FROM Scores INNER JOIN Players ON Players.PlayerID = Scores.PlayerID ORDER BY Scores.Wins

    最后,您对 playerStandings() 的调用有什么作用?您不会向它传递任何参数,也不会从中接收任何值。它是在打印另一个数据集吗?如果是这样,我建议你重构它;通常最好将您的函数一分为二:有一些获取数据(并这样做),另一些调用这些函数并使用所需格式打印结果。如果您将查询与他们的演示捆绑在一起,您将无法在不将数据打印到屏幕上的情况下获取数据,这会减少代码重用并使您的程序更难理解和维护。

    【讨论】:

      【解决方案2】:

      问题

      您的每个 select 语句都会产生一个 list,其中包含只有一个元素的 tuples,因此 idsnames 的内容是一个元组列表。

      ids   => [(291,), (293,), (290,), (292),]
      names => [ ('Fluttershy',), ('Pinkie Pie',), ('Twilight',), ('Applejack',) ]
      

      上面的意思是zip将创建一个新的元组列表,其中每个值对将是一对来自ids元组 em> 和 名称

      您正在寻找的是转换从数据库接收到的数据,以便获得两个值列表(不是元组)——换句话说;您需要在调用 zip 之前解压缩元组。


      建议的解决方案

      为了解决这个问题,您只需确保 idsnames 都是值列表,而不是包含单个值的元组列表.

      这可以通过以下任何一种方式轻松完成:

      ids   = [ x[0] for x in c.fetchall () ] # unpack tuples
      
      ...
      
      names = [ x[0] for x in c.fetchall () ] # unpack tuples
      

      替代解决方案

      另一种生成元组列表中每个元组的第一个元素的列表的语法:

      ids = [ x for x, in c.fetchall () ]  # unpack tuple 
      

      您当然也可以更改您对zip 的调用,以便在那里进行解包(如果您采用此解决方案,则无需更改任何其他内容):

      pairs = zip ([ x for x, in ids], [x for x, in names])
      

      一起规避问题

      只需同时选择玩家的 idname

      c.execute("select Players.PlayerId, Player.Name from Players join Scores\
          on Players.PlayerID = Scores.PlayerID\
          order by Wins;")
      
      pairs = c.fetchall ()
      

      【讨论】:

      • 有道理!谢谢你。拆包后,我的列表现在生成如下:[(381, 'Fluttershy'), (383, 'Pinkie Pie'), (380, 'Twilight Sparkle'), (382, 'Applejack')] 我怎样才能让这两个显示两组对?像这样-[(381, 'Fluttershy'), (383, 'Pinkie Pie')], [(380, 'Twilight Sparkle'), (382, 'Applejack')]
      猜你喜欢
      • 1970-01-01
      • 2019-07-09
      • 2015-12-06
      • 1970-01-01
      • 2017-12-02
      • 1970-01-01
      • 2012-02-29
      • 2021-07-29
      • 1970-01-01
      相关资源
      最近更新 更多