>>> Как замыкания
Интересно, что во вложенных функциях используемые нелокальные переменные точно так же доступны через 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'
Комментариев нет:
Отправить комментарий