【问题标题】:Is it possible to access the source code of a python script passed to python on standard in?是否可以在标准中访问传递给 python 的 python 脚本的源代码?
【发布时间】:2023-12-10 12:17:01
【问题描述】:

这是一个随机的问题,更多的是出于好奇而不是任何特定的需要。

是否可以编写一些 python 代码来打印一些东西,包括源代码本身,而无需将 python 代码存储在文件中?例如,在 Bash 提示符下执行以下操作:

$ echo '
> print "The Code:"
> PrintScript() # What would this function look like?
> for i in range(5):
>     print i,
> print "!"
> ' | python

得到这样的输出:

The Code:
print "The Code:"
PrintScript() # What would this function look like?
for i in range(5):
    print i,
print "!"
0 1 2 3 4 5 !

我怀疑这可能做不到,但是鉴于python的自省能力,我很想知道它是否扩展到了这个级别。

【问题讨论】:

    标签: python stdin quine


    【解决方案1】:

    这是我得到的最接近的:

    echo 'import  __main__,inspect;print inspect.getsource(__main__)' | python
    

    失败了......无论如何,原始代码在启动时被解释器吃掉(从标准输入读取)。最多您可以再次通过__main__ 模块访问编译后的代码。

    更新:

    dis 模块应该为您提供模块中所有函数的反汇编,但即使这样也看不到任何代码:

    $ echo -e 'import  __main__,dis;print dis.dis(__main__)' | python
    None
    

    即使我抛出一个函数:

    $ echo -e "import  __main__,dis;print dis.dis(__main__)\ndef x():\n pass" | python
    None
    

    【讨论】:

      【解决方案2】:

      是的,确实可以编写一个程序来输出它自己的源代码。您甚至不需要对此任务进行自省,您只需要能够打印计算字符串(适用于每种语言)。

      该技术称为Quine,这是一个相当简短的 Python 示例:

      quine = 'quine = %r\r\nprint quine %% quine'
      print quine % quine
      

      但 quines 并不局限于这些简单的程序。他们可以做更多的事情,例如向后打印自己的源代码等等...... :)

      【讨论】:

        【解决方案3】:

        罢工>

        print open(__file__).read(),
        

        我认为这适用于 UNIX 系统,但我不确定 Windows。尾随逗号确保源代码被准确打印,没有额外的尾随换行符。

        刚刚意识到(基于下面的 cmets)如果您的源代码来自 sys.stdin(这正是您所要求的),这将不起作用。在这种情况下,您可能会利用this page 中概述的关于 Python 中的 quines(打印自己的源代码的程序)的一些想法,但没有一个解决方案是一个可以正常工作的函数。独立于语言的讨论是here

        所以,简而言之,不,如果您的源代码来自标准输入,我认为使用单个函数是不可能的。 可能有可能将程序的解释形式作为 Python 代码对象访问并将其翻译回源形式,但翻译后的形式几乎肯定不会与原始文件内容完全匹配。 (例如,cmets 和 shebang 线肯定会被剥离)。

        【讨论】:

        • 这仅适用于您的代码在文件中的情况,而不是通过标准输入或python -c <command> 传入的代码。
        • 我试过这个(在 Windows 和 Linux 下的 Cygwin 上)并且都产生了一个异常:IOError: [Errno 2] No such file or directory: '<stdin>'
        • 可以sys.stdin读取,但是解释器已经在启动时读取并编译了你所有的代码,所以你不能通过这种方式得到它。
        • 谢谢,你说得对,我不够仔细,答案已修改。
        【解决方案4】:

        你能得到的最接近的方法是使用 readline 来询问命令历史记录(如果我可以看到 e.g.),但我怀疑这可能不包含通过管道传输到会话中的内容,并且无论如何只能用于交互式会话

        【讨论】:

          最近更新 更多