4

I have a function that generally accepts lists, but on occasions needs to accept functions as well. There were several ways of dealing with this, but it would have been very very useful to be able to do len(foo) for a given function foo.

In the end, instead of passing in functions, I passed in callable classes that had a __len__ function defined. But it got me thinking, since in python everything is an object, and functions can have attributes etc. just as a curiosity...

Question

Is there any way to give a function a len? A quick google didn't bring up anything.

My attempt

def foo():
    return True

def my_len(self):
    return 5

foo.__len__ = my_len

len(foo)
tim-mccurrach
  • 6,395
  • 4
  • 23
  • 41
  • adding `__len__` on the _instance_ doesn't work, even for an object. – Jean-François Fabre Mar 30 '18 at 19:38
  • https://stackoverflow.com/questions/7642434/is-there-a-way-to-implement-methods-like-len-or-eq-as-classmethods – anjaneyulubatta505 Mar 30 '18 at 19:39
  • this isn't related. foo is an instance, not a class here. – Jean-François Fabre Mar 30 '18 at 19:51
  • @ChristianDean first, congrats for the python gold. _but_ the approaches mentionned in the "original" question don't work for special classes like `function` – Jean-François Fabre Mar 30 '18 at 20:02
  • Already on it @Jean-FrançoisFabre :-) – Christian Dean Mar 30 '18 at 20:02
  • 1
    Gold badge works both ways :) – Jean-François Fabre Mar 30 '18 at 20:02
  • It wasn't a bad dupe. The OP already has a solution anyway, and the dupe explained why adding `__len__` to `foo` doesn't work. The reason why I personally don't like it as a dupe target is because adding a `__len__` method to `foo` is just one possible "solution". There might be other ways to do it. – Aran-Fey Mar 30 '18 at 20:05
  • 2
    What does your function do that it might try to compute the length of a function, but not try to call a list? I think your code needs some redesign rather than a function with a `__len__` method. – chepner Mar 30 '18 at 20:06
  • @chepner I agree, it was more a curiosity. But one practical application might be iterating through a list of iterables, but only iterating through the 'inner iterables' below a certain length. If some of those iterables are lists and some are generators, it might be helpful to be able to estimate the 'length' of the generator before hand. – tim-mccurrach Mar 30 '18 at 20:16
  • No @Aran-Fey, I didn't think it was a bad one either. But as Jean said, it wasn't really a necessary dupe as the alternative solution' didn't work with certain objects. Also, are you sure "There might be other ways to do it"? I'm pretty sure there aren't. Like [user2357112's answer](https://stackoverflow.com/questions/36557079/making-len-work-with-instance-methods/36557192#36557192) says: _"Python always looks up special methods through the object's class."_ – Christian Dean Mar 30 '18 at 20:18
  • @Tim A function and a generator are two very different things. Besides, Python provides `__length_hint__` for that use case. – chepner Mar 30 '18 at 20:21
  • @chepner yes, the example was more to give a sense of the original use case without a very very lengthy explanation, and in the original use case, I did need functions not generators. However I was not aware of `__length_hint__` that may well come in useful elsewhere. Thankyou :) – tim-mccurrach Mar 30 '18 at 20:25
  • @ChristianDean Well, it depends on how you read the question. If the question is strictly just "How can I make `len(foo)` work?", then there probably is no way to do it. But if the question is "How can I make my function work with containers _and_ callables?", then there are a few ways to do it. – Aran-Fey Mar 30 '18 at 20:35

1 Answers1

5

Adding __len__ to an object is not working (see this link added by Aran-Fey why). A function is just an object defining a __call__ method. You can define a class like this:

class Foo:
  def __call__(self):
    return True
  def __len__(self):
    return 5

Using it:

>>> foo=Foo()
>>> foo()
True
>>> len(foo)
5

It is possible to create a function which is having a length, but you should consider the use case. Python gives you a lot of power, but not everything what's possible is actually a good idea.

Günther Jena
  • 3,706
  • 3
  • 34
  • 49