Python 如何创建一个可以直接从shell执行的程序(调和和)?

Python 如何创建一个可以直接从shell执行的程序(调和和)?,python,function,shell,executable,main,Python,Function,Shell,Executable,Main,我用MatLab做过一些编程,但我对Python完全陌生。对于我们的第一个项目,我们的老师希望我们编写一个调和和(1/1+1/2+1/3…)和一个“可以直接从shell执行的完整程序,如下所示: $python3 hsum.py 10 0 0 1.1.0 2.1.5 3 1.8333333 4 2.083333 5 2.2833333 6 2.4499999997 7.2.5928571428571425 8.2.7178571428571425 9.2.8289682539682537 我是这

我用MatLab做过一些编程,但我对Python完全陌生。对于我们的第一个项目,我们的老师希望我们编写一个调和和(
1/1+1/2+1/3…
)和一个“可以直接从shell执行的完整程序,如下所示:

$python3 hsum.py 10
0 0
1.1.0
2.1.5
3 1.8333333
4 2.083333
5 2.2833333
6 2.4499999997
7.2.5928571428571425
8.2.7178571428571425
9.2.8289682539682537

我是这样管理的:

导入系统 def hSum(n): s=0 对于范围(n+1)内的i: 如果i==0: s=0 其他: s+=1/i 返回s def main(): hSum(int(sys.argv[1])#他指定给我们使用的命令 main() 主要问题是我实际上不理解他所说的“一个可以直接从shell执行的完整程序”是什么意思。显然,第二个问题是,当我运行他提供的“测试”文件时,它会测试程序是否正确,它会告诉我:

main函数应生成与赋值中完全相同的输出
得到:
[空白]
而不是:
[上一引用中的列表]

下面是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()





现在,您的代码不打印或不返回任何内容。这可能是复制/粘贴中的错误-如果您取消输入最后一行
main()
,那么它将运行,并且
hSum()
在代码写入时返回一个
s
值。现在,这最后一行作为
main()
函数本身的一部分执行(使其无限循环),但函数本身从未真正被调用,因此不会发生任何事情

您是否也可以上传test.py脚本的副本?目前尚不清楚它希望如何返回结果

从第一个引号判断,它只是想让您打印所有的值。您可以通过在
for
循环中添加
print(str(i)+“+str(s))
来轻松完成这一操作(当然,在计算
s
之后)。您不需要
返回s
,因为这将导致
hSum()
s
相等(例如,
value=hSum()

使用下面的代码,我的测试通过了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()
使用
returns
是正确的做法,因为它允许测试脚本调用
hSum(n)
函数并获得
s
的最终值。这对测试1和2正确工作,返回5和7的正确值

我认为第三个测试有一个错误,或者在测试代码的实现方式上有一个我看不到的核心差异。这个问题导致了冲突-在测试1和2中,它希望函数返回5和7的值,包括5和7。对于最终测试,它希望返回10包括10的值,但打印不包括1的值0.为了通过测试,可以为此编写一个变通方法,但如果是的,即通过了任意测试,则代码的功能将不如您保持原样。这是测试驱动开发的常见问题。您的测试需要完美才能生成好的代码

除非有人解释我失踪,否则我建议给你的导师/讲师发邮件,询问这一冲突

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)的东西,你可以把它放在文件的顶部,使它也可以执行。它应该是文件中的第一行(在导入或任何操作之前)。它告诉操作系统使用什么来执行文件。它看起来像下面的代码:

#!/usr/bin/env python3
import sys


def hSum(n):
    s = 0
...
正如Yuuu指出的,调用main()时,由于缩进的原因,它看起来像是在调用main()函数本身。您可以像调用main()时那样(但缩进正确)进行调用,但还有另一个选项,name='main'if语句。这里有一个更深入的解释,但我的理解是,这是从命令行执行python脚本时调用函数或w/e的标准方式

#!/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()
编辑//
如果没有Yuuu询问的信息,很难给出更多的答案。

谢谢,我已经更新了帖子,加入了test.py。我没有注册
main()
,但现在它给了我一条信息:
回溯(最近一次调用):\File“xxx”,第16行,in main()\File“xxx”,第15行,in main\hSum(int(sys.argv[1]))\索引器:列表索引超出范围
@Cacti我在回答中添加了对我有效的代码,将查看测试代码,并查看它的确切期望值。@Cacti-您自己在问题的第一段中编写了完整的程序,可以直接从shell执行,如下所示:…-现在您只需继续并执行即可它是这样的。@Cacti只是再次阅读您的注释,此错误意味着sys.argv参数列表中没有“1”元素。此列表是您在运行脚本时在“python”之后编写的内容列表-其中sys.argv[0]是脚本的路径。[1]超出范围表明您没有在路径后添加要计算的数字。谢谢,我已更新帖子以包含test.py。我希望尽可能保持此代码的基本性,因为这是我们的第一项任务。您是否尝试过您所说的我已这样管理的代码?