Quine in Python3
I finally took a stab at writing a quine, a program that outputs a copy of itself. I’d learned about quines when I first started programming, maybe even in middle school, but whereever I read about it said something along the lines of “but wait, before you read how to do it, why not try it yourself?”. So I’ve diligently avoided looking at an example of a quine since. This afternoon I decided to actually try it though, and it turned out less difficult than I thought. I knew that generally (unless you’re using some weird quirk of the programming language) the way to do it would be to have the text of the program stored as data (ex. a string) and then have the program itself be capable of reading the data and printing it out twice, once to be a copy of the data and once again to be a copy of the program.
My first result ended up like this:
data = "data = \n\
instructions = data.splitlines()[-1].split()\n\
for code in instructions:\n\
if code == 'n': print()\n\
elif code == 'q': print(chr(34),end=chr(0))\n\
elif chr(58) in code:\n\
starti, endi = code.split(chr(58))\n\
print(chr(10).join(data.splitlines()[int(starti):int(endi)]))\n\
elif chr(59) in code:\n\
starti, endi = code.split(chr(59))\n\
print((chr(92)+'n'+chr(92)+chr(10)).join(data.splitlines()[int(starti):int(endi)]),end=chr(0))\n\
else:\n\
print(data.splitlines()[int(code)],end=chr(0))\n\
0 q 0;14 q n 1:13"
instructions = data.splitlines()[-1].split()
for code in instructions:
if code == 'n': print()
elif code == 'q': print(chr(34),end=chr(0))
elif chr(58) in code:
starti, endi = code.split(chr(58))
print(chr(10).join(data.splitlines()[int(starti):int(endi)]))
elif chr(59) in code:
starti, endi = code.split(chr(59))
print((chr(92)+'n'+chr(92)+chr(10)).join(data.splitlines()[int(starti):int(endi)]),end=chr(0))
else:
print(data.splitlines()[int(code)],end=chr(0))
I used chr()
because I didn’t want to have to worry about escaping special characters in quotes.
Essentially the program is an interpreter capable of processing a few instructions. The possible codes it processes are as follows:
n
: print a newlineq
: print a quote character "a:b
: print the range a:b of lines in thedata
variablea;b
: print the range a:b of lines in thedata
variable, but at\n\
at the end of each linea
: print linea
of thedata
variable without a newline
The text of the interpreter program is stored in the data
variable, along with the line data =
and the code that the interpreter interpreter runs 0 q 0;14 q n 1:13
. The code that the interpreter runs works like this:
0
: print line 0, “data =”q 0;14 q
: copy out exact full text of data (including\n
chars) with quotes around itn
: add a newline to separate data section and interpreter1:13
: print out interpreter (does not includedata =
line and the line being interpreted)
This works, but the interpreter is clearly overkill since theres only one program it’s actually supposed to run. Still, it was a good idea to design something with more “infrastructure” first. It allows me to then gradually make the program more efficient by removing unneccessary “infrastructure”. Here’s the same idea, but with the program “built in”:
data = "data = \n\
lines = data.splitlines()\n\
text = (chr(92)+'n'+chr(92)+chr(10)).join(data.splitlines()[0:len(lines)])\n\
print(lines[0]+chr(34)+text+chr(34))\n\
print(chr(10).join(lines[1:len(lines)]))"
lines = data.splitlines()
text = (chr(92)+'n'+chr(92)+chr(10)).join(data.splitlines()[0:len(lines)])
print(lines[0]+chr(34)+text+chr(34))
print(chr(10).join(lines[1:len(lines)]))