Composing Python built-ins to make text
A friend of mine sent me an ominous message:
Don’t run this in the Python repl
print(chr(sum(range(ord(min(str(not())))))))
I figured that somehow this piece of code would crash the interpreter or something of the like, but after disregarding his suggestion, I was delighted to see the code print:
ඞ
How does this string of incomprehensibly nested function compositions create anything at all?
-
not()
Python’s not operator on an empty tuple. Empty tuples are considered to be false in a boolean sense, so the output of this is the negation. Result:True
-
str(True)
Cast boolean to string. Result:"True"
. -
min("True")
Search through each character in the string, and return the one with the smallest Unicode Codepoint value. Capital letters come before lowercase letters. Result:"T"
-
ord("T")
Take a single character and return the codepoint value as an integer. Result:84
. -
sum(range(84))
I’ve lumped these two together because they work as a unit. This finds the sum of all integers between 0 and 83 (inclusive). Result3486
. -
chr(3486)
take an integer codepoint and convert it back into a character. Result:ඞ
.
Hello World #1
The ඞ
example above got me thinking: just what can be made by composing built-in functions?
An obfuscated hello world string was an obvious first thought for me
print(
chr(max(range(max(range(ord(max(str(complex(int()))))))))),
next(reversed(str(bool()))),
chr(max(range(max(range(max(range(ord(max(oct(int())))))))))),
chr(max(range(max(range(max(range(ord(max(oct(int())))))))))),
max(oct(int())),
min(str(slice(int()))),
chr(max(range(ord(max(hex(int())))))),
max(oct(int())),
max(str(range(int()))),
chr(max(range(max(range(max(range(ord(max(oct(int())))))))))),
chr(max(range(max(range(max(range(max(range(max(range(max(range(ord(max(str(complex(int())))))))))))))))))
)
Print is called with many parameters, each one being one of these composed function character expressions. The individual expressions were found by a janky recursive algorithm which was limited to a fixed depth. The shortest expression for a given character was chosen and the others discarded.
Hello World #2
I showed my fancy “hello world” string to the friend who brought on this chaotic rambling, and was fascinated by his reply.
That’s cool, but how about you write your python code with it?
Quite a devilish idea: make executable python code where each character is obfuscated into one of these composed function expressions.
Without much difficulty, I was able to add to the previous hello world string making it a hello world program. By wrapping it in an exec
expression, the program string is executed.
exec(
chr(max(range(max(range(ord(max(str(range(int()))))))))) +\
max(str(range(int()))) +\
chr(max(range(ord(max(str(complex(int()))))))) +\
chr(max(range(ord(max(oct(int())))))) +\
max(str(type(int()))) +\
min(str(set())) +\
chr(max(range(max(range(sum(range(len(bin(ord(max(str(not())))))))))))) +\
chr(max(range(max(range(max(range(max(range(max(range(max(range(sum(range(len(str(type(int())))))))))))))))))) +\
next(reversed(str(bool()))) +\
chr(max(range(max(range(max(range(ord(max(oct(int())))))))))) +\
chr(max(range(max(range(max(range(ord(max(oct(int())))))))))) +\
max(oct(int())) +\
min(str(type(int()))) +\
chr(max(range(max(range(max(range(max(range(ord(min(str(list())))))))))))) +\
max(oct(int())) +\
max(str(range(int()))) +\
chr(max(range(max(range(max(range(ord(max(oct(int())))))))))) +\
chr(max(range(ord(next(reversed(str(bool()))))))) +\
chr(len(str(slice(sum(range(sum(range(sum(range(ord(min(str(not()))))))))))))) +\
chr(max(range(max(range(sum(range(len(bin(ord(max(str(not())))))))))))) +\
next(reversed(str(set())))
)
So what are the rules?
I don’t know of any non-malicious uses of these composed function character expressions, but if you for whatever reason want to expand on my work here, I’ve jotted down some general rules for them.
- The expression must begin with a function call.
- The outermost function call must return a string of length 1.
- Each function call must be one of the built-in functions
- Each function call must either take one parameter or no parameters.
- Functions can only be called with other function calls as the parameter.
- The not operator on an empty tuple
not()
is to be considered a function call. - Functions can not be used in such a way that creates a final output which is dependant on the environment, interpreter, or other temporary state.
Here’s a table of the functions which should follow those rules (depending on how you use them)
bool | ascii | sum |
bytearray | bin | any |
complex | chr | all |
float | hex | callable |
dict | oct | enumerate |
frozenset | repr | memoryview |
bytes | format | iter |
set | round | next |
list | ord | property |
tuple | abs | range |
str | len | reversed |
object | max | slice |
int | min | sorted |
type |