RedKnite
RedKnite

Reputation: 1545

make local copy of global variable

I'm probably missing something really obvious, but how do I create a local copy of a global vaiable with the same name? I have something like:

d = {"one": 1, "two": 2, "three": 3}

def foo():
    d = d.copy()
    d["four"] = 4

I want to create a copy of d in the inner scope that I can modify as I like without affecting the global version. This will complain that d is reference before assignment, which makes perfect sense because it is being interpreted as a local variable. If I declare it global though, this will modify it.

This would be trivial if I didn't mind if it had a different name eg: d_local = d.copy(), but that would be a big hassle in this situation and not just a find and replace one either.

If the only solution is to use a new name and deal with the consequences let me know.

Upvotes: 3

Views: 4610

Answers (2)

John Krakov
John Krakov

Reputation: 375

Generally using local and global variables with the same name is a really bad practice as it causes confusion. You could use d as an argument, or simply use a different name. However if you really wanted to leave your code structure untouched (which I do not recommend), you could define a function in the global scope that returns a copy of d. As such :

d = {"one": 1, "two": 2, "three": 3}

def copyD():
  return d.copy()

def foo():
  d = copyD()
  d["four"] = 4

As pointed out by @rici the function could be defined inside the local scope by using the global keyword :

d = {"one": 1, "two": 2, "three": 3}

def foo():
  def copyD():
    global d
    return d.copy()
  d = copyD()
  d["four"] = 4

This code is better, because the copyD function really won't be used anywhere else.

Upvotes: 3

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 96028

You'd have to use another identifier if you are doing it this way. A variable can be either local or global but not both ... That's the whole point of scope. When you assign to something in a function, it will default to local. But if you make it global, i.e. by using the global statement, it will re-assign your global variable, which presumably you don't want (although, it would mutate a new object not the one being referenced by your global variable prior to calling the function).

The most reasonable thing here would be to take d as an argument. Then simply do d = d.copy()

so:

d = {"one": 1, "two": 2, "three": 3}

def foo(d):
    d = d.copy()
    d["four"] = 4

foo(d)

This would be trivial if I didn't mind if it had a different name eg: d_local = d.copy(), but that would be a big hassle in this situation and not just a find and replace one either.

That sounds like a fundamental problem with your code. Identifiers should not really matter other than to help you understand your own code. If your logic depends on identifiers, that is almost always bad. Read Keep Data Out of Your Variable Names which is yet another excellent tutorial by Ned Batchelder.

Upvotes: 3

Related Questions