我有一个脚本,我要求用户提供要执行的预定义操作的列表.我还希望能够在用户没有定义任何内容时采用特定的操作列表.然而,似乎试图将这两者结合在一起是不可能的.
当用户不提供参数时,他们会收到默认选项无效的错误
acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('action', nargs='*', action='append', choices=acts, default=[['dump', 'clear']])
args = p.parse_args([])
>>> usage: [-h] [{clear,copy,dump,lock} [{clear,copy,dump,lock} ...]]
: error: argument action: invalid choice: [['dump', 'clear']] (choose from 'clear', 'copy', 'dump', 'lock')
Run Code Online (Sandbox Code Playgroud)
当它们确定一组动作时,结果命名空间将用户的动作附加到默认值,而不是替换默认值
acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('action', nargs='*', action='append', choices=acts, default=[['dump', 'clear']])
args = p.parse_args(['lock'])
args
>>> Namespace(action=[['dump', 'clear'], ['dump']])
Run Code Online (Sandbox Code Playgroud) 我希望模仿内置函数(如getattr)的行为,允许用户指定"默认"返回值.我最初的尝试就是这样做
def myfunc(foo, default=None):
# do stuff
if (default is not None):
return default
raise SomeException()
Run Code Online (Sandbox Code Playgroud)
问题是,如果用户想要None成为他们的返回值,则此函数会引发异常.第二次尝试:
def myfunc(foo, **kwargs):
# do stuff
if ('default' in kwargs):
return kwargs['default']
raise SomeException()
Run Code Online (Sandbox Code Playgroud)
这解决了上述问题并允许用户指定任意值,但引入了一个烦恼,即用户必须始终default=bar在其函数调用中指定; 他们不能只提供bar最后.同样,*args可以使用,但default=bar如果他们更喜欢这种语法,则会阻止用户使用.
结合*args并**kwargs提供可行的解决方案,但感觉这需要付出很多努力.它还可能掩盖不正确的函数调用(例如bar = myfunc(foo, baz, default=qux))
def myfunc(foo, *args, **kwargs):
# do stuff
if (len(args) == 1):
return args[0]
if ('default' in kwargs):
return kwargs['default']
raise SomeException()
Run Code Online (Sandbox Code Playgroud)
有更简单的解决方案吗?(如果重要,则为python 3.2)
是否可以在退出块之前重新分配 with-block 的对象?
我与偶尔在传输过程中断开连接的 FTP 服务器进行交互,而 IT 不愿意对此做任何事情。作为我自己的工具的解决方法,我使用了一个包装器,它会在放弃之前重试传输几次:
def retry(conn, max_tries=3, **kwargs):
this_try = 1
while (this_try <= max_tries):
try:
# upload / download / whatever
return conn
except ftplib.all_errors:
conn.quit()
time.sleep(60)
conn = ftplib.FTP(**kwargs)
this_try += 1
Run Code Online (Sandbox Code Playgroud)
这个包装器工作正常,但似乎不能在with块内使用,就像可以使用普通的 FTP 连接一样。如果该except子句被击中,连接将重新建立,但在退出with块时,python 将尝试关闭原始conn,而不是新的:
with ftplib.FTP(**kwargs) as conn:
conn = retry(conn, **kwargs)
Run Code Online (Sandbox Code Playgroud)
这可以通过自定义上下文管理器来演示,显示 python 调用__exit__()来自原始对象,即使变量在块中间重新分配:
>>> class Echo(object):
... def __enter__(self):
... print('entering ' + repr(self))
... return self
... def …Run Code Online (Sandbox Code Playgroud)