从命令行构建列表列表
Construct a list of lists from command line
我正在 python 中编写一个小型模拟,它应该根据命令行参数以不同的方式汇总结果。
一旦模拟具有 运行 并且 Simulation
对象包含原始结果,我想使用 Simulation.sample(list_of_objects)
方法或 Simulation.sample_differently()
方法生成一些输出对于每个指定的采样器。 list_of_objects
应该是 range(N)
或在命令行上明确指定的列表。
例如,我希望进行以下计算。
$ simulation --sample 5
[Simulation.sample(range(5))]
$ simulation --sample-objects 0 1 2 3 a
[Simulation.sample([0, 1, 2, 3, "a"])]
$ simulation --sample 4 --sample-objects 1 3 "b"
[Simulation.sample(range(4)), Simulation.sample([1, 3, "b"])]
$ simulation --sample-differently --sample-objects 1
[Simulation.sample_differently(), Simulation.sample([1])]
$ simulation --sample-objects 0 1 2 --sample-objects 3 4
[Simulation.sample([0, 1, 2]), Simulation.sample([3, 4])]
我想我会做如下。
def parse_objects_to_sampler(object_strings):
objects = []
for entry in object_strings:
try:
objects.append(int(entry))
except ValueError:
objects.append(entry)
return lambda simulation: simulation.sample(objects))
parser = argparse.ArgumentParser()
parser.add_argument(
"--sample", action=append,
type=lambda x: lambda simulation: simulation.sample(range(int(x))))
parser.add_argument(
"--sample-differently", action="append_const", dest="sample",
const=Simulation.sample_differently)
parser.add_argument(
"--sample-objects", nargs="*", action="append", dest="sample",
type=parse_objects_to_sampler)
for sampler in parser.parse().sample:
sampler(Simulation)
不幸的是,type
构造函数对每个单独的命令行参数进行操作,而不是对为 nargs≠None
生成的其中几个参数的列表进行操作,因此上述方法不起作用。
实现上述行为的最佳pythonic 方法是什么?
我认为比我更有经验的人可以谈论 "most pythonic",但我的处理方式是接受 CSV 字符串,然后使用 parse_objects_to_sampler
函数拆分字符串和做进一步的逻辑。
所以:
def parse_objects_to_sampler(input_string):
object_string = input_string.split(",")
objects = []
for entry in object_strings:
try:
objects.append(int(entry))
except ValueError:
objects.append(entry)
return lambda simulation: simulation.sample(objects))
然后你会调用,例如:
simulation --sample-objects "0,1,2,3,a"
希望这会得到你想要的结果!
type
应该专注于测试输入并将其转换为基本输入。它接受一个字符串作为输入和 returns 某个对象,或者如果字符串无效则引发错误。要将 nargs*
列表的项目作为聚合处理,您需要在解析后稍后处理。
Pythonic 方式(或通常好的编程方式)是将任务分解成多个部分。使用 argparse
仅解析输入,然后使用后续代码构建 simulation
个对象的最终列表。
例如,我认为这个解析器会接受您的所有输入(我还没有测试过):
parser = argparse.ArgumentParser()
parser.add_argument("--sample", type=int, action='append')
parser.add_argument("--sample-differently", action="store_true")
parser.add_argument("--sample-objects", nargs="*", action="append")
args = parser.parse_args()
重点是接受 --sample
的整数、--sample-objects
的字符串列表和 --sample-differently
.
的 True/False 值
然后我可以根据这些参数构建范围列表和 simulation
对象(再次未测试):
alist = []
if args.sample_differently:
alist.append(Simulation.sample_differently())
for i in args.sample:
# is a number
alist.append(Simulation.sample(range(i)))
for i in args.sample_objects:
# i will be a list of strings
def foo(i):
# conditionally convert strings to integers
res = []
for j in i:
try:
j = int(j)
except ValueError:
pass
res.append(j)
return res
alist.append(Simulation.sample(foo(i))
如果我做对了 alist
应该符合您想要的列表。
您可以创建一个自定义操作 class 来执行这种与 Simulation.sample
的加法。 Action 获取整个列表 values
,它可以处理并添加到 namespace
。但与我概述的内容相比,它并没有节省任何编码。
===============
这对定义可能会修正您的“--samples-objects”参数:
def intorstr(astr):
# conditionally convert strings to integers
try:
astr = int(astr)
except ValueError:
pass
return astr
class SamplesAction(argparse._AppendAction):
# adapted from _AppendAction
def __call__(self, parser, namespace, values, option_string=None):
values = Simulation.sample(values)
items = _copy.copy(_ensure_value(namespace, self.dest, []))
items.append(values)
setattr(namespace, self.dest, items)
parser.add_argument("--sample-objects", nargs="*",
action=SamplesAction, dest="sample", type=intorstr)
我忽略了你使用 lambda simulation: simulation....
的原因。如果您将其重写为函数或 class 定义,我认为会减少混淆。太多 lambdas
使代码混乱。
我正在 python 中编写一个小型模拟,它应该根据命令行参数以不同的方式汇总结果。
一旦模拟具有 运行 并且 Simulation
对象包含原始结果,我想使用 Simulation.sample(list_of_objects)
方法或 Simulation.sample_differently()
方法生成一些输出对于每个指定的采样器。 list_of_objects
应该是 range(N)
或在命令行上明确指定的列表。
例如,我希望进行以下计算。
$ simulation --sample 5
[Simulation.sample(range(5))]
$ simulation --sample-objects 0 1 2 3 a
[Simulation.sample([0, 1, 2, 3, "a"])]
$ simulation --sample 4 --sample-objects 1 3 "b"
[Simulation.sample(range(4)), Simulation.sample([1, 3, "b"])]
$ simulation --sample-differently --sample-objects 1
[Simulation.sample_differently(), Simulation.sample([1])]
$ simulation --sample-objects 0 1 2 --sample-objects 3 4
[Simulation.sample([0, 1, 2]), Simulation.sample([3, 4])]
我想我会做如下。
def parse_objects_to_sampler(object_strings):
objects = []
for entry in object_strings:
try:
objects.append(int(entry))
except ValueError:
objects.append(entry)
return lambda simulation: simulation.sample(objects))
parser = argparse.ArgumentParser()
parser.add_argument(
"--sample", action=append,
type=lambda x: lambda simulation: simulation.sample(range(int(x))))
parser.add_argument(
"--sample-differently", action="append_const", dest="sample",
const=Simulation.sample_differently)
parser.add_argument(
"--sample-objects", nargs="*", action="append", dest="sample",
type=parse_objects_to_sampler)
for sampler in parser.parse().sample:
sampler(Simulation)
不幸的是,type
构造函数对每个单独的命令行参数进行操作,而不是对为 nargs≠None
生成的其中几个参数的列表进行操作,因此上述方法不起作用。
实现上述行为的最佳pythonic 方法是什么?
我认为比我更有经验的人可以谈论 "most pythonic",但我的处理方式是接受 CSV 字符串,然后使用 parse_objects_to_sampler
函数拆分字符串和做进一步的逻辑。
所以:
def parse_objects_to_sampler(input_string):
object_string = input_string.split(",")
objects = []
for entry in object_strings:
try:
objects.append(int(entry))
except ValueError:
objects.append(entry)
return lambda simulation: simulation.sample(objects))
然后你会调用,例如:
simulation --sample-objects "0,1,2,3,a"
希望这会得到你想要的结果!
type
应该专注于测试输入并将其转换为基本输入。它接受一个字符串作为输入和 returns 某个对象,或者如果字符串无效则引发错误。要将 nargs*
列表的项目作为聚合处理,您需要在解析后稍后处理。
Pythonic 方式(或通常好的编程方式)是将任务分解成多个部分。使用 argparse
仅解析输入,然后使用后续代码构建 simulation
个对象的最终列表。
例如,我认为这个解析器会接受您的所有输入(我还没有测试过):
parser = argparse.ArgumentParser()
parser.add_argument("--sample", type=int, action='append')
parser.add_argument("--sample-differently", action="store_true")
parser.add_argument("--sample-objects", nargs="*", action="append")
args = parser.parse_args()
重点是接受 --sample
的整数、--sample-objects
的字符串列表和 --sample-differently
.
然后我可以根据这些参数构建范围列表和 simulation
对象(再次未测试):
alist = []
if args.sample_differently:
alist.append(Simulation.sample_differently())
for i in args.sample:
# is a number
alist.append(Simulation.sample(range(i)))
for i in args.sample_objects:
# i will be a list of strings
def foo(i):
# conditionally convert strings to integers
res = []
for j in i:
try:
j = int(j)
except ValueError:
pass
res.append(j)
return res
alist.append(Simulation.sample(foo(i))
如果我做对了 alist
应该符合您想要的列表。
您可以创建一个自定义操作 class 来执行这种与 Simulation.sample
的加法。 Action 获取整个列表 values
,它可以处理并添加到 namespace
。但与我概述的内容相比,它并没有节省任何编码。
===============
这对定义可能会修正您的“--samples-objects”参数:
def intorstr(astr):
# conditionally convert strings to integers
try:
astr = int(astr)
except ValueError:
pass
return astr
class SamplesAction(argparse._AppendAction):
# adapted from _AppendAction
def __call__(self, parser, namespace, values, option_string=None):
values = Simulation.sample(values)
items = _copy.copy(_ensure_value(namespace, self.dest, []))
items.append(values)
setattr(namespace, self.dest, items)
parser.add_argument("--sample-objects", nargs="*",
action=SamplesAction, dest="sample", type=intorstr)
我忽略了你使用 lambda simulation: simulation....
的原因。如果您将其重写为函数或 class 定义,我认为会减少混淆。太多 lambdas
使代码混乱。