سؤال

لقد قرأت الكثير عن الإغلاق و أعتقد أنني أفهم منهم ، ولكن دون أن يعكر الصورة على نفسي وعلى الآخرين ، وأنا آمل شخص يمكن أن تفسر الإغلاق بإيجاز ووضوح ممكن.أنا أبحث عن تفسير بسيط قد تساعدني على فهم أين ولماذا كنت ترغب في استخدامها.

هل كانت مفيدة؟

المحلول

الإغلاق على الإغلاق

كائنات البيانات مع أساليب تعلق والإغلاق هي المهام البيانات المرفقة.

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

نصائح أخرى

انها بسيطة:وظيفة مراجع المتغيرات من التي تحتوي على نطاق يحتمل بعد تدفق من السيطرة على ترك هذا النطاق.هذا الجزء الأخير مفيد جدا:

>>> 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

علما أن 12 و 4 قد "اختفى" داخل f g, على التوالي, هذه الميزة هي ما جعل f و g السليم الإغلاق.

أحب هذا الخام ، مقتضبة تعريف:

وظيفة التي يمكن أن تشير إلى البيئات التي لم تعد نشطة.

كنت أود أن أضيف

إغلاق يسمح لك لربط المتغيرات في دالة دون المرور عليها كما المعلمات.

الديكور التي تقبل المعلمات شائعة الاستخدام الإغلاق.إغلاق شائعة آلية التنفيذ لهذا النوع من "وظيفة المصنع".أنا في كثير من الأحيان اختيار استخدام الإغلاق في نمط استراتيجية عندما استراتيجية تعديل البيانات في وقت التشغيل.

في اللغة التي تسمح مجهول تعريف كتلة -- على سبيل المثال, روبي, C# -- الإغلاق يمكن استخدامها لتنفيذ (كمية) رواية جديدة هياكل المراقبة.عدم وجود مجهول كتل بين قيود الإغلاق في بايثون.

أن نكون صادقين, أنا أفهم الإغلاق تماما إلا أنني لم واضحة حول ما هو بالضبط الشيء الذي هو "إغلاق" و ما هو "إغلاق" حول هذا الموضوع.أنصحك التخلي عن أي منطق وراء اختيار المصطلح.

على أى حال هذا هو الشرح:

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

bar = foo()
bar()   # print 5

مفتاح الفكرة هنا هي أن وظيفة الكائن عاد من فو يحتفظ هوك المحلية فار 'x' على الرغم من 'x' قد خرجت من نطاق وينبغي البائد.هذا هوك هو فار نفسه ، ليس فقط القيمة التي فار كان في ذلك الوقت, لذلك عندما ويسمى شريط, يطبع 5 وليس 3.

يكون من الواضح أيضا أن بيثون 2.x محدودة الإغلاق:ليس هناك طريقة يمكنني تعديل 'x' داخل 'شريط' لأن الكتابة 'x = bla' يعلن المحلية 'x' في شريط, تعيين إلى " x " من فو.هذا هو أحد الآثار الجانبية من بيثون مهمة=الإعلان.للحصول على هذا الثعبان 3.0 يدخل غير محلي الكلمة:

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

لم أسمع من المعاملات المستخدمة في السياق نفسه بشرح ما الإغلاق و هناك في الحقيقة ليست أي معاملة دلالات هنا.

انه دعا الإغلاق لأنه "يغلق على" الخارج متغير (ثابت) - أي أنه ليس مجرد وظيفة بل بضميمة البيئة حيث وظيفة تم إنشاؤه.

في المثال التالي ، واصفا إغلاق ز بعد تغيير x تغيير قيمة x في ز ، إذ ز يغلق على x:

x = 0

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


closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4

هنا هو استخدام نموذجي حالة الإغلاق - رد على عناصر واجهة المستخدم الرسومية (هذا من شأنه أن يكون بديلا subclassing زر الطبقة).على سبيل المثال ، يمكنك إنشاء وظيفة التي من شأنها أن يسمى ردا على زر الصحافة ، و "إغلاق" على المتغيرات ذات الصلة في الأصل نطاق اللازمة لمعالجة انقر فوق.وبهذه الطريقة يمكنك توصيل أسلاك معقدة جدا واجهات من نفس وظيفة التهيئة وبناء جميع التبعيات إلى الإغلاق.

في بيثون ، إغلاق مثيل الوظيفة التي لديها المتغيرات لا بد لها immutably.

في الواقع ، نموذج البيانات يفسر هذا في وصف الوظائف __closure__ السمة:

لا شيء أو المجموعة من الخلايا التي تحتوي على الارتباطات عن وظيفة مجانا المتغيرات.للقراءة فقط

تثبت هذا:

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

closure_instance = enclosure('foo')

ومن الواضح أننا نعرف أن لدينا الآن وظيفة موجه من اسم المتغير closure_instance.ظاهريا ، إذا كنا نسميها مع كائن ، bar, ، يجب طباعة السلسلة ، 'foo' ومهما تمثيل سلسلة من bar هو.

في الواقع ، فإن سلسلة 'فو' هو لا بد على سبيل المثال وظيفة ، و يمكننا قراءة مباشرة هنا قبل الوصول إلى cell_contents السمة الأولى (فقط) خلية في tuple من __closure__ السمة:

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

بوصفها جانبا ، الخليوي الكائنات الموضحة في ج وثائق API:

"الخليوي" الكائنات تستخدم لتنفيذ المتغيرات المشار إليها من قبل عدة نطاقات

ويمكننا أن ندلل على إغلاق الاستخدام ، مشيرا إلى أن 'foo' عالق في وظيفة لا يتغير:

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

ولا شيء يمكن تغييره:

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

جزئية وظائف

المثال المذكور يستخدم الإغلاق الجزئي وظيفة ، ولكن إذا كان هذا هو هدفنا الوحيد ، نفس الهدف يمكن أن يتحقق مع 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

هناك أكثر تعقيدا الإغلاق كما أنه لا يصلح الجزئي وظيفة سبيل المثال ، سوف تثبت لهم كذلك كما يسمح الوقت.

هنا هو مثال على Python3 الإغلاق

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
# 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

معايير التقى قبل الإغلاق هي:

  1. يجب أن يكون لدينا وظيفة متداخلة.
  2. وظيفة متداخلة يجب الرجوع إلى القيمة المحددة في أرفق وظيفة.
  3. أرفق وظيفة لا بد من العودة الدالة المتداخلة.

# 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

بالنسبة لي "الإغلاق" هي الوظائف التي هي قادرة على تذكر البيئة التي تم إنشاؤها.هذه الوظيفة تسمح لك لاستخدام المتغيرات أو أساليب في إغلاق اللي تبونه, بطريقة أخرى,أنت لن تكون قادرة على استخدام إما لأنها لم تعد موجودة أو أنها بعيدة المنال بسبب نطاق.دعونا ننظر في هذه التعليمة البرمجية في روبي:

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"  

يعمل حتى عندما يكون كل من "ضرب" طريقة "x" متغير,لم تعد موجودة.كل ذلك بسبب إغلاق القدرة على تذكر.

علينا جميعا استخدامه الديكور في بيثون.فهي لطيفة الأمثلة لإظهار ما هي إغلاق وظائف في بيثون.

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)

هنا القيمة النهائية هو 12

هنا وظيفة المجمع هو قادرة على الوصول إلى وظائفها كائن لأن المجمع هو "المعجمية الإغلاق" ، فإنه يمكن الوصول إليه الأم الصفات.هذا هو السبب في أنها قادرة على الوصول إلى وظائفها الكائن.

أود أن حصة بلدي على سبيل المثال و تفسيرا حول الإغلاق.أنا جعلت الثعبان سبيل المثال ، واثنين من الأرقام تثبت كومة الدول.

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!')

الناتج من هذا القانون على النحو التالي:

*****      hello      #####

      good bye!    ♥♥♥

وهنا اثنين من الأرقام تظهر أكوام إغلاق تعلق على وظيفة الكائن.

عندما وظيفة هو عاد من صانع

عندما يتم استدعاء الدالة في وقت لاحق

عندما يتم استدعاء الدالة من خلال معلمة أو غير محلي متغير ، رمز الاحتياجات المحلية متغير الارتباطات مثل margin_top ، الحشو فضلا عن a, b, n.من أجل ضمان وظيفة رمز للعمل ، المكدس الإطار صانع وظيفة التي كان قد ذهب بعيدا منذ فترة طويلة ينبغي أن تكون متاحة ، وهو احتياطيا في إغلاق نجد جنبا إلى جنب مع رسالة مهمة الكائن.

أفضل شرح رأيت من أي وقت مضى من إغلاق لشرح آلية.كان شيئا مثل هذا:

تخيل برنامج المكدس كما تتحول شجرة مكان كل عقدة لديه طفل واحد فقط و ورقة واحدة عقدة سياق حاليا تنفيذ الإجراء.

الآن الاسترخاء القيد أن كل عقدة يمكن أن يكون لها طفل واحد فقط.

إذا كنت تفعل هذا, هل يمكن أن يكون بناء ('المحصول') التي يمكن العودة من الإجراء دون تجاهل السياق المحلي (أيلا البوب خارج المكدس عند العودة).في المرة القادمة الإجراء هو الاحتجاج الاحتجاج تلتقط القديمة المكدس (شجرة) إطار تواصل تنفيذ من حيث توقفت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top