The unknown features of Python's `operator` module
martinheinz.dev
martinheinz.dev
$ python -m timeit "(lambda x,y: x + y)(12, 15)"
10000000 loops, best of 3: 0.124 usec per loop
$ python -m timeit -s "from operator import add" "add(12, 15)"
10000000 loops, best of 3: 0.0565 usec per loop
Instead, it should create a function in the setup and use that for the loop: $ python -m timeit -s "func = lambda x,y: x + y" "func(12, 15)"
10000000 loops, best of 3: 0.0779 usec per loopdef add_fun(x,y): return x+y
But I wouldn't mind irritating the linter with an assigned lambda. I fail to see what's the problem with it
Of course the point regarding the simplicity of importing a function instead of defining it still stands.
I personally wouldn't mind defining those functions as they are very immediate. So from the article I would take only the part about the more exotic "operator".
In short: being picked up by a linter does not mean that something is un-pythonic.
For someone familiar with the operator module, there is a final small argument for using it instead of defining your own, if the result will be the same: that's a definition that doesn't have to be understood by the reader.
Also verify the type info on the object here:
In [1]: import operator
In [5]: operator.add??
Signature: operator.add(a, b, /)
Docstring: Same as a + b.
Type: builtin_function_or_methodSo I agree that it is why it's slower, but I also agree that it's a mistake. This is the "hard part" about synthetic benchmarks. This one is measuring something people rarely do: creating an anonymous function and calling it in a tight loop.
It's extremely unlikely you're ever going to run into a situation where creating this lambda is in a hot path, and if you do the thing you did wrong is very unlikely to be whether you used a standard library function or one you defined yourself. It's that you have a loop where you did almost nothing but create a lambda every iteration instead of, say, passing it to a map/fold function or whatever.
Maybe you still want to know how long it takes to create a lambda or import from operator, but if such a function is being called more than a few times (and if not, why are we concerned about performance?), execution time will dominate other factors.
(lambda x, y: x ^ y)(7, 10)
from operator import xor
xor(7, 10)
> Clearly the second option is more readable.Clearly, the readable option here is ”7 ^ 10”. The examples are a bit contrived, so readability can’t really be gauged from them.
If you want to do a parity check on a string:
parity = reduce(xor, map(ord, str))%2
Except Python3 took reduce away in favor of more boilerplate. And yes, there are multiple alternative implementations of the above."% 2" will not calculate the parity of the reduced value; it just extracts the least significant bit.
I'm guessing the last one since that's what fits your LSB comment(when using 'evenness' not 'oddness'). But in that case I'm not sure your example is doing, my python might be too rusty but is it something like: get the unicode representation(int) of each character in a string, xor the results and get the LSB?
But, the more useful concept is parity for error detection, which my example clearly fails at.
https://en.wikipedia.org/wiki/Parity_bit
https://en.wikipedia.org/wiki/Parity_(mathematics)
"parity check on a string" tends toward the former interpretation of "parity". You don't do parity checks by looking at only the least significant bit of every code word.
If the examples don’t show cases where the feature even arguably is the best option, they’re bad examples of the feature. I don’t think that’s nitpicking.
#this used to be y = 2 * x + 1 until I read a sweet blog
y = operator.add(1, operator.mul(2, x))
I really don't see any danger of that, myself.You can import functools.reduce to get it back but maybe thats what you meant with more boilerplate
For instance, I'm writing a library to simulate the behavior of vectors in R, and that means vectorized operators (the operators runs the length of two paired vectors). All you need to do is make a special tuple subclass that maps the operator along another tuple (vector) and returns your vector subclass:
https://github.com/shanedrabing/pyrat/blob/e0049213152f615e4...
Anyways, this is all to say that I love `operator` and try my best not to use lamdbas much anymore (except where they are honestly simpler).
operator.length_hint
operator.itemgetter
operator.countOf
What's the (historical?) reason the operator module uses different casing standards?PEP8 was introduced in 2001: https://www.python.org/dev/peps/pep-0008/
Tables are simple key-value maps, with an optimization for dense arrays, while symbols are strings with a parser-enforced grammar. A method call is syntax sugar: table:method(...) is converted into table.method(table, ...).
This means that "methodcaller" is simply table[string](table, ...), which I've used in a few places to good effect.
This is why javascript moved away from their "super user-friendly" concept of objects-as-maps towards having a real `Map` type - because mixing data and program can get weird (and if it's user-controllable data, dangerous).
I suppose the question is - is it possible for a table in lua to contain separate entries for the string "foo" and the symbol "foo", or will one happily overwrite the other?
{ __proto__: null, foo: 'bar' }
That creates a clean prototype-less map/record object. I always wish they would add special literals to create such objects.I have no idea what you mean by advanced methods on container types though. I find the simplicity of Lua tables liberating rather than constraining.
Lua tables are a Map type, anything except nil can be a key, and every key has a value: if you haven't assigned something to that value, it's nil. There's no separate "object" and no separate "symbol", those patterns are implemented using tables and strings. Even global environments (you can have as many as you need) are just tables.
Having such methods on a table which you're still expecting to use as a container sounds like it would allow a attacker to e.g. overwrite your methods if you're processing user-controllable data.
Actually, I didn't even know about `methodcaller` till I read this blogpost, so I would have implemented your example in python as: `getattr(table, string)(...)`.
That is, sometimes when I'm making a largeish modification there's a point in the commit series where the natural way to express what's going on involves using methodcaller, then by the time the work is finished the use has gone away again.
close_file = methodcaller('close')
exhaust(map(close_file, files))
where exhaust is a function that consumes an iterator. Obviously this is a contrived example, but it's a weird transformation -- it turns map from 'call this function on each of a sequence of arguments' to, roughly 'call each of this sequence of functions on a fixed argument'Both by a compiler easily readable by a human unreadable out of purely functional languages by design this high fashion came.
Do you think it's better to use a conceptually difficult example to showcase a high order function? Or do you think it's better to show an example where the reader can accurately understand the concept and focus on what the function does?