【问题标题】:List comprehension with tkinter Scale widget data使用 tkinter Scale 小部件数据进行列表理解
【发布时间】:2012-02-22 17:11:36
【问题描述】:

我正在尝试创建一个 python 2.7 tkinter 模块,该模块使用比例小部件数据来影响列表理解,该列表理解在概率特征表示为列表列表的动物之间进行选择。单击“提交”并激活相关命令后,该模块按降序排列和显示这三种动物。

在此示例中,所有三只动物在点击“提交”后的比例均为 33%,因为它们共享相同的概率数据。动物仅在列表列表的第 2 列中的比例小部件数据中有所不同,因为每个动物要么是水生的,要么是陆生的,或两者兼而有之。

from Tkinter import BOTH, BOTTOM, Button, E, END, Entry, FLAT, Frame, Grid, HORIZONTAL, Label, LEFT, N, NO, Pack, RAISED, RIGHT, S, Scale, Text, Tk, TOP, W, YES

from operator import mul

root = Tk()
root.title('Example')

class Environment:
    def __init__(self, parent):

        # layout
        self.myParent = parent

        self.main_frame = Frame(parent, background="light blue")
        self.main_frame.pack(expand=YES, fill=BOTH)

        self.main_left_frame = Frame(self.main_frame, background="light blue")
        self.main_left_frame.pack(side=LEFT, expand=YES, fill=BOTH)

        self.main_right_frame = Frame(self.main_frame, background="light blue")
        self.main_right_frame.pack(side=RIGHT, expand=YES, fill=BOTH)

        self.water = Scale(self.main_right_frame, from_=0.01, to=1.00, orient=HORIZONTAL, bd=0, label="Aquatic",
        background="white", troughcolor="cyan", length=50, width=10, sliderlength=10, resolution=0.01)
        self.water.pack()
        self.water.set(1.00)

        self.soil = Scale(self.main_right_frame, from_=0.01, to=1.00, orient=HORIZONTAL, bd=0, label="Terrestrial",
        background="white", troughcolor="saddle brown", length=50, width=10, sliderlength=10, resolution=0.01)
        self.soil.pack()
        self.soil.set(1.00)

        self.id_frame = Frame(self.main_left_frame, background="white")
        self.id_frame.pack(side=BOTTOM)

        # submit button
        self.submitbutton = Button(self.main_left_frame,text="Submit", background="black", foreground="white",
        width=6, padx="2m", pady="1m")
        self.submitbutton.pack(side=TOP)
        self.submitbutton.bind("<Button-1>", self.submitbuttonclick)
        self.submitbutton.bind("<Return>", self.submitbuttonclick)

        #Animal Matrix
        self.animal = [
        ('Odocoileous virginiana','White-tailed Deer',self.soil.get,0.99,0.01,0.99),
        ('Anguilla anguilla','American Eel',self.water.get,0.99,0.01,0.99),
        ('Trachemys scripta','Slider',lambda:self.soil.get()*self.water.get(),0.99,0.01,0.99)]

    def submitbuttonclick(self, event):
        self.id_frame.destroy()
        self.id_frame = Frame(self.main_left_frame, background="white")
        self.id_frame.pack(side=BOTTOM)

        A=self.animal

        #equation
        sigma = float(sum(reduce(mul,item[3:]) for item in A))
        B = [(item[0], "%.2f" % (item[2]()*reduce(mul, item[3:])/sigma)) for item in A]
        C = sorted(B, key=lambda item: item[1], reverse=True)  

        Label(self.id_frame, text = C[0], background = "white").pack(side=TOP, anchor = W)
        Label(self.id_frame, text = C[1], background = "white").pack(side=TOP, anchor = W)
        Label(self.id_frame, text = C[2], background = "white").pack(side=TOP, anchor = W)

environment = Environment(root)       
root.mainloop()

感谢许多贡献的改进,此代码有效!

【问题讨论】:

  • 查看我的更新,了解适当的(如果有点尴尬)方法。
  • 你解释得很好,我已经更新了代码,看起来应该可以工作,但是元组规模的交互仍然让我很适应。我尝试将比例条目声明为 DoubleVar() 变量,但没有运气。只要代码能正常运行而又不会过于冗长,谁会在意尴尬?
  • 您没有调用该函数。您不能只将函数或方法与数字相乘。这就是我在帖子底部说“你必须进一步分解列表理解以明确调用l[2]”时的意思。您必须先调用它。类似reduce(mul, [item[2]()] + item[3:])
  • 哎呀。没听懂。谢谢。我会一直玩它直到我让它工作,然后更新方程。
  • 永远不要使用import *,并且尤其是不要使用多个import *

标签: python tkinter list-comprehension tkinter-scale


【解决方案1】:

我注意到的第一件事是您将A 定义为一个空字典,然后用self.animal 覆盖该空字典,这是一个列表。

    A={}
    A=self.animal

所以我不确定你在这里做什么。然后在您对B 的定义中对其进行切片:

    B = [(A[0], "%.2f" % (reduce(mul,A[3:])*A[2][i]/sigma*A[2][i])) for A in A]

这不符合Aeither 定义,因为您不能对字典进行切片,但您选择的起始索引是3,而最高索引在@987654328 @ 是 2。令人困惑!但仔细观察,很明显问题在于您将A 重用为索引变量。你真的不应该那样做;它使这段代码难以置信令人困惑。

它也可能导致错误。考虑这段代码:

>>> a = range(10)
>>> [a for a in a]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
9

如您所见,列表解析导致a 引用之前称为a 的序列中的最后一个值。这不会在您的代码中发生,因为您使用了生成器表达式。但它仍然难以阅读和混淆。我强烈建议改为这样做:

    sigma = float(sum(reduce(mul,item[3:]) for item in A))
    B = [(item[0], "%.2f" % (reduce(mul,item[3:])/sigma)) for item in A] 

更新:好的,进行了这些更改后,您仍然需要 get 来自秤的数据。在您对self.animal 的定义中,您使用self.soil.get(),如下所示:

('Odocoileous virginiana','White-tailed Deer',self.soil.get(),0.99,0.01,0.99)

这会将self.soil.get() 的返回值放在一个元组中。但是那个值是固定的——它永远不会改变。您必须明确调用self.soil.get() 每次您想要更新的值。此外,您的列表推导永远不会访问那里返回的值。你像这样切片它们:

>>> l = ('Odocoileous virginiana','White-tailed Deer',
...      self.soil.get(), 0.99, 0.01, 0.99)
>>> l[3:]
(0.98999999999999999, 0.01, 0.98999999999999999)

请记住,列表和元组中的索引以0 开头——所以在上面的元组中ll[0] == 'Odocoileous virginiana'。所以如果你想要除了前两件事之外的所有东西,你必须从索引 2 开始切片:

>>> l[2:]
(0.55000000000000004, 0.98999999999999999, 0.01, 0.98999999999999999)

但这仍然没有解决根本问题,即您必须调用self.soil.get() 才能获取更新的数据。您可以做到这一点的一种方法是在每次点击提交按钮时重新创建self.animal。那会很浪费,但它会起作用。一种不那么浪费(但仍然很尴尬)的方法是将函数本身保存在元组中,而不是函数的结果。你会这样做:

>>> l = ('Odocoileous virginiana','White-tailed Deer',
...      self.soil.get, 0.99, 0.01, 0.99)

注意self.soil.get 后面没有()。现在元组包含的不是浮点值,而是一个返回浮点值的函数。您必须调用它来获取值,但它每次都会返回完全更新的值。组合功能,可以使用lambda

>>> l = ('Odocoileous virginiana','White-tailed Deer',
...      lambda: self.soil.get() * self.water.get(), 0.99, 0.01, 0.99)

现在您可以调用l[2] 来获取值:

>>> l[2]()
0.30250000000000005

因此,要将所有内容放在一起,您必须进一步分解列表理解以显式调用l[2],但是一旦您这样做了,这应该可以工作。这不是一个理想的设置,但恐怕我不得不将创建改进的架构作为读者的练习。

【讨论】:

  • A、B、anc C 不是字典。它们要么是列表列表,要么是元组列表——我承认我不确定是哪个。 A 是原始的,B 是通过将原始输入到列表推导中生成的,C 是根据等式结果将 B 从高到小排序的结果。
  • {} 是一本字典。在您的代码中,您将{} 分配给A,因此至少有一会儿,A 字典。然后是一个列表。然后是一个元组。停止重复使用变量名!
  • 谢谢,我想我必须在填充之前声明一个空的 A={} 对象。已删除——工作正常。
  • @Jeff,啊,我明白了,这是因为它是生成器表达式而不是列表推导式。好吧,你仍然不应该这样做。并将其更改为 item 不会对我造成错误。
  • 对不起,我的错误——我没有改变一切,只是最后一点。如果它是更好的代码,我将更改为...项目。但这仍然留下了我原来的问题。
【解决方案2】:

A[2][i]/sigma*A[2][i] 这个位试图索引浮点数。 应该改为:A[i]/sigma*A[i]

我确实假设 A 中的值都是浮点数。

【讨论】:

  • A[2][i] 正在引用给定行的第二列(所以也许它应该是 A[i][2]?)在列表的动物数据列表中,或者是 self .water.get()、self.soil、get() 或 self.water.get()*self.soil.get()。这些值的范围应为 0.01-1.00,具体取决于用户选择。所以是的,它们应该是花车。 A[2:] 中的所有值都是浮点数。希望这可以帮助。我认为 A[i] 会包含文本元素。
【解决方案3】:

for A in A 部分对我来说似乎有点狡猾。它可能在语法上是正确的,但通常更清楚的是为这些集合中的集合和元素使用不同的名称。

还可以通过使用for i, isolates in enumerate(A) 使for isolates in A: i = A.index(isolates) 更有效,因为当A 很大时A.index(isolates) 可能需要很长时间。

我知道,这不是您问题的真正答案,但我希望它仍然有用。

为了更容易调试(并实际帮助您),请重写:

[(A[0], "%.2f" % (reduce(mul,A[3:])*A[2][i]/sigma*A[2][i])) for A in A]

变成更具可读性的东西。如果将其拆分为多行内容,您实际上可以使用调试器,并轻松查看什么变量是“浮点数”以及它的索引位置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 2013-10-04
    相关资源
    最近更新 更多