Search code examples
pythonprintingbuilt-in

print('Hello World!') not using 'e' nor 'p' in the code with python


This question might seem silly. It's a simple useless task, but I believe it's a good way to learn things (I did learn a lot while doing this kind of tricks).

So, idea is in the title: No 'e' allowed => no eval() or exec() No 'p' allowed => no print() or import

What I tried is to get the print function from:

dir(__builtins__)[133]

but it's returned as a string, I found no way to get it as a callable function.


Solution

  • Since the order of the builtins dict is random, this is not a very useful thing to do, unless you're just as happy calling staticmethod as print.

    But it may be worth knowing how to get from there to the next step you were trying to get to.

    Modules are just objects, like any other objects. So, you can get their attributes with getattr. OK, so that's against your rules. But most objects—including modules—store their attributes in a dict. So:

    >>> dir(__builtins__)[133]
    'staticmethod'
    >>> __builtins__.__dict__[_]
    <type 'staticmethod'>
    

    Is there any way we could actually get print? Well, maybe not guaranteed, but pretty close:

    >>> [v for k, v in __builtins__.__dict__.items() if 'rint' in k]
    [('print', <function print>)]
    

    Oops, I used an e for that items, right? Fine:

    >>> [__builtins__.__dict__[k] for k in __builtins__.__dict__ if 'rint' in k]
    [<function print>)]
    >>> [__builtins__.__dict__[k] for k in __builtins__.__dict__ if 'rint' in k][0]('zzz')
    zzz
    

    But meanwhile, how were you planning to build the string 'Hello World!' without an e? There are lots of options—\x or \u escapes, or something really silly like rot13. And all of those options would work to get you the string 'print' just as easily. So, I'm not sure why you're trying to pull print out of the module's names in the first place.

    >>> __builtins__.__dict__['\x70rint']
    <function print>
    

    As John Anderson pointed out in a comment, using the inspect module is nicer than going to the __dict__. For one thing, it works for objects that store attributes elsewhere—or even objects that generate them on the fly with a custom __dir__ and __getattr__.

    >>> [v for k, v in inspect.getmembers(__builtins__) if k == 'print'][0]
    <function print>
    

    The problem is, how do we get the inspect module? We can use the same backslash/etc. tricks to get the name 'inspect' easily, but (unless we can assume it was already imported into sys.modules—and that sys is also already imported), we need to import or __import__ or use importlib or… they've all got a p in them. And then, to get at getmembers, we need to go through the inspect module's dict to look it up by name.

    But still, maybe it's better to do that once than every time:

    >>> i = __builtins__.__dict__['__im\x70ort__']
    >>> ins = i('ins\x70\x65ct')
    >>> gm = ins.__dict__['g\x65tm\x65mb\x65rs']
    >>> builty = lambda nam: dict(gm(__builtins__))[nam]
    >>> builty('\x70rint')
    <function print>
    >>> builty('\x65val')
    <function eval>
    

    Of course using lambda to create a named function in a statement rather than an anonymous one in an expression is an anti-pattern, but then this whole post is a pile of anti-patterns. I'm doing it here to avoid the need for def and return, both of which have es (as pointed out by Elliot Frisch). (It's hard to notice all the es you type; even Gadsby had three accidental e's in it, and it's famous for being the novel with no e's…)


    I'm sure someone is hoping that I'm going to show how to get around this by just using a compiled bytecode literal, right?

    Unfortunately, there's only two ways to run a code object: either you wrap it up in a function object—which requires getting FunctionType, which requires either an import or a call to type—or you exec or eval it—which are already out.

    Plus, in Python 3, all you'd be doing is cramming the constants "print" and "Hello, World" into co_names and co_consts, and then it's just a LOAD_NAME, LOAD_CONST, CALL_FUNCTION, RETURN_VALUE (which, coincidentally, happens to start with e: b'e\x00d\x00\x83\x01S\x00').

    In Python 2, on the other hand, print is a statement, and has a special PRINT_ITEM bytecode, so it's maybe a bit more fun:

    >>> ty = builty('typ\x65')
    >>> gattr = builty('g\x65tattr')
    >>> f = lambda: None
    >>> c = gattr(f, 'func_cod\x65')
    >>> ct = ty(c)
    >>> cc = ct(0, 0, 1, 0x43, 'd\x00\x00\x04GS', ('H\x65llo World!',),
    ...         (), (), '', 'h\x65llo', 0, '')
    >>> xval = builty('\x65val')
    >>> xval(cc)
    Hello World!
    'Hello World!'
    

    (The extra quoted output at the end is because I just returned "Hello World!" because I was too lazy to dig up None. The code is LOAD_CONST 0; DUP_TOP; PRINT_ITEM; RETURN_VALUE.)