У овом упутству ћете научити о затварању Питхона, како дефинисати затварање и разлозима због којих бисте га требали користити.
Нелокална променљива у угнежђеној функцији
Пре него што уђемо у закључак, прво морамо да схватимо шта је угнежђена функција и нелокална променљива.
Функција дефинисана унутар друге функције назива се угнежђена функција. Угњежђене функције могу приступити променљивим опсега који обухвата.
У Питхону су ове не-локалне променљиве подразумевано само за читање и морамо их експлицитно прогласити не-локалним (користећи нелокалну кључну реч) да бисмо их модификовали.
Следи пример угнежђене функције која приступа не-локалној променљивој.
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()
функција била у могућности да приступи не-локалној променљивој мсг функције која обухвата.
Дефинисање функције затварања
У горњем примеру, шта би се догодило ако последњи ред функције 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
у овом случају) везују за код назива се затварање у Питхону .
Ова вредност у опсегу који се затвара памти се чак и када променљива излази из опсега или се сама функција уклони из тренутног простора имена.
Покушајте да покренете следеће у Питхон љусци да бисте видели излаз.
>>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined
Овде враћена функција и даље ради чак и када је оригинална функција избрисана.
Када имамо затварања?
Као што се види из горњег примера, имамо затварање у Питхону када се угнежђена функција позива на вредност у свом опсегу затварања.
Критеријуми који морају бити испуњени да би се створило затварање у Питхону сумирани су у следећим тачкама.
- Морамо имати угнежђену функцију (функцију унутар функције).
- Угњежђена функција мора се односити на вредност дефинисану у приложеној функцији.
- Функција затварања мора вратити угнијежђену функцију.
Када користити затвараче?
Па чему служе затварања?
Затварање може да избегне употребу глобалних вредности и пружа неки облик скривања података. Такође може пружити објектно оријентисано решење проблема.
Када постоји неколико метода (у већини случајева једна метода) које треба применити у класи, затварања могу пружити алтернативно и елегантније решење. Али када се број атрибута и метода повећа, боље је применити класу.
Ево једноставног примера где би затварање могло бити пожељније од дефинисања класе и израде објеката. Али преференција је твоја.
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
Питхон Децораторс такође широко користе затвараче.
На крају, добро је истаћи да се вредности које су затворене у функцији затварања могу сазнати.
Сви функционални објекти имају __closure__
атрибут који враћа скуп ћелијских објеката ако је функција затварања. Позивајући се на горњи пример, знамо times3
и times5
јесу функције затварања.
>>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)
Објекат ћелије има атрибут целл_цонтентс који чува затворену вредност.
>>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5