0

I'm running the following code and cannot understand why python thinks that I'm not passing an argument to the endswith method:

filtered_list = list(filter(str.endswith("mp4"), my_files))

This is the error that I'm getting:

TypeError: endswith() takes at least 1 argument (0 given)

I know I can do the same thing with a lambda function instead of using the method with the class name, or to use the methodcaller, but I think this way it is shorter and cooler and I don't understand why it doesn't work. Maybe when using a class.method notation I can't pass any arguments and have to use it without paranthases?

martineau
  • 119,623
  • 25
  • 170
  • 301
Maria
  • 1

2 Answers2

1

It doesn't work because you're immediately calling str.endswith, but with one argument too few. (Try replacing str.endswith("mp4") with input("Hello?"), so you see it's evaluated immediately.)

>>> str.endswith("foo")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: endswith() takes at least 1 argument (0 given)
>>> str.endswith("foo", "oo")
True

This has to do with how "foo".endswith is a bound method, i.e. the "generic" str.endswith, but with the first "self" argument already bound to the string instance "foo".

(The error message is a bit cryptic, or "off-by-one", even, because you are indeed supposed to pass one argument in addition to "self").

This is how methods work for user-created classes too; for an instance inst of class MyClass, inst.somefunc(x) is equivalent to MyClass.somefunc(inst, x).

Anyway, the Pythonic, i.e. way cool, way to say what you want is

filtered_list = [f for f in my_files if f.endswith(".mp4")]
AKX
  • 152,115
  • 15
  • 115
  • 172
  • Thank you! So you're saying there's no way to use the endswith method with the filter function (without a lambda or methodcaller)? So, if I understand correctly, the only methods that can be used as functions in this case are methods that do not take an argument (besides self), and then the classname.methodname notation can be used? – Maria Jul 18 '22 at 17:15
  • That's correct. The important difference is that e.g. `str.startswith(...)` is a function call (which returns a boolean), `str.startswith` is just the function. `lambda: ...` is an expression that returns a function; `methodcaller` is a function that returns a function. – AKX Jul 18 '22 at 17:22
0

filter requires a callable that returns a Boolean value; str.endswith("mp4") does not evaluate to such a callable. You have to use a lambda expression or methodcaller because those do evaluate to callables.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • OP mentions both lambdas and methodcaller in their question, so I'm not sure why expand on the options they don't want to use..? – AKX Jul 17 '22 at 20:44
  • My bad. Honestly, I didn't read the rest of the question carefully enough. – chepner Jul 17 '22 at 20:50
  • Can you pleaese explain why str.endswith("mp4") is not a collable that evaluates to a Boolean value? From my understanding, in this notation each member (string) of the list should be put instead of the str part of the expression, and then it is checked if "mp4" is the ending of the string, and return True or False. From the previous answer that I got I understood that the problem has something to do with the fact that this method needs an argument. – Maria Jul 18 '22 at 17:24