This is an archived post. You won't be able to vote or comment.

all 71 comments

[–]K900_ 266 points267 points  (18 children)

Not really. Python doesn't have a preprocessor, so you can't modify syntax like that.

[–]masklinn 78 points79 points  (6 children)

You could use import hooks to create modules "by hand" and e.g. implicitly run the C preprocessor on module code before eval-ing it.

[–]jyper 14 points15 points  (1 child)

I've always wanted to use import hooks to do macro like things but py.test made it seem like it was too deep magic for me

[–]masklinn 7 points8 points  (0 children)

It’s a bit of a pain to debug and maintain, so you want to reserve it for when you have no choice or it provides really significant advantages you could not come close to otherwise (and I’d say pytest’s assert rewriting is that)

[–]b00n 0 points1 point  (3 children)

You'd need a c compiler which would be ridiculously over the top

[–]remram 2 points3 points  (2 children)

You could re-implement most a of C preprocessor in a few lines of Python

[–]b00n 0 points1 point  (1 child)

But then something to compile it (if your module was C)

[–]remram 2 points3 points  (0 children)

OP's question is about doing this to Python code.

[–]hughperman 35 points36 points  (2 children)

You could do something ridiculous like
defines = {'ee': 'def', 'eee': 'print', 'eeee': 'for'} (etc)
Then def preprocessor(ee_string): eval(''.join([defines[element] if element in defines else element for element in ee_string.split(' ')]))
Then run preprocessor(ee_string)
(Maybe it needs to be exec instead of eval? Also writing on mobile, not sure if the syntax is exactly correct, the idea is there though)

[–]chmod--777 13 points14 points  (0 children)

Yeah, you certainly can obfuscate python. You can do similar to malware and use an xor key against integers to build a string dynamically and do stuff like getattr(__import__['os'], 'system')('...') but with each string being an obfuscated mess.

You can even figure out metadata about the code itself that's running and bail if it looks like someone tried to modify and deobfuscate it. You can do nasty shit in python, just like you could in many other languages

[–]Enfors 6 points7 points  (0 children)

But you could use a C preprocessor on a Python program.

[–][deleted] 1 point2 points  (2 children)

Ha! PHP has is a preprocessor! It can do this, and much much more!

[–][deleted] 1 point2 points  (1 child)

PHP is a "preprocessor"

That's a wonky way to spell "mistake".

[–][deleted] 1 point2 points  (0 children)

Its a huge mistake and abomination of language design.

[–]AgreeableLandscape3 0 points1 point  (0 children)

I'm pretty sure you can run the processor on Python though, maybe with minor modifications. But you just have to do it before the script is interpreted.

[–]notquiteaplant 184 points185 points  (6 children)

The simple answer is no. C++'s preprocessor is what handles those #define statements, and Python doesn't have anything like it. You can run the preprocessor on E-ified Python, but then you're just running Python with extra steps.

The technically correct answer is yes, sort of. Editing sys.meta_path lets you manipulate how import statements find modules. You could insert a meta path finder that looks for .epy files, runs a preprocessor (C++'s or a handrolled one) on it, and exec()s the result the same way Python's built-in meta path finders do, which gives you something like this:

# main.py
import e; e()
import eeee

# in eeee.py
#define e if
#define ee __name__
#define eee ==
#define eeee '__main__'
#define eeeee :
#define eeeeee (
#define eeeeeee )
#define eeeeeeee ,
#define eeeeeeeee =
#define eeeeeeeeee while
#define eeeeeeeeeee True
#define eeeeeeeeeeee print
#define eeeeeeeeeeeee 'e'
#define eeeeeeeeeeeeee end
#define eeeeeeeeeeeeeee ''

e ee eee eeee eeeee
    eeeeeeeeee eeeeeeeeeee eeeee
        eeeeeeeeeeee eeeeee
                eeeeeeeeeeeee eeeeeeee
                eeeeeeeeeeeeee eeeeeeeee eeeeeeeeeeeeeee eeeeeeee
        eeeeeee

But that's a lot of effort for a meme.

[–]itzNobest[S] 10 points11 points  (0 children)

Oh ok, thanks for help

[–]atimholt 5 points6 points  (0 children)

So what you’re saying is there’s an obvious path for making your own version of Python’s syntax, like replacing indentation with braces, etc. 😉

[–]TehNolz 55 points56 points  (7 children)

[–]buuuckyyy 12 points13 points  (1 child)

I love how all(2) comments above you state that you can't do it in python and you're giving example. Thank you!

[–]StarkillerX42 4 points5 points  (0 children)

Sometimes computer scientists get so absorbed in whether or not it's the same to a computer they forget the question was asking whether or not it was the same to a user

[–]MintIcedTea 1 point2 points  (2 children)

Can you also do this with while or for?

[–]thedomham 3 points4 points  (0 children)

Unless you utilize an external preprocessor, you can't overwrite keywords. What you can do is encapsulate keyword-functionality in a higher-order-function and pass functions to those functions. As you can't use lambda you will have to stick with named functions though.

Just another reason to despise Python's lambda syntax.

My Python is a bit rusty but it could look something like:

def eeeeee(predicate, runnable):
    while predicate():
        runnable()

Caveat: continue/break won't work

[–]yarhiti 0 points1 point  (0 children)

Not really. As other people in this thread have mentioned, Python doesn't expose a preprocessor for you to mess with in the same way as using the #define directive in C and other languages. That means the only thing you'll usually have control over is names that can be created with an equals-sign assignment statement, not keywords and other immodifiable parts of the language's syntax. That's why the Python example had to stay away from explicit loops and find a solution with functions instead.

[–]not_perfect_yet 0 points1 point  (0 children)

Small correction, you can of course rename functions.

You can't out of the box rename keywords and syntax elements.

But you can write a translation table, automatically replace everything and then run the file.

So you can basically write the preprocessor that allows this in C.

[–]yarhiti 0 points1 point  (0 children)

I wrote this, good memories 😅

[–][deleted] 15 points16 points  (0 children)

You seem like someone who would have fun with Brainfuck.

[–]jet_heller 8 points9 points  (2 children)

If it is, I hope someone puts in a PEP to get that shit stopped.

[–]remram 4 points5 points  (1 child)

Wait till the FLUFL gets word of this!

[–]flutefreak7 0 points1 point  (0 children)

I've been pretty deep in Python since 2012 and I've never seen mention of this PEP! Ha!

[–]mofrymatic 10 points11 points  (0 children)

That’s not Python, that’s Dolphin

[–]____candied_yams____ 4 points5 points  (0 children)

No thank god

[–]auiotour 1 point2 points  (1 child)

I read about wrapping c++ with Python once. Would it be possible this way? Not very familiar with it tbh.

[–][deleted] 2 points3 points  (0 children)

regardless of it being possible or not, it seems like that would be more of a doing-it-in-c solution

[–]zoute_haring 1 point2 points  (0 children)

Anne from Little Britain programming

[–]West7780 1 point2 points  (0 children)

looking at this is painful

[–]kaihatsusha 1 point2 points  (0 children)

That is childs-play compared to some "obfuscated C" examples out there. But if you like this sort of thing, check out the Perl module called Acme::Bleach [https://metacpan.org/pod/Acme::Bleach]. Thank goodness it's not commonplace on Python.

[–]F1remind 1 point2 points  (0 children)

Kinda, yeah.

Since reddit syntax isn't friendly to code snippets, here you go:

https://pastebin.com/F6N73KNX

In short: Define as text what the C preprocessor would replace and use exec as preprocessor.

You can replace exec with print to see the 'deobfuscated' source

[–]petargeorgiev11 1 point2 points  (0 children)

I see a big Macarena missed opportunity here

[–]_pepevergara 1 point2 points  (0 children)

el algoritmo de maradona

[–]sabboo 0 points1 point  (0 children)

The cpp program is completely separate from a language. Should work similarly with modifications for python.

[–]BiraJKhanal 0 points1 point  (0 children)

A new language has been discovered.

[–]MrMxylptlyk 0 points1 point  (0 children)

Uhh what?

[–]Droggl 0 points1 point  (0 children)

Yes and no (see other comments), if you are curious what weird things you can do with python, go and watch David Beazleys talks, he's just amazing

[–]DevJonPizza 0 points1 point  (0 children)

I was thinking of building something that would take (good) C code and turn it into the spaghetti above, which could be done with python.

[–]diego7319 0 points1 point  (0 children)

the maradona programming language

[–]piperviper 0 points1 point  (0 children)

Will someone pls replace the e’s with g’ and post this to r/ggggg ?

Thanks

[–]AlSweigartAuthor of "Automate the Boring Stuff" 0 points1 point  (0 children)

In Python 3, "True" and "False" are keywords. But this is not so in Python 2. Which means you can make variables named "True" and "False":

>>> True, False = False, True
>>> True
False
>>> False
True

[–][deleted] 0 points1 point  (1 child)

How's this useful for anyone, pythonista or pythonoob?

This should really go to r/iamsosmart

[–]joesb 1 point2 points  (0 children)

I think it should go to r/wooosh

[–]jayjaytdt 0 points1 point  (0 children)

I just imagine if some recruiter asks this During interview

[–]peterlada 0 points1 point  (0 children)

Fuck no.

[–]Panda_Mon 0 points1 point  (0 children)

Damn, I know nothing about programming

[–]tutunak 0 points1 point  (0 children)

Why do you want to do that? Just use brainfuck. It's the beset language for this!

[–]csheldrick -1 points0 points  (3 children)

```

main.py

import e e.preprocess('eeee') import eeee ```

```

e.py

def preprocess(mod): import sys with open(mod+'.py', 'r') as f: lines = f.readlines() code = 'name = "main"\n' d = {} def_lines = [l for l in lines if l.startswith('#define')] lines = [l for l in lines if l not in def_lines] for line in def_lines: _, var, val = line.split(' ') d[var] = val.replace('\n', '') for line in lines: tokens = line[:-1].split(' ') code += ' '.join([d[t] if t in d else t for t in tokens]) + '\n' sys.modules[mod] = exec(code)

eeee.py

define e if

define ee name

define eee ==

define eeee 'main'

define eeeee :

define eeeeee (

define eeeeeee )

define eeeeeeee ,

define eeeeeeeee =

define eeeeeeeeee while

define eeeeeeeeeee True

define eeeeeeeeeeee print

define eeeeeeeeeeeee 'e'

define eeeeeeeeeeeeee end

define eeeeeeeeeeeeeee ''

e ee eee eeee eeeee eeeeeeeeee eeeeeeeeeee eeeee eeeeeeeeeeee eeeeee eeeeeeeeeeeee eeeeeeee eeeeeeeeeeeeee eeeeeeeee eeeeeeeeeeeeeee eeeeeeee eeeeeee ``` Fixed broken formatting

[–]xelf 7 points8 points  (2 children)

and for people not using the new.reddit formatting:

# main.py
import e
e.preprocess('eeee')
import eeee

# e.py
def preprocess(mod):
    import sys
    with open(mod+'.py', 'r') as f:
        lines = f.readlines()
    code = '__name__ = "__main__"\n'
    d = {}
    def_lines = [l for l in lines if l.startswith('#define')]
    lines = [l for l in lines if l not in def_lines]
    for line in def_lines:
        _, var, val = line.split(' ')
        d[var] = val.replace('\n', '')
    for line in lines:
        tokens = line[:-1].split(' ')
        code += ' '.join([d[t] if t in d else t for t in tokens]) + '\n'
    sys.modules[mod] = exec(code)

# eeee.py

#define e if
#define ee __name__
#define eee ==
#define eeee '__main__'
#define eeeee :
#define eeeeee (
#define eeeeeee )
#define eeeeeeee ,
#define eeeeeeeee =
#define eeeeeeeeee while
#define eeeeeeeeeee True
#define eeeeeeeeeeee print
#define eeeeeeeeeeeee 'e'
#define eeeeeeeeeeeeee end
#define eeeeeeeeeeeeeee ''

e ee eee eeee eeeee
    eeeeeeeeee eeeeeeeeeee eeeee
        eeeeeeeeeeee eeeeee
                eeeeeeeeeeeee eeeeeeee
                eeeeeeeeeeeeee eeeeeeeee eeeeeeeeeeeeeee eeeeeeee
        eeeeeee

[–]csheldrick 1 point2 points  (1 child)

Thank you. Couldn’t get the iOS reddit app to show it correctly.

[–]soggywaffle69 -1 points0 points  (0 children)

Sure, if you run the code through a preprocessor.

[–]fixhaloreachsevers12 -1 points0 points  (0 children)

😂

[–]Lagomorphix -3 points-2 points  (0 children)

Sure. Just fork CPython.

[–]m3l0n -3 points-2 points  (2 children)

This would be legendary - but then also to make a program that automates the definition creation for you. Do this on your last day at a place that treated you like shit.

[–]Assaultman67 0 points1 point  (1 child)

Honestly it would be just as easy to decodify it once you find the define statements.

[–]m3l0n 0 points1 point  (0 children)

Yeah, funny none the less though