2

I wish to understand things better, why is this working without declaring list c as a global within the function fct? The same is not true for variable a ?

def fct():
    global a      # have to declare this for "a" to work, but not for c[]
    print(a,c)    # by not declaring "a" as global, caused this to flag
                  # "accessing a without assignment", which I understand why,
                  # but why c[] needn't declaration
    c[1]=5
    a=234

c=[0,0]
a=11
fct()
ffrree
  • 93
  • 2
  • 10
  • 5
    You are not assigning to `c`. You are *mutating* `c` by telling *it* to set values for a given index. In other words, `c[...] = ...` differs materially from `c = ...`. – Martijn Pieters Jun 12 '17 at 11:57
  • https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules – Arpit Solanki Jun 12 '17 at 11:57
  • The short answer is because lists are mutable and integers are immutable. – Anup Jun 12 '17 at 12:31
  • @Anup That's missing the point. As Martijn said, it's because you are _only_ mutating the list. But even if it is mutable, if you did `c = ...`, you'd need `global c`. – tobias_k Jun 12 '17 at 13:16

2 Answers2

1

Okay this question might need a little bit of explaining.

PEP 3104 states that:

In most languages that support nested scopes, code can refer to or rebind (assign to) any name in the nearest enclosing scope. Currently, Python code can refer to a name in any enclosing scope, but it can only rebind names in two scopes: the local scope (by simple assignment) or the module-global scope (using a global declaration).

Two things you must understand here is that:

  • Binding: create a name, bind a value to it. e.g:>>> a=10 creates a variable a and assigns 10 to it.

  • Rebinding: change the value bound to the name. e.g: >>> a=10;a=5 binds value 10 then rebinds 5 to 'a' itself.

So as it is clearly stated it can only rebind name in the local scope.

Example:

def func():
    a=5
    print(a)
a=10
print("a in the program")
print(a)
print("a in func()")
func()

output:

a in the program
10
a in func()
5

Now remove a=5 from func() and you get:

a in the program
10
a in func()
10

What happens is a is found out to be 10 and it is printed.

Now do this:

def func():
    print(a)
    a=5
a=10
print("a in the program")
print(a)
print("a in func()")
func()

you get this:

UnboundLocalError: local variable 'a' referenced before assignment

What happens if you give a=5 in a function?

No rebinding occurs now instead a new local variable a=5 is created.

So,

  • if you don't write a=5 after/before print statement it just prints the global variable a by default.

  • However if you write a=5 before print(a) it creates a local variable a and then binds (note: not rebind but binds) the value 5 to it.

  • But if you write a=5 after print(a) it gets confused as to why you are referencing a variable(local variable a) which hasn't yet been created.

However, because any assignment to a name implicitly declares that name to be local, it is impossible to rebind a name in an outer scope (except when a global declaration forces the name to be global).

So if you use global a the print(a) happily prints the global a as 10 and then creates a new local variable a=5 by binding 5 to a.

global a
print(a)
a=5
print(a)

output:

def func():
    global a
    print(a)
    a=5
    print(a)
a=10
print("a in the program")
print(a)
print("a in func()")
func()

But this is not the case with your other objects like list,dict and such. In this case, you're just modifying an existing, global object, which is found by regular name lookup (changing a list entry is like calling a member function on the list, it's not a name rebinding).

So it works fine without any errors. Hope you understood something.

void
  • 2,571
  • 2
  • 20
  • 35
0

If you use word global it means that you can write on a global variable, but I you just want to read it you don't need to use global.

You do not need to declare c and a in the function body because you have declared them just before execution of fct()

trojek
  • 3,078
  • 2
  • 29
  • 52
  • Thank you for pointing the finer points of binding to "c" the list as against changing one of its members. – ffrree Jun 13 '17 at 01:42