简体   繁体   中英

Inconsistent scope in python

I have tried creating a function like this:

n = ["one", "two"]
result=""
def join_strings(words):
  for word in words:
    result+=word
  return result
print (join_strings(n))

This does not work and outputs:

UnboundLocalError: local variable 'result' referenced before assignment

The result variable has to be inside the function for it to work.

However, when I have this simple function:

x=3
def price():
  return (x+3)
print (price())

This works and prints the price, even though x is outside of the function. Why is this happening?

Actually there is no inconsistency as the examples you gave are different from each other. It would still fail in the second function if you have tried to assign x to itself, like:

>>> x = 3
>>> def price():
...     x +=3
...     return x
...
>>> price()
UnboundLocalError: local variable 'x' referenced before assignment

Instead of assigning back to x if you choose another name, it would run with no problem:

>>> def price():
...     y  = x + 3
...     return y
...
>>> price()
6

But, why it happens?

It's because Python's scoping rules. You can read the value of a variable outside of function but you can't change it**. When you do x += 3 , which is same as x = x + 3 for integers, that means " I have a variable x that I have write access to it in the current scope. " You don't have such variable, thus as the error says: you are referencing a "local variable" before assignment.

Is there a way to modify them in the function?

Yes. You can use global keyword, changes will be applied to your global variable:

>>> x = 3
>>> def price():
...     global x
...     x += 3
...     return x
...
>>> x
3
>>> price()
6
>>> x
6

** By changing , I mean assigning something else to it so it's id will change.

The difference is that in the second example you aren't trying to modify or reassign x . (You'll get the same error if you say something like x += 3 in the price function.) Once you use an assignment operator, you're binding a new value to that name, shadowing the outer scope.

If you want to be able to modify something from an outer scope, put it inside a mutable container (like a list); you can then modify the contents without reassigning that variable.

result = [""]
def join_strings(words):
    for word in words:
        result[0] += word
    return result[0]

If you just want to be able to reference the result value, without modifying it, that's fine too, but you have to assign it to a new variable then:

result = ""
def join_strings(words):
    ret = result
    for word in words:
        ret += word
    return ret

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM