Python puzzles

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Python puzzles

Postby Lopsidation » Thu Jul 03, 2014 6:44 pm UTC

Is this possible in Python? (Assume version 2.7.)

Code: Select all

(type whatever code you want here)
x = 1
print x # this line prints 0


Redefining print isn't allowed. (And I don't know if that's even possible.) Anything else is fair game.

How about this?

Code: Select all

(type whatever code you want here)
def f(x):
    return f(x)
print f(1) # this line prints 3.14

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Python puzzles

Postby EvanED » Thu Jul 03, 2014 7:04 pm UTC

Lopsidation wrote:Is this possible in Python? (Assume version 2.7.)

Code: Select all

(type whatever code you want here)
x = 1
print x # this line prints 0


Redefining print isn't allowed. (And I don't know if that's even possible.) Anything else is fair game.
I don't think you can redefine print with the version you have... if you had said print(x) instead then it'd be possible to do a __future__ import of print_function and then you could. :-)

Anyway, I've seen something like that done (and checked it myself) by messing with ctypes. (Nit: you didn't specify CPython, which matters. :-)) Basically the same trick can lead to the following amusing interaction:

Code: Select all

>>> 5+0
4
>>> 5+1
4
>>> 5+2
6

relevant thread.

How about this?

Code: Select all

(type whatever code you want here)
def f(x):
    return f(x)
print f(1) # this line prints 3.14
This one I'll have to think about.

Volcano99
Posts: 56
Joined: Wed Dec 16, 2009 10:10 pm UTC
Location: 350 km SW of The Castle

Re: Python puzzles

Postby Volcano99 » Thu Jul 03, 2014 7:43 pm UTC

For the first one:
Messing with the cached 1 and 0 will easily crash python, but maybe after the print statement. Is a segmentation fault allowed?

The second one is really easy:

Hint1:
Spoiler:
A quite python-specific feature makes it really easy.


Hint2:
Spoiler:
Use decorators!

Code:
Spoiler:

Code: Select all

def second_puzzle(f):
    def returns_pi(*args):
       return 3.14
    return returns_pi

@second_puzzle
def f(x):
   return f(x)

f(1) # returns 3.14

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Re: Python puzzles

Postby Lopsidation » Thu Jul 03, 2014 8:12 pm UTC

My solution doesn't redefine 0 or 1... but if you can do that and make Python print the 0 before crashing, more power to you! Multiple solutions are welcome.

Volcano99 got my intended solution for the second puzzle.

Volcano99
Posts: 56
Joined: Wed Dec 16, 2009 10:10 pm UTC
Location: 350 km SW of The Castle

Re: Python puzzles

Postby Volcano99 » Thu Jul 03, 2014 10:06 pm UTC

Some thoughts and things I tried for problem one:
Spoiler:
Overloading assignment is impossible in python (so can't make an object that ignores assignments)

So is monkeypatching builtin types (can't override int.__str__)

Descriptors only work for class attributes

Inserting '1':'0' into the globals() object can't create a variable named 1 with the value 0

Overriding globals() and locals() with an object whose __getitem__ always returns 0

What could work, but i didn't test:
making x global, then modifying it from another thread?
messing with sys.stdout, but that would be almost like redefining print

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Python puzzles

Postby EvanED » Thu Jul 03, 2014 10:53 pm UTC

Yeah, I actually tried my ctypes nonsense for #1 and didn't have any luck. I alternately got no effect or crashes. The crashes I can kind of see, but I'm surprised sometimes it just had no effect at all.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Python puzzles

Postby troyp » Fri Jul 04, 2014 12:29 am UTC

Volcano99 wrote:
Spoiler:
What could work, but i didn't test:
making x global, then modifying it from another thread?

Spoiler:
I assume we can't change the value from another thread. If we could do things other than just running the specified code, we could do anything, like run it within a program that shuts down the interpreter when it detects output and then prints 0. Besides, it's hard to see how that could work reliably: at best you'd end up with a race condition that might give the result in some circumstances.

Volcano99 wrote:
Spoiler:
messing with sys.stdout, but that would be almost like redefining print

Spoiler:
Something like that is the only thing I can think of, but I agree it sounds like it's probably disallowed.


Is the code given exactly what's allowed? For instance, there's no indentation missing (and so the code is all at the top level)?
I'm having trouble seeing how you could do the first one in pure Python, without screwing with the output itself.

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Re: Python puzzles

Postby Lopsidation » Fri Jul 04, 2014 12:59 am UTC

troyp wrote:Is the code given exactly what's allowed? For instance, there's no indentation missing (and so the code is all at the top level)?
I'm having trouble seeing how you could do the first one in pure Python, without screwing with the output itself.
Yes. The code given is exactly what's allowed, and there's no indentation missing.
My intended solution doesn't use threads or screw with the output itself. But again, if you can find a solution using those, more power to you!

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Python puzzles

Postby troyp » Fri Jul 04, 2014 2:54 am UTC

Actually...
Spoiler:
Is it required that the lines given actually execute? Can we just precede them with "print 0; exit"?
(It's not stated if this is a script that's being run or lines entered at the Python REPL.)

User avatar
Dopefish
Posts: 854
Joined: Sun Sep 20, 2009 5:46 am UTC
Location: The Well of Wishes

Re: Python puzzles

Postby Dopefish » Fri Jul 04, 2014 5:46 am UTC

troyp wrote:Actually...
Spoiler:
Is it required that the lines given actually execute? Can we just precede them with "print 0; exit"?
(It's not stated if this is a script that's being run or lines entered at the Python REPL.)


Spoiler:
Presumably the "#this line prints 0" part means that a preceding "print 0; exit" approach wouldn't be valid, as the line in question wouldn't actually be printing anything.

Volcano99
Posts: 56
Joined: Wed Dec 16, 2009 10:10 pm UTC
Location: 350 km SW of The Castle

Re: Python puzzles

Postby Volcano99 » Fri Jul 04, 2014 8:02 am UTC

Okay, found a way to breat sys.stdout:
Spoiler:

Code: Select all

#you can't just override the write function, we have to modify the whole stdout.
class problem_one:
    def write(self, arg):
         # python is very helpful again and keeps the original streams as magic objects.
         # we could save the original stdout object too, but i enjoy the underscores, makes it SRS BSNS
         # note we use the string 1 instead of the number 1, because print calls __str__ on its arguments.
         sys.__stdout__.write("0" if arg == "1" else arg)

import sys
sys.stdout = problem_one()
x = 1
print x

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Re: Python puzzles

Postby Lopsidation » Fri Jul 04, 2014 4:40 pm UTC

Nice!
Now that we have a solution, I'll give a tiny tiny hint for my intended method:
Spoiler:
I never redefine the literal "1", or the meaning of "=". And the line "x=1" executes normally: it's in the lowest indentation level, x is an ordinary global variable, and there's no multiple threads. Yet, after the line "x=1" executes, x is not 1.

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Python puzzles

Postby Nyktos » Fri Jul 04, 2014 10:55 pm UTC

This one might be cheating.
Spoiler:
Backslashes!

Code: Select all

x = 0
def y(): pass
y.\
x = 1
print x

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Re: Python puzzles

Postby Lopsidation » Fri Jul 04, 2014 11:08 pm UTC

Grrr!
I'm embarrassed to say I didn't think of that.
It's not technically cheating, so... now we have two solutions!

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Python puzzles

Postby EvanED » Fri Jul 04, 2014 11:59 pm UTC

Nice. It's no more cheating than the canonical problem 2 solution I'd say. :-)

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Python puzzles

Postby troyp » Sat Jul 05, 2014 4:34 am UTC

I really can't believe we all missed that. I guess it goes to show how much we use continuation lines.
(I actually do use them very occasionally, when it's the only way to achieve a readable formatting, but I'm always so horrified at what I've had to do I repress the whole experience.)

edit: So we still don't have the intended solution. I'm assuming it doesn't involve "\". So that means "x=1" is a complete statement on its own, right? Anything else that would continue a line, like a trailing operator, would require an indented line afterwards (that is always compulsory, right?) So I'm still not seeing any way forward without altering the output stream or using some module that affects Python internals. Is there something else obvious we're missing?

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Re: Python puzzles

Postby Lopsidation » Sun Jul 06, 2014 8:01 pm UTC

Hint:
Spoiler:
My solution for #1 involves defining a new class, and setting x to an instance of that class. You might find this page helpful: A Guide To Python's Magic Methods. I learned a lot of stuff from that page -- I mean, useful stuff, not just ways to make Python do weird puzzle crap.

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Python puzzles

Postby Nyktos » Sun Jul 06, 2014 8:56 pm UTC

Oh hell. I see it.
Spoiler:
Something like this, yes?

Code: Select all

class Foo(object):

    def __del__(self):
        global x
        x = 0


x = Foo()
x = 1
print x

That is pure evil right there. It also won't work (deterministically) on non-refcounting implementations like PyPy.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Python puzzles

Postby troyp » Sun Jul 06, 2014 10:28 pm UTC

I actually wasn't expecting something implementation-specific.

Spoiler:
Also, I didn't realise you could delete an object and count on it being garbage collected before the next statement executes. Is that always guaranteed?

Still, I like that solution.

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Python puzzles

Postby Nyktos » Sun Jul 06, 2014 10:49 pm UTC

troyp wrote:
Spoiler:
Also, I didn't realise you could delete an object and count on it being garbage collected before the next statement executes. Is that always guaranteed?
Spoiler:
It's not a language guarantee. It will always work in CPython provided the object isn't part of a reference cycle.

User avatar
Lopsidation
Posts: 183
Joined: Tue Oct 27, 2009 11:29 pm UTC

Re: Python puzzles

Postby Lopsidation » Mon Jul 07, 2014 12:01 am UTC

Yeah, that's it! Huh, I didn't know it was implementation specific. Makes sense that other versions of Python can handle
Spoiler:
garbage collection
differently though.


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 5 guests