Python higher order functions usage with str.startswith
Question: I have a file which I want to clean commented lines from. **I'd like to use
python`functools.partial` for the operation**, in something similar to the
following manner:

    
    
    from functools import partial
    
    f = open(filetoread, "r")
    lines = f.readlines()
    f.close()
    
    # Filtering the comment lines
    f_func = partial(str.startswith, prefix="#")
    lines = filter(f_func, lines)
    

This does not work, apparently because `str.startswith` is a class method.
What is the proper way to use `functools.partial` with `str.startswith` so it
will work?


Answer: You have three problems:

First, `str.startswith` doesn't take keyword arguments, it takes positional
arguments only. It's implemented in C, and uses `PyArg_ParseTuple` to get its
positional arguments. There's nothing to tell Python what names they have,
since the name `prefix` appears only in the docstring. So `prefix=` is no
good. The problem is analogous to this:

    
    
    >>> str.startswith('#hi', prefix='#')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: startswith() takes no keyword arguments
    >>> def foo(self,prefix,start=None,end=None): return str.startswith(self,prefix,start,end)
    ...
    >>> foo('#hi', prefix='#')
    True
    

Second, the first argument of `str.startswith` is not the prefix, it's `self`,
the object in which we're checking whether or not it has the prefix. There's
no inherent problem with it being a method, you'd be fine if there was a
method called `str.isprefixof`, or if this method were implemented in Python.
But there isn't and it isn't.

Finally, `functools.partial` only lets you bind the initial positional
arguments, it doesn't know how to bind the second but not the first. Since the
argument you want to bind isn't the first and isn't accessible by name, you're
out of options.

There's a workaround for this case, though, to write functional-style code.
You just need `operator.methodcaller`, not `functools.partial`:

    
    
    f_func = operator.methodcaller('startswith', '#')
    

`operator.methodcaller` binds all arguments _except_ the first.

* * *

Since you ask what's the proper way to use `functools`, I suppose you could do
so with an extra higher-order function to reverse the arguments:

    
    
    def flip(func):
        return lambda x,y: func(y,x)
    
    f_func = partial(flip(str.startswith), '#')
    

You might consider this "cheating" since it uses a lambda, and if we wanted to
use a lambda we'd have used it like in Daniel's answer. But we're using it to
implement a basic higher-order function that Python doesn't provide, and once
that's out of the way the line to define `f_func` feels nice and functional.

Mind you, I'm not implementing that higher-order function particularly _well_
here in Python terms, since I don't provide any meta-data like `partial` does.
It has a `func` read-only attribute that users might reasonably want `flip` to
provide too.

Alternatively, you could write a Python wrapper to `str.startswith`, like
`foo` above, and apply `partial` to that.

