This article mainly introduces the issue of each circular variables in Python and Ruby, similar to the use of referenced variables in PHP foreach, for more information, see. although I encountered this problem in Python, it is easier to explain it in Ruby. In Ruby, there are many methods to traverse an array. The two most common methods are for and each:
The code is as follows:
Arr = ['A', 'B', 'C']
Arr. each {| e |
Puts e
}
For e in arr
Puts e
End
I usually like the latter because it seems to be nice to write, but in terms of efficiency, the former should be a little faster, because the latter actually calls a lambda function for each element in the traversal process, although it is not obvious in general, it is indeed overhead to set the context and call the function, especially in dynamic languages (without considering JIT inline optimization ). However, this issue is not about performance. However, it is related to "each creates a scope for each element, but for is not.
See the following code:
The code is as follows:
Arr = ['A', 'B', 'C']
H1 = Hash. new
H2 = Hash. new
Arr. each {| e |
H1 [e] = lambda {e + '! '}
}
For e in arr
H2 [e] = lambda {e + '! '}
End
H1 ['A']. call # =>?
H2 ['A']. call # =>?
What do two calls get separately? I already guessed it, right? They are 'a! 'And 'C! ', The latter is 'C! 'Because for does not create a new scope at every step of the loop, the closure of the three lambda references the same variable, this variable was assigned a value of 'C' for the last time, resulting in such a consequence.
The problem actually comes from a section of a small program I wrote in Python. the code is similar to this:
The code is as follows:
For prop in public_props:
Setattr (proxy, 'get _ % s' % prop, lambda: self. get_prop (prop ))
Proxy is a proxy object provided by me. it exposes some public attributes of self, because it is necessary to restrict access to non-public attributes, I don't want to store any reference to self in this proxy. otherwise, in Python that has no access permission restriction, I use a method similar to proxy. _ orig_self.some_private_prop is easy to access. So I finally chose the above method.
Unfortunately, as we mentioned earlier, for does not create a single scope every time, so closure references all of them to the same variable, as a result, all attribute values are obtained as the last attribute. I have seen such a strange bug. if it is in C/C ++, I must doubt the memory or pointer problem. However, after half a day, I finally realized it! However, in Python, there is no Ruby-so convenient each to use, and lambda is also very useful. Therefore, a local function is defined to solve the problem:
The code is as follows:
Def proxy_prop (name ):
Setattr (proxy, 'get _ % s' % prop, lambda: self. get_prop (name)
For prop in public_props:
Proxy_prop (prop)
Finally, I have to say one more word. for the Ruby example, if we reverse the execution order of each and for, we will get different results:
The code is as follows:
Arr = ['A', 'B', 'C']
H1 = Hash. new
H2 = Hash. new
For e in arr
H2 [e] = lambda {e + '! '}
End
Arr. each {| e |
H1 [e] = lambda {e + '! '}
}
H1 ['A']. call # => 'C! '
H2 ['A']. call # => 'C! '
Now both are 'C! ! This is because the block parameters in Ruby 1.8 can assign values to local variables or global variables, rather than the parameters of a lambda function in the general sense. Because the previous for statement creates an e in the current scope as a local variable, each directly assigns a value to this local variable. in this way, every time you reference it, it becomes the same thing, leading to a hidden Bug!
Fortunately, this "feature" of block has been removed in Ruby 1.9. The block parameter can only be a normal parameter, so this problem no longer exists. Hope 1.9 will be popularized as soon as possible!