Python “代码未传递”;支票;变量到函数

Python “代码未传递”;支票;变量到函数,python,tk,Python,Tk,我试图将名为checks的变量列表传递给函数installFunc,由于某些原因,它似乎不起作用,以下是我(认为是)相关的代码: def installFunc(checks): subprocess.call("md c:\MGInstall", shell=True) subprocess.call (u"net use w: \\it01\files") if checks[0] == 1: subprocess.call(u"w:\\softwar

我试图将名为checks的变量列表传递给函数installFunc,由于某些原因,它似乎不起作用,以下是我(认为是)相关的代码:

def installFunc(checks):
    subprocess.call("md c:\MGInstall", shell=True)
    subprocess.call (u"net use w: \\it01\files")
    if checks[0] == 1:
        subprocess.call(u"w:\\software\\snagitup.exe")
    if checks[1] == 1:
        subprocess.call(u"w:\\software\\camtasia.exe")
    if checks[2] == 1:
        urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\gotomeeting.exe")
        subprocess.call (u"c:\\MGinstall\\gotomeeting.exe")
    if checks[3] == 1:
        sixtyfourcheck()
        if is64bit == True:
            urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\tortoiseSVN.exe")
        elif is64bit == False:
            urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\tortoiseSVN.exe")
    #urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\MGinstall.exe")
    #subprocess.call (u"c:\\MGinstall\\MGinstall.exe")
    #subprocess.call (u"w:\\printers\\installer\\printer.exe")

app = Tk()

w = Label(app, text="IT Automatic Installer")
w.pack()

text = ["Snagit", "Camtasia", "GotoMeeting", "TortoiseSVN"]
variables = []
for name in text:
    variables.append(IntVar())
    Checkbutton(text=name, variable=variables[-1]).pack()

checks = [variable.get() for variable in variables]
b = Button(text="Install", command= lambda : installFunc(checks))
b.pack()

app.mainloop()
现在,我尝试了一些不同的方法——实际上是堆栈溢出给我的lamba部分——我在理解它的工作原理时遇到了一些困难


但我遇到的最大问题是-为什么不将检查传递给installFunc()?我想将完整的检查列表(输入的项目数)传递给installFunc()。

您至少可以通过几种方式来完成这项工作。就我个人而言,我会将安装程序抽象为一个对象,正如Hugh Bothwell的评论中提到的那样。这具有最大的灵活性以及对国家的简洁包容。但是,如果设置为只使用单个函数,则可以使用functools“curry”函数:动态创建嵌入给定参数的新函数。以下是您需要做的更改

def installFunc(checks):
    subprocess.call("md c:\MGInstall", shell=True)
    subprocess.call (u"net use w: \\it01\files")
    if checks[0].get( ) == 1:
        subprocess.call(u"w:\\software\\snagitup.exe")
    if checks[1].get( ) == 1:
        subprocess.call(u"w:\\software\\camtasia.exe")
    if checks[2].get( ) == 1:
        urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\gotomeeting.exe")
        subprocess.call (u"c:\\MGinstall\\gotomeeting.exe")
    if checks[3].get( ) == 1:
        sixtyfourcheck()
        if is64bit == True:
            urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\tortoiseSVN.exe")
        elif is64bit == False:
            urllib.urlretrieve(u"LONGURL", u"c:\\MGinstall\\tortoiseSVN.exe")


import functools

app = Tk()

w = Label(app, text="IT Automatic Installer")
w.pack()

text = ["Snagit", "Camtasia", "GotoMeeting", "TortoiseSVN"]
variables = []
for name in text:
    variables.append(IntVar())
    Checkbutton(text=name, variable=variables[-1]).pack()

checks = [variable.get() for variable in variables]

#-- Here's where we "curry" the installFunc, producing the new doInstall function.
doInstall = functools.partial(installFunc, checks)

b = Button(text="Install", command = doInstall)
b.pack()

app.mainloop()
这里的问题是,variable.get()创建了一个不可变的int,并且您的列表“checks”永远不会更改。你可能真正想要的是

import functools

app = Tk()

w = Label(app, text="IT Automatic Installer")
w.pack()

text = ["Snagit", "Camtasia", "GotoMeeting", "TortoiseSVN"]
variables = []
for name in text:
    variables.append(IntVar())
    Checkbutton(text=name, variable=variables[-1]).pack()

checks = [variable for variable in variables]

#-- Here's where we "curry" the installFunc, producing the new doInstall function.
doInstall = functools.partial(installFunc, checks)

b = Button(text="Install", command = doInstall)
b.pack()

app.mainloop()
variable.get()
返回调用
IntVar
实例时的值,该值甚至在应用程序启动之前。因此,它将充满零

def installCommand(variables):
    checks = [variable.get() for variable in variables]
    return installFunc(checks)

b = Button(text="Install", command= lambda v=variables: installCommand(v))
b.pack()

此外,您需要将
变量作为默认参数传递给lambda,这样就不会与全局变量和局部变量发生冲突。

根据我之前的评论,重构版本:

import urllib
import subprocess
import os
import Tkinter as tk

class ProgramInstaller(object):
    def __init__(self, name, descr, do_install):
        self.name    = name
        self.descr   = descr
        self.do_install = do_install    # can be function or list of strings

    def install(self):
        if callable(self.do_install):
            self.do_install()
        else:
            for s in self.do_install:
                subprocess.call(s)

TEMP_DIR = r"c:\MGInstall"

def makeTempDir(dir=TEMP_DIR):
    # need to expand on this - what if dir already exists, etc
    os.mkdir(dir)

def removeTempDir(dir=TEMP_DIR):
    # need to expand on this - del files in dir before rmdir, etc
    os.rmdir(dir)

def installGoToMeeting():
    makeTempDir()
    url = "http://www.gotomeeting.com/download/something"
    fname = os.path.join(TEMP_DIR, "gotomeeting.exe")
    urllib.urlretrieve(url, fname)
    subprocess.call(fname)
    removeTempDir()

def installTortoiseSVN():
    makeTempDir()
    if is64bit(): url = "http://www.tortoisesvn.net/download/something/64bit"
    else:         url = "http://www.tortoisesvn.net/download/something/32bit"
    fname = os.join(TEMP_DIR, "tortoisesvn.exe")
    urllib.urlretrieve(url, fname)
    subprocess.call(fname)
    removeTempDir()

installers = (
    ProgramInstaller("SnagIt",      "Take screen-shots",           [r"net use w: \\it01\files", r"w:\software\snagitup.exe"]),
    ProgramInstaller("Camtasia",    "Record your desktop",         [r"net use w: \\it01\files", r"w:\software\camtasia.exe"]),
    ProgramInstaller("GoToMeeting", "Web conferencing",            installGoToMeeting),
    ProgramInstaller("TortoiseSVN", "(Sub)Version control client", installTortoiseSVN),
    ProgramInstaller("Printer",     "HP4020 Printer drivers",      [r"net use w: \\it01\files", r"w:\printers\installer\printer.exe"])
)

def doInstall():        # install-button callback
    for inst in installers:
        if inst.cbvar.get():
            inst.install()

def main():
    app = tk.Tk()
    tk.Label(app, text="IT Automatic Installer").pack()

    # need to fiddle with a grid layout to make this look right
    for inst in installers:
        inst.cbvar = tk.IntVar()
        tk.Checkbutton(text=inst.name, variable=inst.cbvar).pack()
        tk.Label(text=inst.descr).pack()

    tk.Button(text="Install", command=doInstall()).pack()
    app.mainloop()

if __name__=="__main__":
    main()

我敢打赌,这与您的lambda实际上没有接受“支票”值这一事实有关,因此您得到的是一些空垃圾,而不是您所期望的,但我希望了解传统知识的人首先发表评论。这看起来不太可能。你将如何修复它?也许lamvar=lamba:installFunc(检查),然后在按钮内使用lamvar?那会有区别吗?我想这会确保计算通过,如果我读对了,你觉得现在没有发生。我想我会完全不同地考虑这段代码-创建一个ProgramInstaller类,并为要安装的每个程序使用适当的数据值对其进行实例化。我想说的是,我期望
lambda检查:installFunc(检查)
,或者类似的东西。抛出了一个错误。TypeError:()只接受1个参数(给定0)我很确定
检查=[variable for variable in variables]
是无用的:P…思考。。。是的……这是多余的,不是吗这似乎奏效了。我不知道这里到底发生了什么。我必须仔细阅读。@AndrewAlexander如jadkik94所述,当您在IntVar实例上调用.get()方法时,它将返回IntVar()持有的值的副本,而该副本不会更改。因此,正如您的代码最初所拥有的那样,您的检查列表将创建为[0,0,0,0,…]。您可能真正想要的是对IntVar()对象的引用,这是jadkik94的代码完成的。请尝试
打印变量[0]。get()
。它将返回一个int。您希望如何更改它?您需要传递
变量[0]
以在希望获取值0或1时调用
get
函数。这是基本的函数操作,与Tkinter无关。@AndrewAlexander请参阅关于lambdas的最后一句话。如果您确实想使用默认参数为lambda函数保存变量,则需要将其更改为
lambda variables=variables:installCommand(variables)
lambda v=variables:installCommand(v)
——实际上,您绑定了变量
v
,但没有使用它,您不妨说
lambda:installCommand(variables)