Затваряния на Python: Как да го използвам и защо?

В този урок ще научите за затварянето на Python, как да дефинирате затваряне и причините, поради които трябва да го използвате.

Нелокална променлива в вложена функция

Преди да разгледаме какво е затваряне, първо трябва да разберем какво е вложена функция и нелокална променлива.

Функция, дефинирана вътре в друга функция, се нарича вложена функция. Вложените функции могат да имат достъп до променливи от обхващащия обхват.

В Python тези нелокални променливи са само за четене по подразбиране и трябва да ги декларираме изрично като нелокални (използвайки нелокална ключова дума), за да ги модифицираме.

Следва пример за вложена функция за достъп до нелокална променлива.

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello")

Изход

 Здравейте

Виждаме, че вложената printer()функция е успяла да осъществи достъп до нелокалната променлива на msg на заграждащата функция.

Определяне на функция за затваряне

В горния пример, какво би се случило, ако последният ред на функцията print_msg()върне printer()функцията, вместо да я извика? Това означава, че функцията е дефинирана както следва:

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let's try calling this function. # Output: Hello another = print_msg("Hello") another()

Изход

 Здравейте

Това е необичайно.

Най- print_msg()функцията се нарича с низ "Hello"и се върна функция е свързан с името на друг. При обаждане another()съобщението все още се помни, въпреки че вече бяхме приключили с изпълнението на print_msg()функцията.

Тази техника, чрез която някои данни ( "Helloв случая) се прикачват към кода, се нарича затваряне в Python .

Тази стойност в заграждащия обхват се запомня, дори когато променливата излезе извън обхвата или самата функция е премахната от текущото пространство от имена.

Опитайте да изпълните следното в обвивката на Python, за да видите изхода.

 >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined

Тук върнатата функция все още работи дори когато оригиналната функция е била изтрита.

Кога имаме затваряния?

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

Критериите, които трябва да бъдат изпълнени, за да се създаде затваряне в Python, са обобщени в следващите точки.

  • Трябва да имаме вложена функция (функция вътре във функция).
  • Вложената функция трябва да се отнася до стойност, дефинирана в заграждащата функция.
  • Ограждащата функция трябва да върне вложената функция.

Кога да се използват затваряния?

И така, за какво са полезни затварянията?

Затварянето може да избегне използването на глобални стойности и предоставя някаква форма на скриване на данни. Той може да осигури и обектно ориентирано решение на проблема.

Когато има малко методи (един метод в повечето случаи), които да бъдат внедрени в клас, затварянията могат да осигурят алтернативно и по-елегантно решение. Но когато броят на атрибутите и методите стане по-голям, по-добре е да внедрите клас.

Ето един прост пример, при който затварянето може да е по-предпочитано от дефинирането на клас и създаването на обекти. Но предпочитанието е ваше.

 def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))

Изход

 27 15 30

Python Decorators също широко използват затварянията.

В заключителна бележка е добре да се отбележи, че стойностите, които се затварят във функцията за затваряне, могат да бъдат открити.

Всички функционални обекти имат __closure__атрибут, който връща набор от клетъчни обекти, ако е функция за затваряне. Позовавайки се на горния пример, ние знаем times3и times5имаме функции за затваряне.

 >>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)

Клетъчният обект има атрибут cell_contents, който съхранява затворената стойност.

 >>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5

Интересни статии...