# Non-idempotent Python [closed]

Write a few lines of Python code, X, that does not reference any global variables, such that

def method():
X
print(a)

method()


prints 1 but

def method():
X
X
print(a)

method()


prints 2.

So, I hate to be a stickler, but it seems like vars and locals are actually global variables in Python:

def test_global_1():
global vars, locals
vars = lambda: 2
locals = lambda: 3

def test_global_2():
print(vars())
print(locals())

test_global_1()
test_global_2()


Also, it looks like people would like to see objective winning criteria for puzzles like this. Code length doesn't really feel right here so perhaps we could make a system of brownie points for various novel features of the code? I'm not sure exactly what these could be but here's a start:

• +1 for really truly no globals (no vars or locals)
• +1 for being the first to post a particular technique
• +1 for the shortest solution posted
• +1 for a solution involving only a single Python statement
• +1 for interesting "hacks" like joining at lexical non-boundaries
• +1 for not using exceptions

And if you can think of more you could edit this question to add to the list.

Can this problem be solved without using exceptions and without using globals like vars and locals? I suspect it can, though I haven't figured out exactly how yet...

• Good puzzle! I made sure not to scroll down so I could solve it myself without seeing anyone's answers. :D – mbomb007 Jul 30 '15 at 21:36
• Thanks for the puzzles Owen, and welcome to the site. There is a rule on the site that all questions must have an objective winning condition, so you should probably add one. One possibility is shortest length of X, but there are other options. – isaacg Jul 31 '15 at 8:25
• "all questions must have an objective winning condition" - Stupid rule imho. Who cares about a "winner" when we all actually most enjoy the puzzling and learning from the different answers. – JimmyB Jul 31 '15 at 11:34
• Please add a code-golf or popularity-contest tag, depending on whether you want people to optimize for shortness code or for general popularity. I imagine code-golf is better for this challenge (popularity-contest is encouraged only for challenges that cannot be easily classified otherwise), but it's up to you. – apsillers Jul 31 '15 at 13:18
• You've added a scoring system, but also added the popularity contest tag, which means that a winner is decided by votes. What do you mean here? Perhaps you want votes just as a tiebreak? – xnor Aug 2 '15 at 2:13

def method():
if 'a' not in vars():a=0
a+=1
if 'a' not in vars():a=0
a+=1
print(a)


Initializes the variable a to 0 only if it's not already initialized in the variables table. Then, increments it.

More briefly (thanks to histocrat for len):

def method():
a=len(vars())+1
a=len(vars())+1
print(a)


If the two copies of X could be on the same line, we could do

a=0;a+=1;a


which doubles to

a=0;a+=1;aa=0;a+=1;a


with the "sacrificial lamb" aa eating up the second variable assignment.

• I don't want to be a spoilsport posting this so fast, so how about we try for shortest code? – xnor Jul 30 '15 at 20:03
• Slightly shorter variant: a=len(vars())+1 – histocrat Jul 30 '15 at 20:50
• @histocrat Nice one, thanks! – xnor Jul 30 '15 at 21:03

# Python

Thought of this solution, since try and except was the first way I thought of to determine if a variable existed yet or not.

def method():
try:a+=1
except:a=1
print(a)


# Python 2

def method():
exec'';locals()['a']=locals().get('a',0)+1
exec'';locals()['a']=locals().get('a',0)+1
print a

method()


Basically, when exec is encountered in Python 2, it causes a special flag (0x01) to be removed from method.func_code.co_flags, which makes locals assignments have an effect. I exploited this to implement nonlocal support in Python 2 (see line 43 for the xor that modifies the flag).

• Why not a = locals().get('a', 0) + 1? – Vincent Jul 31 '15 at 13:15
• @Vincent I was tiree. :O Fixed. – kirbyfan64sos Jul 31 '15 at 14:15
• In that case you don't need exec'' any more ;) – Vincent Jul 31 '15 at 14:20
• @Vincent Eh, maybe I should just stick with the longer version. It felt more creative. Now it just seems a lot like a clone of the top-voted answer... :/ – kirbyfan64sos Jul 31 '15 at 14:23

My first idea (and then smooshing it) was:

def method():
a=2if'a'in vars()else 1
a=2if'a'in vars()else 1
print(a)


My attempt. Uses the math module to track if X is run once or twice.

def module():
import sys
if 'math' in sys.modules:
a+=1
else:
a=1
import math

import sys
if 'math' in sys.modules:
a+=1
else:
a=1
import math

print(a)

module()

def method(a=[]):
a.append(a)
print len(a)


Edited in response to comment: a is a list of empty lists of length n, where n is the number of time you've called method. Calling this method twice prints 1 then 2.

• Putting a=[] as a parameter is outside the parameters for this challenge. – mbomb007 Jul 31 '15 at 2:57
• Sorry, this is my answer, and it's not very good. This is (arguably) a surprisingly non-idempotent operation in python, but there's no way to slot it into the format provided for the challenge without also making the challenge trivial. – WithScience Jul 31 '15 at 17:29
• Also, the challenge asks to print 1 or 2, not just two different things. – xnor Jul 31 '15 at 22:52
def method():
#### X-block
try:a
except NameError:a=1
else:a=2
####
print(a)


The try block checks if the variable a is defined.
If variable not defined,(this is only when X-block is present once) then NameError Exception is raised.
If variable is defined, (this is when X-block is present twice) then else will be entered .

• Yeah, that's the solution I found by searching Google. Then I created my current solution, which is shorter. – mbomb007 Jul 30 '15 at 21:46
• @mbomb007 Yeah :P. Your way is shorter than using else – Kamehameha Jul 30 '15 at 21:50