如何创建一个可以直接从shell(谐和)执行的程序?
How to create a program which can be executed directly from the shell (harmonic sum)?
我在 MatLab 中做过一些编程,但我对 Python 完全陌生。对于我们的第一个项目,我们的老师希望我们编写调和和 (1/1+1/2+1/3...
) 和一个“可以直接从 shell 执行的完整程序,如下所示:
$ python3 hsum.py 10
0 0
1 1.0
2 1.5
3 1.8333333333333333
4 2.083333333333333
5 2.283333333333333
6 2.4499999999999997
7 2.5928571428571425
8 2.7178571428571425
9 2.8289682539682537
我是这样管理的:
import sys
def hSum(n):
s = 0
for i in range(n + 1):
if i == 0:
s = 0
else:
s += 1 / i
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
main()
主要问题是我并不真正理解他所说的“可以直接从shell执行的完整程序”是什么意思。显然第二个问题是,当我 运行 他提供的“测试”文件,测试程序是否正确时,它告诉我:
function main should generate exactly the same output as in the assignment
Got:
[blank]
Instead of:
[the list in the previous quote]
这里是 test.py 代码:
import sys
import importlib.util
def testEq(res, ref, msg):
global pass_tests, fail_tests
if res == ref:
pass_tests = pass_tests + 1
else:
print(msg)
print("Got:")
print(res)
print("Instead of:")
print(ref)
fail_tests = fail_tests + 1
def test(fun, x, y):
global pass_tests, fail_tests
if type(x) == tuple:
z = fun(*x)
else:
z = fun(x)
if y == z:
pass_tests = pass_tests + 1
else:
if type(x) == tuple:
s = repr(x)
else:
s = "(" + repr(x) + ")"
print("Condition failed:")
print(" " + fun.__name__ + s + " == " + repr(y))
print(fun.__name__ + " returned/printed:")
print(str(z))
fail_tests = fail_tests + 1
def run(src_path=None):
global pass_tests, fail_tests
saved_stdout = sys.stdout
sys.stdout = io.StringIO()
saved_argv = sys.argv
sys.argv = ["hsum.py", "10"]
if src_path == None:
import hsum
else:
spec = importlib.util.spec_from_file_location("hsum", src_path + "/hsum.py")
hsum = importlib.util.module_from_spec(spec)
spec.loader.exec_module(hsum)
sys.argv = saved_argv
out = sys.stdout.getvalue()
sys.stdout = saved_stdout
pass_tests = 0
fail_tests = 0
fun_count = 0
if hasattr(hsum, "hSum"):
fun_count = fun_count + 1
test(hsum.hSum, 5, 2.283333333333333)
test(hsum.hSum, 7, 2.5928571428571425)
else:
print("hSum is not implemented yet!")
if hasattr(hsum, "main"):
fun_count = fun_count + 1
testEq(out,
"0 0\n1 1.0\n2 1.5\n3 1.8333333333333333\n4 2.083333333333333\n5 2.283333333333333\n6 "
"2.4499999999999997\n7 2.5928571428571425\n8 2.7178571428571425\n9 2.8289682539682537\n",
"function main should generate exactly the same output as in the assignment")
else:
print("main is not implemented yet!")
print(str(pass_tests) + " out of " + str(pass_tests + fail_tests) + " passed.")
return fun_count == 2 and fail_tests == 0
if __name__ == "__main__":
run()
现在您的代码不打印或 return 任何东西。这可能是 copy/pasting 中的一个错误 - 如果您取消缩进最后一行 main()
然后它会运行并且 hSum()
return 是 s
的单个值,因为代码是写给。现在这最后一行作为 main()
函数本身的一部分执行(导致它无限循环),但函数本身从未真正被调用,所以什么也没有发生。
您能否也上传一份 test.py 脚本?目前还不清楚它希望如何 returned.
根据第一个引号判断,它只是想让您打印所有值。您可以通过在 for
循环中添加 print(str(i) + " " + str(s))
轻松地做到这一点(当然是在计算 s
之后)。您不需要 return s
,因为这会导致 hSum()
“等于”s
(例如,value = hSum()
会导致 value
取值 return由函数编辑),但你没有对这些信息做任何事情。
使用以下代码,我通过了 2/3 的测试。稍后我会解释为什么。
import sys
def hSum(n):
s = 0
for i in range(n + 1):
if i == 0:
s = 0
else:
s += 1 / i
print(str(i) + " " + str(s))
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
main()
使用 return s
是正确的做法,因为它允许测试脚本调用 hSum(n)
函数并获得 s
的最终值。这适用于测试 1 和 2,return为 5 和 7 设置正确的值。
我认为第三个测试有错误,或者我看不到测试代码实现方式的核心差异。此问题导致冲突 - 在测试 1 和 2 中,它期望函数 return 5 和 7 的值 包括 5 和 7。对于最终测试,它期望它 return 10 的值包括 10 但打印值 不包括 10。可以为此编写一个解决方法以通过测试,但是虽然是 - 你通过了任意测试 - 如果你保持原样,代码将不会像它那样起作用。这是测试驱动开发的常见问题。您的测试需要完美才能产生好的代码。
除非其他人有我遗漏的解释,否则我建议向您发送消息 tutor/lecturer 并询问此冲突。
FWIW 这里有一个解决方法,它根本不打印最终结果。我不推荐这样编码,但它通过了所有测试。
import sys
def hSum(n):
s = 0
for i in range(n+1):
if i == 0:
s = 0
else:
s += 1 / i
if(i != n):
print(str(i) + " " + str(s))
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
main()
我同意 yuuuu 的观点,多看一些可能会有帮助。
还有一个叫做 shebang (#!/usr/bin/env python3) 的东西,您可以将它放在文件的顶部以使其也可执行。它应该是您文件中的第一行(在导入或任何内容之前)。它告诉 OS 使用什么来执行文件。它看起来像下面的代码:
#!/usr/bin/env python3
import sys
def hSum(n):
s = 0
...
正如 yuuuu 所指出的,您调用了 main(),但由于它的缩进,看起来您正在调用 main() 函数本身。您可以只调用 main() 就像您正在尝试做的那样(但缩进正确),但还有另一种选择, name == 'main' if 语句。 Here is a more in-depth explanation of that https://www.freecodecamp.org/news/if-name-main-python-example/ ,但我的理解是它是调用函数的标准方式或 w/e 从命令行执行 python 脚本时
#!/usr/bin/env python3
import sys
def hSum(n):
s = 0
for i in range(n + 1):
if i == 0:
s = 0
else:
s += 1 / i
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
if __name__ == '__main__':
main()
编辑//
没有 yuuuu 询问的信息,很难给出更多的答案。
我在 MatLab 中做过一些编程,但我对 Python 完全陌生。对于我们的第一个项目,我们的老师希望我们编写调和和 (1/1+1/2+1/3...
) 和一个“可以直接从 shell 执行的完整程序,如下所示:
$ python3 hsum.py 10
0 0
1 1.0
2 1.5
3 1.8333333333333333
4 2.083333333333333
5 2.283333333333333
6 2.4499999999999997
7 2.5928571428571425
8 2.7178571428571425
9 2.8289682539682537
我是这样管理的:
import sys
def hSum(n):
s = 0
for i in range(n + 1):
if i == 0:
s = 0
else:
s += 1 / i
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
main()
主要问题是我并不真正理解他所说的“可以直接从shell执行的完整程序”是什么意思。显然第二个问题是,当我 运行 他提供的“测试”文件,测试程序是否正确时,它告诉我:
function main should generate exactly the same output as in the assignment
Got:
[blank]
Instead of:
[the list in the previous quote]
这里是 test.py 代码:
import sys
import importlib.util
def testEq(res, ref, msg):
global pass_tests, fail_tests
if res == ref:
pass_tests = pass_tests + 1
else:
print(msg)
print("Got:")
print(res)
print("Instead of:")
print(ref)
fail_tests = fail_tests + 1
def test(fun, x, y):
global pass_tests, fail_tests
if type(x) == tuple:
z = fun(*x)
else:
z = fun(x)
if y == z:
pass_tests = pass_tests + 1
else:
if type(x) == tuple:
s = repr(x)
else:
s = "(" + repr(x) + ")"
print("Condition failed:")
print(" " + fun.__name__ + s + " == " + repr(y))
print(fun.__name__ + " returned/printed:")
print(str(z))
fail_tests = fail_tests + 1
def run(src_path=None):
global pass_tests, fail_tests
saved_stdout = sys.stdout
sys.stdout = io.StringIO()
saved_argv = sys.argv
sys.argv = ["hsum.py", "10"]
if src_path == None:
import hsum
else:
spec = importlib.util.spec_from_file_location("hsum", src_path + "/hsum.py")
hsum = importlib.util.module_from_spec(spec)
spec.loader.exec_module(hsum)
sys.argv = saved_argv
out = sys.stdout.getvalue()
sys.stdout = saved_stdout
pass_tests = 0
fail_tests = 0
fun_count = 0
if hasattr(hsum, "hSum"):
fun_count = fun_count + 1
test(hsum.hSum, 5, 2.283333333333333)
test(hsum.hSum, 7, 2.5928571428571425)
else:
print("hSum is not implemented yet!")
if hasattr(hsum, "main"):
fun_count = fun_count + 1
testEq(out,
"0 0\n1 1.0\n2 1.5\n3 1.8333333333333333\n4 2.083333333333333\n5 2.283333333333333\n6 "
"2.4499999999999997\n7 2.5928571428571425\n8 2.7178571428571425\n9 2.8289682539682537\n",
"function main should generate exactly the same output as in the assignment")
else:
print("main is not implemented yet!")
print(str(pass_tests) + " out of " + str(pass_tests + fail_tests) + " passed.")
return fun_count == 2 and fail_tests == 0
if __name__ == "__main__":
run()
现在您的代码不打印或 return 任何东西。这可能是 copy/pasting 中的一个错误 - 如果您取消缩进最后一行 main()
然后它会运行并且 hSum()
return 是 s
的单个值,因为代码是写给。现在这最后一行作为 main()
函数本身的一部分执行(导致它无限循环),但函数本身从未真正被调用,所以什么也没有发生。
您能否也上传一份 test.py 脚本?目前还不清楚它希望如何 returned.
根据第一个引号判断,它只是想让您打印所有值。您可以通过在 for
循环中添加 print(str(i) + " " + str(s))
轻松地做到这一点(当然是在计算 s
之后)。您不需要 return s
,因为这会导致 hSum()
“等于”s
(例如,value = hSum()
会导致 value
取值 return由函数编辑),但你没有对这些信息做任何事情。
使用以下代码,我通过了 2/3 的测试。稍后我会解释为什么。
import sys
def hSum(n):
s = 0
for i in range(n + 1):
if i == 0:
s = 0
else:
s += 1 / i
print(str(i) + " " + str(s))
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
main()
使用 return s
是正确的做法,因为它允许测试脚本调用 hSum(n)
函数并获得 s
的最终值。这适用于测试 1 和 2,return为 5 和 7 设置正确的值。
我认为第三个测试有错误,或者我看不到测试代码实现方式的核心差异。此问题导致冲突 - 在测试 1 和 2 中,它期望函数 return 5 和 7 的值 包括 5 和 7。对于最终测试,它期望它 return 10 的值包括 10 但打印值 不包括 10。可以为此编写一个解决方法以通过测试,但是虽然是 - 你通过了任意测试 - 如果你保持原样,代码将不会像它那样起作用。这是测试驱动开发的常见问题。您的测试需要完美才能产生好的代码。
除非其他人有我遗漏的解释,否则我建议向您发送消息 tutor/lecturer 并询问此冲突。
FWIW 这里有一个解决方法,它根本不打印最终结果。我不推荐这样编码,但它通过了所有测试。
import sys
def hSum(n):
s = 0
for i in range(n+1):
if i == 0:
s = 0
else:
s += 1 / i
if(i != n):
print(str(i) + " " + str(s))
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
main()
我同意 yuuuu 的观点,多看一些可能会有帮助。
还有一个叫做 shebang (#!/usr/bin/env python3) 的东西,您可以将它放在文件的顶部以使其也可执行。它应该是您文件中的第一行(在导入或任何内容之前)。它告诉 OS 使用什么来执行文件。它看起来像下面的代码:
#!/usr/bin/env python3
import sys
def hSum(n):
s = 0
...
正如 yuuuu 所指出的,您调用了 main(),但由于它的缩进,看起来您正在调用 main() 函数本身。您可以只调用 main() 就像您正在尝试做的那样(但缩进正确),但还有另一种选择, name == 'main' if 语句。 Here is a more in-depth explanation of that https://www.freecodecamp.org/news/if-name-main-python-example/ ,但我的理解是它是调用函数的标准方式或 w/e 从命令行执行 python 脚本时
#!/usr/bin/env python3
import sys
def hSum(n):
s = 0
for i in range(n + 1):
if i == 0:
s = 0
else:
s += 1 / i
return s
def main():
hSum(int(sys.argv[1])) # a command he has specified for us to use
if __name__ == '__main__':
main()
编辑// 没有 yuuuu 询问的信息,很难给出更多的答案。