Пространства имен, области видимости

global

In [1]:
a = 1

def f():
    a = 2
    print(a)

f()
print(a)
2
1
In [2]:
a = 1

def f():
    print(a)

f()
print(a)
1
1
In [3]:
a = 1

def f():
    global a
    a = 2
    print(a)

f()
print(a)
2
2

nonlocal

In [4]:
a = 1

def f():
    a = 2
    def g():
        a = 3
        print(a)

    g()
    print(a)

f()
print(a)
3
2
1
In [5]:
a = 1

def f():
    a = 2
    def g():
        nonlocal a
        a = 3
        print(a)

    g()
    print(a)

f()
print(a)
3
3
1
In [6]:
a = 1

def f():
    def g():
        nonlocal a
        a = 3
        print(a)

    g()
    print(a)

f()
print(a)
  File "<ipython-input-6-d4744cb8d4eb>", line 5
    nonlocal a
SyntaxError: no binding for nonlocal 'a' found
In [7]:
a = 1

def h():
    a = 2
    def f():
        def g():
            nonlocal a
            a = 3
            print(a)

        g()
        print(a)

    f()
    print(a)

h()
print(a)
3
3
3
1

Все вместе

In [8]:
def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

Новое локальное пространство имен создается только при вызове функции

In [9]:
if True:
    a = 1
print(a)
1
In [10]:
for i in range(3):
    a = 1
print(a)
print(i)
1
2

Время жизни объекта

Счетчик ссылок

In [11]:
class C:
    def __init__(self, i):
        self.i = i
        print("C({}) initialized".format(self.i))

    def __del__(self):
        print("C({}) is about to be deleted".format(self.i))

def f():
    for i in range(2):
        print("start loop")
        o = C(i)
        print("end loop")

print("before f()")
f()
print("after f()")
before f()
start loop
C(0) initialized
end loop
start loop
C(1) initialized
C(0) is about to be deleted
end loop
C(1) is about to be deleted
after f()
In [12]:
import sys

x = C(1)
sys.getrefcount(x)
C(1) initialized
Out[12]:
2
In [13]:
y = x
sys.getrefcount(x)
Out[13]:
3
In [14]:
del y
sys.getrefcount(x)
Out[14]:
2
In [15]:
import weakref

y = weakref.proxy(x)
sys.getrefcount(x)
Out[15]:
2
In [16]:
y.i
Out[16]:
1
In [17]:
del x
y.i
C(1) is about to be deleted
---------------------------------------------------------------------------
ReferenceError                            Traceback (most recent call last)
<ipython-input-17-ea3a71ce2465> in <module>()
      1 del x
----> 2 y.i

ReferenceError: weakly-referenced object no longer exists
In [18]:
x = C(2)
sys.getrefcount(x)
C(2) initialized
Out[18]:
2
In [19]:
x.x = x
sys.getrefcount(x)
Out[19]:
3
In [20]:
y = weakref.proxy(x)
del x
In [21]:
y.x = None
C(2) is about to be deleted

Циклические ссылки

In [22]:
class Element:
    def __init__(self, data, prev=None, next=None):
        self.data = data
        self.prev = prev
        self.next = next
        print("init")

    def __del__(self):
        print("del", self.data)

head = Element(1)
tail = Element(2)
head.next = tail
tail.prev = head
del head
del tail
print("done")
init
init
done
In [23]:
head = Element(1)
tail = Element(2)
head.next = tail
tail.prev = head
head.next = None
del head
del tail
print("done")
init
init
del 2
del 1
done