Quine -- 打印自己的代码
今天在 github 上看到一个巨牛逼的项目 quine-relay. 所谓 Quine 就是能够打印自己源代码的程序( 当然不能用读取自身源文件的形式啦). 仿照 Wikipedia 上的 JAVA 示例, 我用 Python 也写了一个练习(其实就抄一遍).
def quine():
quotemark = 34
body = [
"def quine():",
" quotemark = 34",
" body = [",
" ",
" ]",
" for i in range(3): # print header line",
" print(body[i])",
" for i in range(len(body)): # print body",
" print(body[3] + chr(quotemark) + body[i] + chr(quotemark) + ',')",
" for i in range(4, len(body)): # print statements after body",
" print(body[i])",
]
for i in range(3): # print header line
print(body[i])
for i in range(len(body)): # print body
print(body[3] + chr(quotemark) + body[i] + chr(quotemark) + ',')
for i in range(4, len(body)): # print statements after body
print(body[i])
思路大致如下:
要打印自身的源代码, 所以首先肯定要把源代码作为 string 存储起来并打印. 按这里的代码我们把这个 string 称为 body. 除了 body 自身之外, 它前后的代码只要直接放进 body 里面就好了. 但是 body 自身的赋值过程并不能存进 body 里, 不然会无限的递归下去. 这样 打印 body 就是一个自指的问题.
因此, 程序的结构以这个 body 为界可以分为三部分(看懂了示例觉得很自然, 但自己完全想不到). 那么打印程序也就分为三部分, 首先打印 body 前的内容, 再打印 body 自身, 最后打印 body 后的内容.
所以我们可以得到程序的雏形:
def quine():
body = [
"def quine()",
" body = [",
" what's to be placed here",
" ]",
"print(first two lines of body)",
"print(body)",
"print(print statements)",
]
print(first two lines of body)
print(body)
print(print statements)
为什么 body 要用 list 存放呢? 注意, body 自身和程序的结构是完全一样的! 所以 body 也是分成了三部分. 那怎么打印 body 呢? 把 body 里的 string 都打印一遍就好了嘛. 这样就可以得到最上面的代码了. 因为引号里不能放引号, 所以要用 ascii 码转一下.
打印 print statements 的时候需要注意把 body 结尾的 “]” 那行加进去. 有 意思的是, 把 body 自身的内容放到 body 里去会导致递归, 但其实那里可以放 任何东西. 只要记得处理一下缩进. 比如像下面这个也是可以的, 当然这个得益 于 python 字符串可以用单引号来表示.
def quine():
quotemark = 34
body = [
"def quine():",
" quotemark = 34",
" body = [",
" ]",
" for i in range(3): # print header line",
" print(body[i])",
" for i in range(len(body)): # print body",
" print(' ' + chr(quotemark) + body[i] + chr(quotemark) + ',')",
" for i in range(3, len(body)): # print statements after body",
" print(body[i])",
]
for i in range(3): # print header line
print(body[i])
for i in range(len(body)): # print body
print(' ' + chr(quotemark) + body[i] + chr(quotemark) + ',')
for i in range(3, len(body)): # print statements after body
print(body[i])