结束语:什么是好用例示例?为什么不使用函子?值得否定吗? [英] Closures: What is a good use case example? Why not a functor? And is it worth the negatives?

查看:39
本文介绍了结束语:什么是好用例示例?为什么不使用函子?值得否定吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近沉迷于Python.以前,我已经用C ++和Matlab编写了大多数数值和数据分析代码.我看到了很多有关Python和Ruby以及闭包的讨论.几乎所有示例都是这样的:

I recently dove into Python. Previous, I had programmed mostly numerical and data analysis code in C++ and Matlab. I saw a lot of discussions about Python and Ruby and closures. Almost all examples looked like this:

>>> def makeAdder(y):
...  def myAdder(x):
...   return x + y
...  return myAdder
... 
>>> f = makeAdder(10)
>>> f(5)
15

我了解这在某种意义上是有用的.但是,实际上,这种情况下的行为(原为只读"情况)可以很容易地由一个对象(仿函数)来模拟:

I understand that this can be useful in some sense. However, realistically, the behavior in situations like this ('read only' situations as it were) can easily be emulated by an object (a functor):

>>> class MyAdder(object):
...  def __init__(self,y):
...   self.y = y
...  def __call__(self,x):
...   return self.y + x
... 
>>> f = MyAdder(5)
>>> f(10)
15

该对象不会占用太多的代码空间,而且用途更加广泛.跟踪和调试后续代码也容易得多.

The object doesn't take up substantially more space to code, and it is far more versatile. It's also much easier to track and debug subsequent code.

在这种情况下,我们仅读取非局部变量.但是我们也可以这样写:在Ruby中,自然地,在Python中,可以使用nonlocal关键字.该对象当然也支持.但是有了对象,您就可以将数据捆绑在一起,因此您可以确切地知道发生了什么.闭包可能以完全不透明的方式携带变量,这可能导致难以调试的代码令人惊讶.这是一个非常奇怪的例子:

In this case, we only read from the nonlocal variable. But we can also write to it: in Ruby, naturally, in Python by using the nonlocal keyword. The object supports that as well of course. But with the object, you have the data bundled together so you know exactly what's going on. The closure can potentially be carrying around variables in a totally non-transparent way and this can lead to code that's amazingly hard to debug. Here's a really bizarre example:

irb(main):001:0> def new_counter
irb(main):002:1> x = 0
irb(main):003:1> lambda { x +=1 }
irb(main):004:1> end
=> nil
irb(main):005:0> counter_a = new_counter
=> #<Proc:0x00007f85c6421cd0@(irb):3>
irb(main):006:0> counter_a.call
=> 1
irb(main):007:0> counter_a.call
=> 2

至少对我而言,这种行为是不直观的.它还有可能导致内存泄漏.这为您提供了很多绳子供您垂吊.同样,这在Ruby中尤其如此,您不需要显式启用它(与Python不同),因为在Ruby中,主代码中都有块,可以访问所有内容.如果外部变量由于处于封闭状态而被更改,则将其传递给封闭对象时,可以无限期地更改变量,使其超出其所居住的范围.与始终安全地随身携带其数据的对象形成对比.

At least to me, this behavior is unintuitive. It also has the potential to cause memory leaks. This gives you a huge amount of rope to hang yourself with. Again, this is especially true in Ruby where you do not need to enable this explicitly (unlike Python), and because in Ruby one has blocks all over their main code, which have access to everything. If an outside variable gets changed as a result of being in a closure, if you pass that closure around you can have a variable changed indefinitely far and out of scope from the place where it lives. Contrast to an object that always safely carries its data with it.

为什么您会听到很多关于闭包效果的好消息,以及它们应该如何潜在地包含在Java中,如何在不完全使用Python的情况下吸收它们等等?为什么不使用函子?还是考虑到代码危险性之高,重构代码来避免这种情况?只是为了澄清一下,我不是那种面向对象的类型之一.我是否低估了它们的使用,夸大了它们的危险或两者兼而有之?

Why do you hear a lot of talk about how good closures are, and how they should be potentially included in Java, how it sucked when they weren't fully in Python, etc. ? Why not use a functor? Or refactor the code to avoid, given how incredibly dangerous they can be? Just to clarify, I'm not one of those foaming at the mouth OO types. Have I underestimated their use, overstated their danger, or both?

也许我应该区分三件事:仅读取一次的闭包(这是我的示例所显示的,几乎每个人都讨论过),通常读取的闭包和写入的闭包.如果您使用外部函数本地的变量在另一个函数内部定义一个函数,则几乎没有机会再次困扰您.我想不到的任何方式都无法访问该空间中的变量,因此您无法更改它.这是非常安全的,并且是生成函数的便捷方式(可能比函子还多).另一方面,如果在类方法内部或主线程内部创建一个闭包,则每次调用该闭包时,它将读取可从其他位置访问的变量.因此它可以改变.我认为这很危险,因为close over变量没有出现在函数头中.您可能在代码的第1页上说了一个长闭包,它关闭了主线程变量x,然后出于不相关的原因修改了x.然后重新使用闭包,并获得您不了解的异常行为,这可能很难调试.如果您确实写了封闭的变量,那么正如我在Ruby中的示例所示,您确实有可能造成混乱并导致意外行为.

maybe I should distinguish between three things: closures that only read once (which is what my example shows, and almost everyone discusses), closures that read in general, and closures that write. If you define a function inside another function using a variable local to the outer function, there's almost no chance this will come back to haunt you. The variable in that space is not accessible in any way I can think of, so you can't change it. This is pretty safe, and a convenient (possibly more than functors) way to generate functions. On the other hand, if you create a closure inside a class method or inside the main thread, it will read in variables each time that are called that can be accessed from other places. So it can change. I think this is dangerous because the closed over variable does not appear in the function header. You could have say a long closure on page 1 of your code that closes over a main thread variable x, and then modify x for unrelated reasons. Then re-use the closure and get bizarre behavior you don't understand, which may be hard to debug. If you actually write to enclosed variables, then as my example with Ruby shows you really have the potential to make a mess and cause unexpected behavior.

Edit2:我给出了第三个用法的闭包异常行为的示例,写入了非局部变量.这是第二种用法的怪异(不那么糟糕)行为的示例(在可以修改其封闭变量的范围内定义闭包):

I gave an example of bizarre behavior from closures for the third usage, writing to non local variables. Here's an example of bizarre (not as bad) behavior from the second usage (defining closures in scopes where their closed-over variables can be modified):

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[4](5)
14

推荐答案

可读性.您的Python示例显示了与函子相比,闭包版本更明显,更易于阅读.

Readability. Your Python example shows how much more obvious and easy to read the closure version is compared to the functor.

我们还整洁地避免创建一个仅充当函数的类,这有点多余.

We also neatly avoid making a class that does nothing but act like a function - this smells of redundancy.

如果没有别的,当我们正在做某事时,

If nothing else, when we are doing something, it makes sense to describe it as an action, not an object.

另一个要注意的是,装饰器是在Python中的 lot 中使用这些结构的一个例子,效果很好.大多数函数装饰器都会执行类似的操作,这是一个非常有用的功能.

As another note, an example of where these structures are used a lot in Python, to great effect, is decorators. Most function decorators do something like this, and they are a really useful feature.

关于状态,请记住,函数在Python中不是特殊的,它们仍然是对象:

As a note on state, remember that functions are not special in Python, they are still objects:

>>> def makeAdder(y):
...     def myAdder(x):
...         return x + myAdder.y
...     myAdder.y = y
...     return myAdder
... 
>>> f = makeAdder(10)
>>> f(5)
15
>>> f.y
10

这篇关于结束语:什么是好用例示例?为什么不使用函子?值得否定吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆