среда, 1 апреля 2020 г.

ЛМНты Python, 51 - 55

>>> Как замыкания

Интересно, что во вложенных функциях используемые нелокальные переменные точно так же доступны через locals(), как это происходит в замыканиях с бесплатными переменными:

>>> def f():
...     one = 1
...     print('f:', locals())
...     def g():
...         two = one + 1
...         print('g:', locals())
...         def h():
...             three = two + 1
...             print('h:', locals())
...         h()
...     g()
...
>>> f()
f: {'one': 1}
g: {'two': 2, 'one': 1}
h: {'three': 3, 'two': 2}

Вложенные функции, даже не потерявшие связь с контекстом, в котором они созданы, выглядят как замыкания.

>>> Работают по-разному

Если имена из глобального пространства имен доступны внутри классов, то имена из проcтранства имен класса недоступны во вложенном классе или в методе класса:

>>> g = 1
>>>
>>> class A(object):
...     a = 2
...     print(locals())
...     class B(object):
...         x = g
...         print(locals())
...         y = a
...
{'__module__': '__main__', '__qualname__': 'A', 'a': 2}
{'__module__': '__main__', '__qualname__': 'A.B', 'x': 1}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in A
  File "<stdin>", line 7, in B
NameError: name 'a' is not defined

>>> class A(object):
...     a = 2
...     print(locals())
...     def double(x):
...         print(locals())
...         return x * a
...
{'__module__': '__main__', '__qualname__': 'A', 'a': 2}
>>> A.double(3)
{'x': 3}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in double
NameError: name 'a' is not defined

Таким образом, области видимости внутри классов и функций работают по-разному. Последние обеспечивают видимость имен, созданных в объемлющих пространствах имен, изнутри вложенных функций.

>>> Перегруженная *

Функция с произвольным числом позиционных аргументов задается так:

>>> def fun(*args):
...     print(args)
...
>>> fun()
()
>>> fun(1)
(1,)
>>> fun(1, 'hello', 'world')
(1, 'hello', 'world')

Как видим, произвольное число аргументов, указанных при вызове функции, "упаковывается" в кортеж, доступный внутри функции.

Другая роль звездочки * состоит в "распаковке" последовательности, переданной в функцию как аргумент. При этом параметрам функции присваиваются элементы последовательности:

>>> def fun(a, b, c):
...     print(a, b, c)
...
>>> abc = (1, 'hello', 'world')
>>> fun(*abc)
1 hello world
>>> fun(*[1, 2, 3])
1 2 3
>>> fun(*range(3))
0 1 2

>>> Перегруженные **

Две звездочки ** при описании параметров функции указывают на необходимость "упаковки" произвольного количества именованных аргументов в словарь, доступный внутри функции:

>>> def fun(**kwargs):
...     print(kwargs)
...
>>> fun()
{}
>>> fun(one=1)
{'one': 1}
>>> fun(one=1, x='hello', y='world')
{'one': 1, 'x': 'hello', 'y': 'world'}

Другая роль двух звездочек ** состоит в "распаковке" словаря, переданного в функцию как аргумент. При этом параметрам функции присваиваются значения соответствующих элементов словаря:

>>> def fun(a, b, c):
...     print(a, b, c)
...
>>> abc = {'c': 'world', 'b': 'hi', 'a': '1'}
>>> fun(**abc)
1 hi world
>>> fun(**{'a': 1, 'b': 2, 'c': 3})
1 2 3

>>> fun(*args, **kwargs)

В эту функцию можно передать произвольное число и позиционных и именованных аргументов (а можно не передать ни одного):

>>> def fun(*args, **kwargs):
...     print(args)
...     print(kwargs)
...
>>> fun()
()
{}
>>> fun(1)
(1,)
{}
>>> fun(*range(5))
(0, 1, 2, 3, 4)
{}
>>> fun(1, two=2)
(1,)
{'two': 2}
>>> fun(one=1, two=2)
()
{'one': 1, 'two': 2}
>>> fun(**{str(i): i for i in range(5)})
()
{'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}

Если функции нужен обязательный параметр, он должен быть явно указан в начале списка параметров:

>>> def fun(a, *args, **kwargs):
...     print(a)
...     print(args)
...     print(kwargs)
...
>>> fun('привет')
привет
()
{}
>>> fun('привет', 'мир', ending='!')
привет
('мир',)
{'ending': '!'}
>>> fun()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: fun() missing 1 required positional argument: 'a'

Комментариев нет:

Отправить комментарий