26

I wanted to see if it was possible to define new keywords or, as they're called in Destroy All Software's "WAT" talk when discussing Ruby, bare words, in Python.

I came up with an answer that I couldn't find elsewhere, so I decided to share it Q&A style on StackOverflow.

kaya3
  • 47,440
  • 4
  • 68
  • 97
ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
  • 1
    Does anyone care to explain why they're downvoting/voting to close? I'm sharing knowledge that could be useful for anyone looking to add new keywords in Python without having to actually modify the interpreter's source code and recompile it. Could this be misused? It almost certainly will be. But if you really want to do it, then I have provided this here for you. And if you don't want to do it, then just move along - there's no need to downvote or to vote to close. – ArtOfWarfare Apr 17 '15 at 14:50
  • 3
    An interesting use case for this would be implementing an interactive command line interface without input(). That way, you have the full power of an interactive shell and a cli at the same time. It is an anti-pattern, but it is interesting. – RobotHumans Sep 24 '15 at 21:29
  • 4
    You're too far ahead of the curve: that's why... **;-)** It's not by inventing a tablet that you'll make money but by refining it and calling it an iPad that you will, so 1 up-vote (which will counteract 5 down-votes) **>:-)** – Fabby Sep 24 '15 at 21:49
  • Gaze too long into the abyss, and the abyss gazes into you. – Shayne Jul 18 '16 at 03:15
  • I was thinking about that talk and googled "bare words programming" to find out what was being quickly mentioned and then passed by. This was the first result. (also glad so didn't close a helpful question) – Old Badman Grey Jul 25 '17 at 15:43
  • Hey!! I am here for the same reason. We are all de same . All f*** nerds. – Pablo Oct 23 '18 at 21:46

1 Answers1

26

I've only tried this in the REPL, outside any block, so far. It may be possible to make it work elsewhere, too.

I put this in my python startup file:

import sys, traceback

def bareWordsHandler(type_, value, traceback_):
    if isinstance(value, SyntaxError):
        import traceback

        # You can probably modify this next line so that it'll work within blocks, as well as outside them:
        bareWords = traceback.format_exception(type_, value, traceback_)[1].split()

        # At this point we have the raw string that was entered.
        # Use whatever logic you want on it to decide what to do.
        if bareWords[0] == 'Awesome':
            print(' '.join(bareWords[1:]).upper() + '!')
            return
    bareWordsHandler.originalExceptHookFunction(type_, value, traceback_)

bareWordsHandler.originalExceptHookFunction = sys.excepthook
sys.excepthook = bareWordsHandler

Quick REPL session demonstration afterwords:

>>> Awesome bare words
BARE WORDS!

Use responsibly.

Edit: Here's a more useful example. I added in a run keyword.

if bareWords[0] == 'from' and bareWords[2] == 'run':
        atPrompt.autoRun = ['from ' + bareWords[1] + ' import ' + bareWords[3].split('(')[0],
                            ' '.join(bareWords[3:])]
        return

atPrompt.autoRun is a list of variables that, when my prompt is displayed, will automatically be checked and fed back. So, for example, I can do this:

>>> from loadBalanceTester run loadBalancerTest(runJar = False)

And this gets interpreted as:

from loadBalancerTest import loadBalancerTest
loadBalancerTest(runJar = False)

It's kind of like a macro - it's common for me to want to do this kind of thing, so I decided to add in a keyword that lets me do it in fewer keystrokes.

ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
  • 1
    @Shayne I think these kinds of things are where new languages are born from. You do evil ugly things in existing languages, until eventually you decide to turn it into its own new official language. IE, I've heard C++ started life as a bunch of macros to make OO design easier in C. – ArtOfWarfare Feb 25 '16 at 00:26
  • 10
    This is my favourite SO answer. This is *such* an abuse of an otherwise sensible and syntactically strict language, +1 – cat Apr 10 '16 at 18:14
  • 3
    @cat - Thanks. I'm glad I didn't give into peer-pressure and delete this when the initial reaction was all negative (the question got downvoted 5 times and the answer 3 times, all within a few hours of me posting it. Took several months for them to actually get positive scores.) – ArtOfWarfare Apr 10 '16 at 18:36
  • In all honestly, I was browsing the [tag:bareword] tag and saw this one, and I was prepared for a VLQ question from a Python newbie, but I'm impressed. Imma go scatter this throughout my company's codebase. – cat Apr 10 '16 at 19:06
  • @cat - If you insist on doing that, please make sure that it's well documented... future maintainers will hate you if you do this and don't document it. – ArtOfWarfare Apr 10 '16 at 19:09
  • 1
    Nahh, documentation's for chumps :P they can figure it out! I believe in them. – cat Apr 10 '16 at 20:34
  • A little trolling does everyone a little good... especially when I don't actually have any company's codebase to mess with (unfortunately) :D – cat Apr 10 '16 at 20:35
  • So you can execute but not return from your bareword handler? So you can't implement operators like "not" or "is"? (took already existing operator, no inspiration for easy to understand usefull new ones þ) – Julien Palard Aug 25 '16 at 08:15
  • @JulienPalard - The entire line will come back to you. You can scan for your new keyword, then run everything on the left through `exec` to have the normal Python interpreter run that, then do the same with everything on the right, then combine the two results however you like. – ArtOfWarfare Aug 25 '16 at 11:25
  • @JulienPalard - If you wanted to make it "return" something you could fake that... You could inject the results into a global variable, then run exec on the original line with the proper part replaced by the name of that global variable. Post as a new question if you're having problems trying this. – ArtOfWarfare Aug 25 '16 at 11:31
  • Hey my comment got deleted at some point! (I basically said it was Evil, and I probably also said I loved it). Maybe a bot that doesnt understand programmers use the word "Evil" differently to other folks – Shayne Jul 06 '22 at 04:43
  • I should note this doesnt work in python 3. If anyone has a work around , I'm all ears. EVIL EARS. – Shayne Jul 06 '22 at 04:45
  • @Shayne - My example was missing `import traceback` and also had a typo in the name of the function. I fixed both issues and found it still works fine for me in the Python 3.8.5 interactive shell on macOS. – ArtOfWarfare Jul 08 '22 at 23:20