2

I've started working on a fairly simple baseball program and have run into an issue regarding a function. I've used functions with a variable before, so I'm not sure why this isn't working.

home = 0
def basestate(base):
    if base is 0:
        base = 1
        print(base)
    else:
        base = 0
basestate(home)
print(home)

Base will print as one, but home will not. I would ideally like to make a simple state switch between one and zero. This seemed like the easiest way to do it, but I'm no expert.

Thanks for any help,

Zach

zachlip98
  • 23
  • 2
  • 6
    You've stumbled upon the difference between "pass by reference" and "pass by value". The difference depends on the language. In a language that passes parameters by reference, changes made to argument parameters *are* reflected in the arguments when the function returns. In a language that passes parameters by value, the value of the parameter is copied to the function, effectively creating a local copy of the variable. Changes to the local, function-scope variables are not reflected in the original variable used as a parameter. Apparently, Python is pass-by-value when it comes to primitives. – Misha May 01 '14 at 21:37
  • Perhaps you want to read this http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference – 01zhou May 01 '14 at 21:37
  • 3
    You should also use `==` instead of `is` for testing equality. `is` tests for object equality whereas `==` tests for value equality. Check out this for more info: http://stackoverflow.com/questions/306313/python-is-operator-behaves-unexpectedly-with-integers – Mdev May 01 '14 at 21:40
  • @Misha Ah, that is actually very interesting. Thanks for explaining. – zachlip98 May 01 '14 at 22:06
  • @Misha, strictly speaking, Python is none of pass by reference or pass by value. It's pass by assignment. Also, as far as I know, "the value of the parameter is copied to the function, effectively creating a local copy of the variable" is not accurate for Python. The fact that the change to the variable is only seen locally, is to do with the mutability/immutability of the value. When you first pass in the argument, both the local variable and the original one outside the variable will be pointing to same location in memory. – s16h May 01 '14 at 22:33
  • @s16h I admit, I'm not a Python user by any means, hence my prefix of "apparently". Thanks for the clarification! – Misha May 01 '14 at 22:36
  • @Misha, your explanation does kind of get the point across; I was just being a bit more precise, although I'm sure my explanation isn't 100% accurate either. – s16h May 01 '14 at 22:39

3 Answers3

1

The easiest way for you to solve this is to return a value from basestate and assign the returned value to home.

home = 0
def basestate(base):
    if base == 0:
        return 1
    else:
        return 0

home = basestate(home)
print(home)

Update

A more pythonic definition of basestate, thanks to s16h:

def basestate(base):
    return 1 if base == 0 else 0
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

There are a couple different things that come up when looking at your code:

Mutable vs. Immutable Data Types

As mentioned in Python's reference:

The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable. (The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.) An object’s mutability is determined by its type; for instance, numbers, strings and tuples are immutable, while dictionaries and lists are mutable.

So, in the case of home = 0, 0 is a number so it is immutable.

Pass by Assignment

In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates. Jeff Knupp goes over this in more depth with more example in this blog post.

What happens in your code...

So, when you have home = 0, now we know that the name home points to the immutable number 0. When you call basestate(home), the local name base is assigned the same object that b is pointing to; the 0. At this point, id(home) == id(b) (In CPython, id(object) is the address of the object in memory.). However, when you say base = 1 (or base = 0), then since numbers (int in this case) are immutable, the name base is assigned a new number object 1. The old 0 object is still reference by home but not by base. So, now id(home) != id(base) because their are no longer pointing to same place in memory.

So, you are assigning 1 (or 0) to base and as soon as the function exits, base is no longer in scope and it hasn't changed anything else like home because numbers are immutable.

So what do I do?

You need to return the required value and re-assign it to home:

home = 0

def basestate(base):
    return 1 if base == 0 else 0

basestate(home)
print(home)

P.S. Don't use is for that kind of comparison. In general, you use == when comparing values and is when comparing identities. In this case you are comparing values. But in the case where I said id(home) == id(base), I could have said home is base

P.P.S Using id() on small numbers is actually quite cunning because the current CPython implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object.

I hope this help!

s16h
  • 4,647
  • 1
  • 21
  • 33
0

I would ideally like to make a simple state switch between one and zero

How about using True/False for a binary state switch?

home = False

home = not home
print(home) # True

home = not home
print(home) # False again
ojdo
  • 8,280
  • 5
  • 37
  • 60