Here's the code. Key new features vs the original:
Nifty, but some of the API choices seem pretty weird and unpythonic to me. Why element[f] instead of more explicit interfaces like element.map(f) and element.filter(f)? Among other things, that would let you accept callable objects that aren't "FunctionType".
Actually, all of the explicit type-checking makes me wary. Instead of this, for example:
if type(index) == int:
result.append(self.list[index])
I would do this:
try:
result.append(self.list[index])
...
Matt, you are certainly welcome to use the tradtional map and filter builtin functions on these objects. My goal with this particular overload was to achive something that would seem XPath-ish.
I don't see how this choice in syntax limits the types of callable objects... can you provide an example of what you were looking for?
The explicit type checking is a consequence of this overloading, coupled with an inability to modify the original definitions of the various types. Yes, some cases could be recast as try blocks, but not all of them, and IMHO, some clarity would be lost.
Okay, I agree that mimicking XPath is a good reason to use slightly non-standard syntax.
Regarding type-checking: Lots of Python objects look and act like functions, but are not "types.FunctionType" objects. This includes built-in functions ("range"), unbound methods ("class.f"), instance methods ("obj.f"), types ("xrange"), and classes ("class").
To properly test for a "function-like" object, you can change this:
isinstance(index,types.FunctionType)
into this (which is also easier to read):
callable(index)
yup, callable is clearly better here.
P.S. Matt - next time you leave a comment, change the semicolon to a colon in your URL. I fixed it manually the first time, but left the one above to show the problem.
[Fixed the URL, thanks.]
Similar arguments apply for "string-like" and "int-like" objects -- things that should work but won't because of too-explicit type checking.
That's why I prefer not to overload arguments by type in Python. Alternatives are: checking capabilities (e.g. "callable") instead of types; testing arguments with try/catch blocks; using keyword arguments; or using separate methods instead of overloading a single method name.