0

I'm confused about how Python scoping works here.

x = 1

def do(y):
    y = y * 2
    print y

print x
do(x)
print x

The code above produces this output:

1
2
1

The global variable remains unchanged, but in the function, the local variable prints out the correct changed value.

However, in this python-chess version I'm running below:

import chess
board = chess.Board()

def do(b):
    b.push(list(b.legal_moves)[0]) #picks the first legal move
    return b.fen()

print board.fen()
print do(board)
print board.fen()

It produces this output:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b KQkq - 1 1
rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b KQkq - 1 1

Unexpectedly (at least for me) the global variable board changes after the function has run.

I thought that a function creates a local variable instead of modifying the global variable - it seems you even need to imply specifically that you want to change it by using the global keyword. It seems to work in the simple multiplication example I used, perhaps it's due to the .push() method python-chess provides?

How would I then preserve the value of the global variable when running the function?

In this case, the output I desire should be:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b KQkq - 1 1
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
  • You can access any global variable inside a function, but you can't assign to it without a `global` directive. What's happening with your `board` is that you _aren't_ assigning a new object to the `board` name, you're mutating the existing `board` object, and that's perfectly fine. – PM 2Ring Jul 23 '17 at 20:02
  • You may find this article helpful: [Facts and myths about Python names and values](http://nedbatchelder.com/text/names.html), which was written by SO veteran Ned Batchelder. For a brief summary with nice diagrams, also see [Other languages have "variables", Python has "names"](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables). – PM 2Ring Jul 23 '17 at 20:04
  • Especially see the accepted answer by J.F. Sebastian in the linked question. – PM 2Ring Jul 23 '17 at 20:08
  • So if you want your `do` function to operate on a _copy_ of the board then you need to either pass it a copy, or get it to construct one. – PM 2Ring Jul 23 '17 at 20:14
  • Thank you @PM2Ring - can confirm it works with `do(board.copy())` –  Jul 23 '17 at 20:43

1 Answers1

0

My guess is that because "board" is some kind of object, python implicitly passes the reference of the object to the function, instead of making a copy of it. If you pass integral types, it most probably just makes copies. Google "python object pass by reference" and read what you find. That should shed some light to it.

travisjayday
  • 784
  • 6
  • 16
  • No. As J.F. Sebastian says in his answer to the linked question, "Python doesn't copy _objects_ you pass during a function call _ever_". – PM 2Ring Jul 23 '17 at 20:10