42
\$\begingroup\$

Just like , pushes one to exploit quirks and hidden features of the Python language. We already have a place to collect all these for , those for remain transmitted by word of mouth or hidden deep within the python documentation.

So today I would like to ask you what are some for solving challenges in Python?

Please only include 1 tip per answer.


What makes a good tip here?

There are a couple of criteria I think a good tip should have:

  1. It should be (somewhat) non obvious.

    Similar to the tips it should be something that someone who has golfed in python a bit and read the tips page would not immediately think of. For example "Replace a + b with a+b to avoid using spaces", is obvious to any golfer, since it is already a way to make your code shorter. Thus it is not a good tip here.

  2. It should not be too specific.

    Since there are many different types of source restrictions, answers here should be at least somewhat applicable to multiple source restrictions, or one common source restriction. For example tips of the form How to X without using character(s) Y are generally useful since banned characters is a common source restriction. The thing your tip helps to do should also be somewhat general. For example tips of the form How to create numbers with X restriction are useful since many programs utilize numbers regardless of the challenge. Tips of the form How to implement Shor's algorithm with X restriction are basically just answers to a challenge you just invented and not very helpful to people solving other challenges.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This and this. \$\endgroup\$
    – nope
    Commented Aug 18, 2020 at 14:46
  • 2
    \$\begingroup\$ I think you can avoid == and ==0 with the ^ and ^0 operations. Does this count as a wat for doing restricted source? \$\endgroup\$
    – user96495
    Commented Aug 19, 2020 at 1:55
  • 7
    \$\begingroup\$ Reading the answers, but pretending you are on codereview.SE is good entertainment. \$\endgroup\$ Commented Aug 21, 2020 at 19:05
  • 1
    \$\begingroup\$ Make use of answers from the Fewest (distinct) characters for Turing Completeness challenge. Another solution \$\endgroup\$
    – mbomb007
    Commented Aug 21, 2020 at 21:52

17 Answers 17

32
\$\begingroup\$

Avoid "normal" letters

Identifiers are normalized by the Python 3 parser. This implies that cursive (Unicode) letters such as 𝓪𝓫𝓬𝓓𝓔𝓕 are interpreted as their ASCII-compliant equivalents abcDEF. So the following code works (as was exploited here):

𝓝=123
𝓹𝓻𝓲𝓷𝓽(𝓝)

Python versions in which this behaviour is confirmed:

  • Works: 3.4, 3.5, 3.6, 3.7, 3.8
  • Doesn't work: 2.7

Example source restriction:

  • Use no characters abc···xyz, ABC···XYZ.
\$\endgroup\$
4
  • 1
    \$\begingroup\$ @AdHocGarfHunter Anyway, this will always work in Python 3.7 \$\endgroup\$
    – user96495
    Commented Aug 19, 2020 at 8:06
  • \$\begingroup\$ I can confirm it works in 3.6.9, and doesn't in 2.7 (even with #coding=utf8) \$\endgroup\$
    – Chris H
    Commented Aug 21, 2020 at 10:58
  • 1
    \$\begingroup\$ @ChrisH Thank you! I have included this information in the answer \$\endgroup\$
    – Luis Mendo
    Commented Aug 21, 2020 at 11:43
  • \$\begingroup\$ This text converter can help with this. \$\endgroup\$
    – Wheat Wizard
    Commented Mar 18 at 22:12
25
\$\begingroup\$

Avoid Numbers with Booleans

When performing arithmetic operations on Booleans, Python treats them as if they are the numbers 1 and 0. So for example

>>> True+False
1

You can make all positive numbers by just adding booleans to each other.

You can also substitute the booleans for boolean values, for example []>[] is False and [[]]>[] is True so

>>> ([]>[])+([[]]>[])
1

In some cases, Booleans can even be used in place of a number without having to using arithmetic to cast it. For example, you can index into lists/tuples/strings with Booleans, so:

>>> ['a','b'][True]
'b'

Example source restrictions:

  • Use no digits (0123456789)

  • Use no alphanumeric characters

  • Use no if conditions

\$\endgroup\$
22
\$\begingroup\$

Avoid Parens with List indexing

Parentheses are super useful for creating the correct operator precedence so it is a bummer when they are banned. However if [] are still available we can use them instead. Simply replace

(...)

with

[...][0]

This creates a list and indexes it to get its only element. The list causes the inside to be evaluated first solving your precedence issue.

The example above uses the characters []0 to do this however there are other third characters that can be used in this case if need be.

  • Using characters []> write [...][[]>[]]
  • Using characters []< write [...][[]<[]]
  • Using characters []= write [...][[[]]==[]]

Example source restriction:

  • Use no parentheses
\$\endgroup\$
20
\$\begingroup\$

Function calls without parentheses

We can avoid using parentheses for operator precedence using list indexing, but parentheses are still very useful for calling functions.

List indexing can be used here as well to solve the issue, however it is a lot more complex so I've made it its own answer.

In order to call a function we start by making a new class which has it's indexing defined to be the function. So if we want to call print this might look like

class c:__class_getitem__=print

Then to call the function we simply index it with the argument we want. For example to print "Hello World" we do

c["Hello World"]

This has a few unfortunate short comings:

  • It can only be used to call functions with one parameter.
  • There are quite a few characters that are required to pull this trick off. ( :=[]_acegilmst)
  • It uses up a lot of characters if you are doing

But sometimes it might be your only option.


Example source restriction:

  • Use no parentheses

Here's an example of it being used.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ You can use multiple parameters with some exec abuse. Here's an example \$\endgroup\$ Commented Aug 19, 2020 at 21:53
18
\$\begingroup\$

Use << and | to generate constant without +

Fun fact: You can get any positive constant only using []<|. The way to go is left-shifting a boolean. []<[[]] is 1, so []<[[]]<<[]<[[]] should left-shift 1 with 1, which is 2.

Does it work?

>>> []<[[]]<<[]<[[]]

Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    []<[[]]<<[]<[[]]
TypeError: unsupported operand type(s) for <<: 'list' and 'list'

...No.

The precedence is wrong. Luckily, we can resolve this with "Ad Hoc Garf Hunter Parenthesis(TM)":

>>> [[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]
2

Aha!

To get numbers other than power of two, you still need +... or not. | or [bitwise or][[]<[]]* will do that for you.

>>> [[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]|[[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]
10

To get negative numbers without -, you may want to use ~.

* That part was enclosed in an "Ad Hoc Garf Hunter Parenthesis(TM)" to indicate precedence.

\$\endgroup\$
1
  • 5
    \$\begingroup\$ From these answers, it looks like Brainfuck is actually a subset of Python... That's interesting! \$\endgroup\$
    – Egor Hans
    Commented Mar 17, 2021 at 14:06
16
\$\begingroup\$

Access methods and built-in functions through __dict__

Classes contain a __dict__ attribute, which maps their method names to the methods themselves. If you can't type a method name directly, you can get them from this __dict__.

For example, let's say you need to append something to a list, but you can't use the characters p,n,+, etc. Since append() is the 26th method in a list's __dict__, you can call the method like this:

a = [1,2,3]
list(a.__class__.__dict__.values())[26](a, 4)
print(a)  # prints [1,2,3,4]

Try it online!

This can also be used with __builtins__ to access built-in functions. Even if someone bans the character x to block the exec function, you can still call exec like this:

list(__builtins__.__dict__.values())[20]("print('Hello, World!')")

Try it online!

This works best in more recent versions of Python that guarantee dictionary order, but there are probably other ways to use this in older versions, like iterating through the __dict__ with a regex or substring match.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ This is so convoluted and ridiculous. I love it. \$\endgroup\$
    – Wheat Wizard
    Commented Aug 19, 2020 at 0:15
  • 2
    \$\begingroup\$ The index is 13 in Python 2.7. Or (ord(sys.version[0])*13-637) \$\endgroup\$
    – Oskar Skog
    Commented Aug 21, 2020 at 15:27
14
\$\begingroup\$

Use ord() or binary strings to avoid digits

Most integers in the ranges [32..47] and [58..126] can easily be obtained from the ASCII code of a single character with:

x=ord('A')

# or, if parentheses are not allowed:

y=b'A'[False]

Try it online!

Larger integers can also be produced using from their unicode points:

>>>print (ord("±"))
177
>>> print (ord("π"))
960

If you can use an assignment, or you need to avoid brackets you can unpack the values, instead. Note that this will not work inline, even with the walrus operator.

x,*_=b'A'
y,_=b'A_'

Try it online!

Example source restrictions:

  • Use no digits
  • Use no digits / no parentheses / no brackets
\$\endgroup\$
0
12
\$\begingroup\$

Alternatives to eval and exec

Do you need to treat a string as code, but you can't use eval or exec? There are at least three other ways to execute a string:

1) timeit.timeit

import timeit
_=timeit.timeit("print('Hello!')", number=1)

Try it online!

timeit runs number times and returns an average of how long it took. By default it runs 1 million times, so you'll almost certainly want to set number=1 or raise an exception to break out (e.g. "print('hello'); 0/0").

Thanks to Ethan White for showing me this approach.

2) os.system

import os
c='echo "import math;print(math.pi)" | python3'
_=os.system(c)  # Prints 3.141592653589793

Try it online!

os.system runs an arbitrary shell command and returns its exit code. If you just need to print something, you can stick to echo, but you can also execute arbitrary code by calling python3 itself.

3) code.InteractiveInterpreter().runcode

from code import InteractiveInterpreter as I
i = I()
i.runcode("print('Hello!')")

Try it online!

code is specifically designed for read-eval-print loops, and even though it's a bit clunky, this is the most powerful of the three. timeit and os.system isolate their processes, but an InteractiveInterpreter can use global state instead of its own:

from code import InteractiveInterpreter as I
a = 64
i = I(globals())
i.runcode("import math; a=math.log2(a)")
print(a)        # a = 6.0
print(math.pi)  # math is imported globally

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ #4. Sympy ACE vulnerabilities \$\endgroup\$
    – emanresu A
    Commented Apr 20, 2022 at 10:43
  • \$\begingroup\$ For the timeit.timeit approach if the code is the only thing you are executing you could avoid setting number by adding something to the end to stop execution before a second run. For example exit() if you want to stop cleanly or a undeclared variable if you are fine with crashing the program. Proof of concept \$\endgroup\$
    – Wheat Wizard
    Commented Sep 30, 2022 at 3:50
11
\$\begingroup\$

Use -- to avoid +

E.g to do a+b:

a--b

Example source restriction:

  • Avoid the + operator
\$\endgroup\$
0
5
\$\begingroup\$

Encode restricted characters and use exec()

Like most interpreted languages, Python can run a string as code with eval and exec. eval is more limited, but exec can handle imports, function definitions, loops, exceptions, etc.

When combined with some of the other tips about encoding characters, this allows you to write your code normally:

import sys

def f(i):
 return 1 if i==1 else i*f(i-1)

i=int(sys.argv[1])
print(f(i))
    

Then pick an encoding and pass the encoded version to exec:

exec('\x69\x6d\x70\x6f\x72\x74\x20\x73\x79\x73\x0a\x0a\x64\x65\x66\x20\x66\x28\x69\x29\x3a\x0a\x20\x72\x65\x74\x75\x72\x6e\x20\x31\x20\x69\x66\x20\x69\x3d\x3d\x31\x20\x65\x6c\x73\x65\x20\x69\x2a\x66\x28\x69\x2d\x31\x29\x0a\x0a\x69\x3d\x69\x6e\x74\x28\x73\x79\x73\x2e\x61\x72\x67\x76\x5b\x31\x5d\x29\x0a\x70\x72\x69\x6e\x74\x28\x66\x28\x69\x29\x29\x0a')

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Replace operators with dunder methods

Most python operators are syntactic sugar for specific method calls (often called "magic methods" or "dunder methods", with "dunder" being short for "double underscore"). For example, + calls __add__(), == calls __eq__(), and << calls __lshift__()

If operators are restricted, you can call these methods directly:

a = 1
print(a.__add__(1).__eq__(2))  # True

Try it online!

For assignment, you can use __setitem__ on the locals() or globals() dictionaries, whether or not the variable already exists:

a = 1
locals().__setitem__('a',2)
locals().__setitem__('b',2)
print(a.__add__(b).__eq__(4))  # True

Try it online!

Note that you'll have to add parentheses around numbers to avoid a syntax error. 4.__eq__(4) won't work, but (4).__eq__(4) will.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ 4 .__eq__(4) also works. \$\endgroup\$ Commented Aug 19, 2020 at 16:38
  • \$\begingroup\$ aha! Got it! Then my method of avoiding + is completely nonsense. \$\endgroup\$ Commented Aug 20, 2020 at 1:43
5
\$\begingroup\$

Use __import__("module") instead of import module

To avoid whitespace in the import statement, or to dynamically construct the name of the module to import as a string (e.g. "RANDOM".lower() if you can't use a lowercase d). Not likely that useful because you don't often need the standard library, and you still need to be able to use _, i, m, p, o, r, t, (, and ).

Edit: or as Ad Hoc Garf Hunter suggests, you can use import<tab>module (with a literal tab character)!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ It might be worth mentioning, if you only need to avoid spaces you can just use a tab between import and the module name. \$\endgroup\$
    – Wheat Wizard
    Commented Aug 21, 2020 at 17:31
  • \$\begingroup\$ You can also assign the return value to an alias. For example, if you can't type a, you could use m=__import__('MATH'.lower()); print(m.pi) \$\endgroup\$ Commented Aug 21, 2020 at 19:14
  • \$\begingroup\$ @AdHocGarfHunter Pretty sure Python also accepts the "vertical tab" character. \$\endgroup\$
    – mbomb007
    Commented Aug 21, 2020 at 21:50
5
\$\begingroup\$

File Encodings

You can set a custom encoding for your Python source file in a comment at the start. This includes various Unicode things, but also text transforms such as unicode_escape and punycode, which can be used for restricted source!

Here's an example:

# encoding: unicode_escape
print(\x22Hello, World!\x22)

Attempt This Online!

Here's the exact specification of an encoding line, from the Python documentation:

If a comment in the first or second line of the Python script matches the regular expression coding[=:]\s*([-\w.]+), this comment is processed as an encoding declaration; the first group of this expression names the encoding of the source code file

So, for , the best definition is therefore #coding:unicode_escape.

This works not only at the file level, but also with exec and eval if you pass them a byte string:

print(eval(rb'''# encoding: unicode_escape
\x22Hello, World!\x22'''))

Attempt This Online!

Not as useful there though because you can generally just pass a constructed string.

\$\endgroup\$
4
\$\begingroup\$

This is likely not relevant to the question but it's very silly.

This is (maybe) a more portable way of water_ghost's convoluted method of accessing builtin methods.
The index is 26 only on CPython 3. This very small and extremely easy to understand modification allows it to run on CPython 2.7, CPython 3, PyPy 2.7 and PyPy 3 (tested on Debian 10 amd64)

a = [1, 2, 3]
list(a.__class__.__dict__.values())[[14,13,26,25][sum(map(ord,{__import__("sys").version[0],__import__("platform").python_implementation()[0]}))&3]](a, 4)
print(a)

The correct indices (on my system) are

CPython 2.7    13
CPython 3      26
PyPy 2.7       26
PyPy 3         25

And by a lucky coincidence ('C'+'2')%4 == 1, ('C'+'3')%4 == 2, ('P'+'2') == 2 and ('P'+'3') == 3. The value 14 is there to trick you into thinking there is a pattern.

\$\endgroup\$
4
\$\begingroup\$

Use * to avoid /

x**-1 is equivalent to 1/x. So to do y/x you can do x**-1*y.

If you desperately want to get rid of the -1, you can check out Ad Hoc Garf Hunter's other tip.

Example source restriction:

  • Avoid using the / character
\$\endgroup\$
1
  • \$\begingroup\$ You can also do x**-y \$\endgroup\$
    – nTerior
    Commented Nov 3, 2021 at 21:38
3
\$\begingroup\$

How to create characters just with numbers, quotes and backslashes

Strings can be composed with \ooo where ooo is the octal value of the character.

Eg:

'\141'=='a'

You can also use hex, at the expense of an x (and a,b,c,d,e and/or f if they're used):

'\x61'=='a'  

And unicode at the expense of a u (two pre-Python 3) and hex characters if they're used:

'\u2713'=='✓'
\$\endgroup\$
0
3
\$\begingroup\$

__debug__ is True

Pretty self-expl... expl...

>>> __debug__
True
\$\endgroup\$
1
  • 4
    \$\begingroup\$ Ha! I figured out how to gain rep! Just post random comment-like answers everywhere! \$\endgroup\$ Commented Aug 27, 2020 at 11:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.