将 argparse 转义字符作为选项处理
Handling argparse escaped character as option
argparse 库处理转义字符(如 \t 到制表符和 \n 到换行符)的方式与我喜欢的不同。 An answer to this question 给出了一个解决方案,但我想让它对用户不那么明显。
给定程序:
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--delimiter', default='\t')
args = parser.parse_args()
print(args)
您将收到此输出:
bash$ parser.py -d \t
Namespace(delimiter='t')
bash$ parser.py -d \t
Namespace(delimiter='\t')
bash$ parser.py -d '\t'
Namespace(delimiter='\t')
bash$ parser.py -d '\t'
Namespace(delimiter='\\t')
bash$ parser.py -d "\t"
Namespace(delimiter='\t')
bash$ parser.py -d "\t"
Namespace(delimiter='\t')
bash$ parser.py -d $'\t'
Namespace(delimiter='\t')
bash$ parser.py -d $'\t'
Namespace(delimiter='\t')
bash$ parser.py -d $"\t"
Namespace(delimiter='$\t')
bash$ parser.py -d $"\t"
Namespace(delimiter='$\t')
我只用
得到了想要的参数
parser.py -d $'\t'
但我希望输入看起来像
parser.py -d \t
或更少
parser.py -d '\t'
parser.py -d "\t"
如果我想改变行为,我可以使用 argparse 库来做这件事吗?
如果没有,我是否可以在现有的 argparse 库之上编写行为?
如果不是,这就是 bash 将参数传递给 argparse 的方式,因此不在我的手中吗?
如果这是真的,这是否通常记录给用户,或者这种行为是否被认为是正常的?
就我个人而言,我只希望这种行为——你的 shell 解释一些项目并传递一个文字制表符,或者一个反斜杠和一个字母 t——而不一定希望 Python 程序进行二级解释(argparse 中没有任何内容可以执行此操作)。
尽管如此,Python 已经为此内置了解释器;参见 this question and answers。
您在 namespace
中看到的字符串正是出现在 sys.argv
中的字符串 - 它是由 bash
和解释器创建的。 parser
不处理或调整此字符串。它只是设置 namespace
中的值。您可以在解析之前通过打印 sys.argv
来验证这一点。
如果你很清楚用户想要什么,那么我建议解析后修改args.delimiter
。解析器的主要目的是弄清楚用户想要什么。作为程序员,您可以以任何方式解释和应用该信息。
一旦你计算出一个令人满意的 post 解析函数,你可以将它实现为这个参数的 type
(比如 int()
和 float()
为数字字符串做)。但重点放在post-解析处理上。
假设问题部分是关于如何执行@hpaulj 解释的 post-processing 并且由于我在上面的链接中看不到 Python 3 的立即解决方案,这里是快速解决方案:
import codecs
def unescaped_str(arg_str):
return codecs.decode(str(arg_str), 'unicode_escape')
然后在解析器中:
parser.add_argument('-d', '--delimiter', type=unescaped_str, default='\t')
这将使您不太理想的案例有效:
parser.py -d '\t'
parser.py -d "\t"
但不是所需的未转义 \t
。无论如何,由于没有检查机制,此解决方案可能很危险...
这是正确处理引用('\t'
和 "\t"
)输入案例的快速方法(尽管它只专门处理您的特定制表符案例输入):
parser.add_argument('-d', '--delimiter', type=lambda d: '\t' if d == '\t' else d)
首先注意以下几点:在Python中,"\t"
是tab字面量,转义后的"\t"
是一个双字符的字符串(第一个字符是"\"
,第二个是"t"
)。你可以用 len("\t"), len("\t")
检查这个,它给出 1, 2
.
当用户在命令行中输入 -d '\t'
时,python 将收到字符串 '\t'
(字面意思是两个字符,"backslash" 和 "t").我们想用一个 "tab" 字符替换这个由两个字符组成的字符串。 type
参数采用函数作为预处理参数的方式。 lambda 函数检查两个字符的字符串并将其替换为制表符。
argparse 库处理转义字符(如 \t 到制表符和 \n 到换行符)的方式与我喜欢的不同。 An answer to this question 给出了一个解决方案,但我想让它对用户不那么明显。
给定程序:
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--delimiter', default='\t')
args = parser.parse_args()
print(args)
您将收到此输出:
bash$ parser.py -d \t
Namespace(delimiter='t')
bash$ parser.py -d \t
Namespace(delimiter='\t')
bash$ parser.py -d '\t'
Namespace(delimiter='\t')
bash$ parser.py -d '\t'
Namespace(delimiter='\\t')
bash$ parser.py -d "\t"
Namespace(delimiter='\t')
bash$ parser.py -d "\t"
Namespace(delimiter='\t')
bash$ parser.py -d $'\t'
Namespace(delimiter='\t')
bash$ parser.py -d $'\t'
Namespace(delimiter='\t')
bash$ parser.py -d $"\t"
Namespace(delimiter='$\t')
bash$ parser.py -d $"\t"
Namespace(delimiter='$\t')
我只用
得到了想要的参数parser.py -d $'\t'
但我希望输入看起来像
parser.py -d \t
或更少
parser.py -d '\t'
parser.py -d "\t"
如果我想改变行为,我可以使用 argparse 库来做这件事吗? 如果没有,我是否可以在现有的 argparse 库之上编写行为? 如果不是,这就是 bash 将参数传递给 argparse 的方式,因此不在我的手中吗? 如果这是真的,这是否通常记录给用户,或者这种行为是否被认为是正常的?
就我个人而言,我只希望这种行为——你的 shell 解释一些项目并传递一个文字制表符,或者一个反斜杠和一个字母 t——而不一定希望 Python 程序进行二级解释(argparse 中没有任何内容可以执行此操作)。
尽管如此,Python 已经为此内置了解释器;参见 this question and answers。
您在 namespace
中看到的字符串正是出现在 sys.argv
中的字符串 - 它是由 bash
和解释器创建的。 parser
不处理或调整此字符串。它只是设置 namespace
中的值。您可以在解析之前通过打印 sys.argv
来验证这一点。
如果你很清楚用户想要什么,那么我建议解析后修改args.delimiter
。解析器的主要目的是弄清楚用户想要什么。作为程序员,您可以以任何方式解释和应用该信息。
一旦你计算出一个令人满意的 post 解析函数,你可以将它实现为这个参数的 type
(比如 int()
和 float()
为数字字符串做)。但重点放在post-解析处理上。
假设问题部分是关于如何执行@hpaulj 解释的 post-processing 并且由于我在上面的链接中看不到 Python 3 的立即解决方案,这里是快速解决方案:
import codecs
def unescaped_str(arg_str):
return codecs.decode(str(arg_str), 'unicode_escape')
然后在解析器中:
parser.add_argument('-d', '--delimiter', type=unescaped_str, default='\t')
这将使您不太理想的案例有效:
parser.py -d '\t'
parser.py -d "\t"
但不是所需的未转义 \t
。无论如何,由于没有检查机制,此解决方案可能很危险...
这是正确处理引用('\t'
和 "\t"
)输入案例的快速方法(尽管它只专门处理您的特定制表符案例输入):
parser.add_argument('-d', '--delimiter', type=lambda d: '\t' if d == '\t' else d)
首先注意以下几点:在Python中,"\t"
是tab字面量,转义后的"\t"
是一个双字符的字符串(第一个字符是"\"
,第二个是"t"
)。你可以用 len("\t"), len("\t")
检查这个,它给出 1, 2
.
当用户在命令行中输入 -d '\t'
时,python 将收到字符串 '\t'
(字面意思是两个字符,"backslash" 和 "t").我们想用一个 "tab" 字符替换这个由两个字符组成的字符串。 type
参数采用函数作为预处理参数的方式。 lambda 函数检查两个字符的字符串并将其替换为制表符。