Many Python builtin "functions" are actually classes, although they also have a straightforward function implementation. Even very simple ones, such as itertools.repeat
. What is the motivation for this? It seems like over-engineering to me.
Edit: I am not asking about the purpose of itertools.repeat
or any other particular function. It was just an example of a very simple function with a very simple possible impementation:
def repeat(x):
while True: yield x
But itertools.repeat
is not actually a function, it's implemented as a class. My question is: Why? It seems like unnecessary overhead.
Also I understand that classes are callable functions and how you can emulate a function-like behavior using a class. But I don't understand why it's so widely used through the standard library.
The built-in Python functions are pre-defined by the python interpreter. There are 68 built-in python functions. These functions perform a specific task and can be used in any program, depending on the requirement of the user.
The Python Standard Library provides a built-in module that contains classes to read, process, and write CSV files. Although this module is quite helpful for simple manipulations, it is recommended to use Pandas for more complex numerical analysis.
Implementing as a class for itertools
has some advantages that generator functions don't have. For example:
__next__
that preserves state as instance attributes; yield
based generators are a Python layer nicety, and really, they're just an instance of the generator
class (so they're actually still class instances, like everything else in Python)__reduce__
/__copy__
/__deepcopy__
(and if it's a Python level class, it probably doesn't even need to do that; it will work automatically) and make the instances pickleable/copyable (so if you have already generated 5 elements from a range
iterator, you can copy or pickle/unpickle it, and get an iterator the same distance along in iteration)For non-generator tools, the reasons are usually similar. Classes can be given state and customized behaviors that a function can't. They can be inherited from (if that's desired, but C layer classes can prohibit subclassing if they're "logically" functions).
It's also useful for dynamic instance creation; if you have an instance of an unknown class but a known prototype (say, the sequence constructors that take an iterable, or chain
or whatever), and you want to convert some other type to that class, you can do type(unknown)(constructorarg)
; if it's a generator, type(unknown)
is useless, you can't use it to make more of itself because you can't introspect to figure out where it came from (not in reasonable ways).
And beyond that, even if you never use the features for programming logic, what would you rather see in the interactive interpreter or doing print debugging of type(myiter)
, <class 'generator'>
that gives no hints as to origin, or <class 'itertools.repeat'>
that tells you exactly what you have and where it came from?
Both functions and classes are callables, so they can be used interchangeably in higher-order functions, for example.
$ python2
...
>>> map(dict, [["ab"], ["cd"], ["ef"]])
[{'a': 'b'}, {'c': 'd'}, {'e': 'f'}]
>>> map(lambda x: dict(x), [["ab"], ["cd"], ["ef"]])
[{'a': 'b'}, {'c': 'd'}, {'e': 'f'}]
That said, classes can also define methods that you can later call on the returned objects. For instance, the dict
class defines the .get()
method for dictionaries, etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With