Kan du forklare nedleggelser (som de forholder seg til Python)?

stemmer
69

Jeg har lest mye om nedleggelser og jeg tror jeg forstår dem, men uten clouding bildet for meg selv og andre, håper jeg noen kan forklare nedleggelser som konsist og tydelig som mulig. Jeg leter etter en enkel forklaring som kan hjelpe meg å forstå hvor og hvorfor jeg ønsker å bruke dem.

Publisert på 17/08/2008 klokken 19:14
kilden bruker
På andre språk...                            


13 svar

stemmer
76

Nedleggelse på nedleggelser

Objekter er data med metoder festet, lukkeanordninger er funksjoner med data knyttet.

def make_counter():
    i = 0
    def counter(): # counter() is a closure
        nonlocal i
        i += 1
        return i
    return counter

c1 = make_counter()
c2 = make_counter()

print (c1(), c1(), c2(), c2())
# -> 1 2 1 2
Svarte 26/09/2008 kl. 19:28
kilden bruker

stemmer
42

Det er enkelt: En funksjon som refererer variabler fra en inneholdende omfang, eventuelt etter strømning av kontroll har forlatt det omfang. Det siste biten er veldig nyttig:

>>> def makeConstantAdder(x):
...     constant = x
...     def adder(y):
...         return y + constant
...     return adder
... 
>>> f = makeConstantAdder(12)
>>> f(3)
15
>>> g = makeConstantAdder(4)
>>> g(3)
7

Legg merke til at 12 og 4 har "forsvunnet" inni f og g, henholdsvis denne funksjonen er det som gjør F og G riktig nedleggelser.

Svarte 17/08/2008 kl. 19:32
kilden bruker

stemmer
14

Jeg liker denne tøffe, konsis definisjon :

En funksjon som kan referere til miljøer som ikke lenger er aktive.

Jeg vil legge til

Et lukke gjør det mulig å binde variabler i en funksjon uten å passere dem som parametere .

Dekoratører som godtar parametere er en vanlig bruk for nedleggelser. Nedleggelser er en felles gjennomføring mekanisme for den slags "-funksjonen fabrikk". Jeg velger ofte å bruke nedleggelser i Strategy Pattern når strategien er endret av data ved kjøring.

I et språk som tillater anonym blokk definisjon - f.eks, Ruby, C # - kan nedleggelser brukes til å implementere (hva beløp) nye nye kontrollstrukturer. Mangelen på anonyme blokker er blant begrensningene av lukninger på Python .

Svarte 17/08/2008 kl. 20:25
kilden bruker

stemmer
13

For å være ærlig, jeg forstår nedleggelser utmerket godt uten at jeg aldri har vært klar på hva er det ting som er "nedleggelse", og hva er så "nedleggelse" om det. Jeg anbefaler at du gir opp etter noen logikk bak valget av begrepet.

Uansett, her er min forklaring:

def foo():
   x = 3
   def bar():
      print x
   x = 5
   return bar

bar = foo()
bar()   # print 5

En viktig Ideen her er at funksjonen objekt returnerte fra foo beholder en krok til den lokale Var 'x' selv om 'x' har gått ut av omfang og bør være dødt. Denne kroken er til VAR seg selv, ikke bare verdien som Var hadde på den tiden, så da bar kalles, skriver den 5, ikke tre.

Også være klart at Python 2.x har begrenset nedleggelse: det er ingen måte jeg kan endre 'x' inne 'bar' fordi skriving 'x = bla' vil erklære en lokal 'x' i baren, ikke tildele 'x' av foo . Dette er en bivirkning av Pythons oppgave = erklæring. For å komme rundt dette, Python 3.0 introduserer nonlocal søkeord:

def foo():
   x = 3
   def bar():
      print x
   def ack():
      nonlocal x
      x = 7
   x = 5
   return (bar, ack)

bar, ack = foo()
ack()   # modify x of the call to foo
bar()   # print 7
Svarte 23/08/2008 kl. 07:43
kilden bruker

stemmer
6

Jeg har aldri hørt om transaksjoner blir brukt i samme sammenheng som forklarer hva en nedleggelse er og at det egentlig ikke er noen transaksjons semantikk her.

Det kalles en nedleggelse fordi det "lukker over" utsiden variable (konstant) - det vil si, det er ikke bare en funksjon, men en innhegning av miljøet der funksjonen ble opprettet.

I det følgende eksempel vil kalle lukke g etter endring x også endre verdien av x i g, ettersom g lukkes over x:

x = 0

def f():
    def g(): 
        return x * 2
    return g


closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4
Svarte 17/08/2008 kl. 20:20
kilden bruker

stemmer
3

Her er en typisk brukstilfelle for nedleggelser - callbacks for grafiske elementer (dette vil være et alternativ til subclassing knappen klasse). For eksempel kan du lage en funksjon som vil bli kalt inn som svar på et tastetrykk, og "lukke" over de aktuelle variablene i den overordnede rammen som er nødvendige for å behandle klikk. På denne måten kan du koble opp ganske kompliserte grensesnitt fra samme initialisering funksjon, bygge alle avhengigheter i nedleggelsen.

Svarte 23/01/2009 kl. 16:13
kilden bruker

stemmer
1

Her er et eksempel på Python3 nedleggelser

def closure(x):
    def counter():
        nonlocal x
        x += 1
        return x
    return counter;

counter1 = closure(100);
counter2 = closure(200);

print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 2 " + str(counter2()))
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 2 " + str(counter2()))

# result

i from closure 1 101
i from closure 1 102
i from closure 2 201
i from closure 1 103
i from closure 1 104
i from closure 1 105
i from closure 2 202
Svarte 22/09/2015 kl. 20:16
kilden bruker

stemmer
1

I Python, er en lukke en forekomst av en funksjon som har variabler bundet til det immutably.

Faktisk forklarer datamodell dette i sin beskrivelse av funksjoner __closure__attributt:

Ingen eller en tuppel av celler som inneholder bindinger for funksjons frie variabler. Skrivebeskyttet

For å demonstrere dette:

def enclosure(foo):
    def closure(bar):
        print(foo, bar)
    return closure

closure_instance = enclosure('foo')

Klart, vi vet at vi nå har en funksjon pekt på fra variabelnavn closure_instance. Tilsynelatende, hvis vi kaller det med et objekt, bardet skal skrives ut strengen, 'foo'og uansett strengrepresentasjon av barer.

Faktisk strengen foo er bundet til forekomsten av funksjon, og vi kan direkte avleses som det her, ved å åpne den cell_contentsegenskap av det første (og eneste) celle i den tuppel av __closure__attributt:

>>> closure_instance.__closure__[0].cell_contents
'foo'

Som en side, blir celle gjenstander er beskrevet i dokumentasjonen C API:

"Cell" objekter blir brukt til å implementere variabler refereres av flere omfang

Og vi kan vise vår nedleggelse sin bruk, og bemerker at 'foo'sitter fast i funksjon og endres ikke:

>>> closure_instance('bar')
foo bar
>>> closure_instance('baz')
foo baz
>>> closure_instance('quux')
foo quux

Og ingenting kan endre det:

>>> closure_instance.__closure__ = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute

delvis Funksjoner

Eksempelet bruker nedleggelsen som en delvis funksjon, men hvis dette er vårt eneste mål, kan det samme målet oppnås med functools.partial

>>> from __future__ import print_function # use this if you're in Python 2.
>>> partial_function = functools.partial(print, 'foo')
>>> partial_function('bar')
foo bar
>>> partial_function('baz')
foo baz
>>> partial_function('quux')
foo quux

Det er mer komplisert nedleggelser samt som ikke ville passe delvis funksjon eksempel, og jeg vil vise dem videre som tiden tillater.

Svarte 18/07/2014 kl. 03:33
kilden bruker

stemmer
0

Jeg vil gjerne dele mitt eksempel og en forklaring om nedleggelser. Jeg har gjort en python eksempel, og to tall for å demonstrere stakk tilstander.

def maker(a, b, n):
    margin_top = 2
    padding = 4
    def message(msg):
        print('\n’ * margin_top, a * n, 
            ' ‘ * padding, msg, ' ‘ * padding, b * n)
    return message

f = maker('*', '#', 5)
g = maker('', '♥’, 3)
f('hello')
g(‘good bye!')

Utgangen av denne koden vil være som følger:

*****      hello      #####

      good bye!    ♥♥♥

Her er to tall for å vise stabler og lukkeanordningen er festet til den funksjon objektet.

når funksjonen er returnert fra maker

når funksjonen kalles senere

Når funksjonen kalles via en parameter eller en nonlocal variabel, må koden lokale variable bindinger som margin_top, padding samt a, b, n. For å sikre funksjonen koden til å fungere, stabelen rammen av maker funksjon som var gått bort for lenge siden skal være tilgjengelig, som er støttet opp om nedleggelse kan vi finne sammen med 'meldingens funksjon objekt.

Svarte 12/05/2018 kl. 04:17
kilden bruker

stemmer
0

vi alle har brukt dekoratører i python. De er fine eksempler for å vise hva er nedleggelse funksjoner i python.

class Test():
    def decorator(func):
        def wrapper(*args):
            b = args[1] + 5
            return func(b)
        return wrapper

@decorator
def foo(val):
    print val + 2

obj = Test()
obj.foo(5)

her endelige verdien er 12

Her er wrapper funksjon i stand til å få tilgang til func objekt fordi wrapper er "leksikalske nedleggelse", det kan få tilgang til det overordnede attributter. Det er derfor, det er i stand til å få tilgang func objekt.

Svarte 17/04/2018 kl. 19:00
kilden bruker

stemmer
0
# A Closure is a function object that remembers values in enclosing scopes even if they are not present in memory.

# Defining a closure

# This is an outer function.
def outer_function(message):
    # This is an inner nested function.
    def inner_function():
        print(message)
    return inner_function

# Now lets call the outer function and return value bound to name 'temp'
temp = outer_function("Hello")
# On calling temp, 'message' will be still be remembered although we had finished executing outer_function()
temp()
# Technique by which some data('message') that remembers values in enclosing scopes 
# even if they are not present in memory is called closures

# Output: Hello

Kriterier til oppfylles av Nedleggelser er:

  1. Vi må ha nestet funksjon.
  2. Nestet funksjon skal referere til den verdi som er definert i den omsluttende funksjon.
  3. Omslutting funksjon må returnere nestet funksjon.

# Example 2
def make_multiplier_of(n): # Outer function
    def multiplier(x): # Inner nested function
        return x * n
    return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
print(times5(3)) # 15
print(times3(2)) #  6
Svarte 26/12/2017 kl. 16:41
kilden bruker

stemmer
0

For meg, "nedleggelser" er funksjoner som er i stand til å huske det miljøet de ble opprettet. Denne funksjonaliteten, kan du bruke variabler eller metoder innen nedleggelsen wich, på annen måte, vil du ikke være i stand til å bruke enten fordi de ikke eksisterer lenger, eller de er ute av rekkevidde på grunn av omfanget. La oss se på denne koden i ruby:

def makefunction (x)
  def multiply (a,b)
    puts a*b
  end
  return lambda {|n| multiply(n,x)} # => returning a closure
end

func = makefunction(2) # => we capture the closure
func.call(6)    # => Result equal "12"  

Det fungerer selv om begge deler, "formere" metoden og "x" variable, ikke lenger eksisterer. Alle fordi nedleggelsen evne til å huske.

Svarte 20/09/2013 kl. 13:39
kilden bruker

stemmer
-2

Den beste forklaringen jeg har sett av en nedleggelse var å forklare mekanismen. Det gikk noe sånt som dette:

Forestill programmet stabelen som en degenerert tre hvor hver node har bare ett barn og én bladnoden er konteksten av tiden utfører prosedyren.

Nå slappe begrensningen at hver node kan bare ha ett barn.

Hvis du gjør dette, kan du ha en konstruksjon ( 'utbyttet') som kan returnere fra en prosedyre uten å forkaste den lokale konteksten (dvs. ikke pop den av stabelen når du kommer tilbake). Neste gang den prosedyre startes, plukker opp påkalling den gamle stabel (tre) ramme, og fortsetter utføring hvor den slapp.

Svarte 18/09/2008 kl. 17:10
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more