I am new to python. I see two kinds of functions. The first one is new to me,
a.append(x)
and the second one, which looks more familiar
a = len(x)
Can I conver the first form to the second form? Or vice versa?
I am new to python. I see two kinds of functions. The first one is new to me,
a.append(x)
and the second one, which looks more familiar
a = len(x)
Can I conver the first form to the second form? Or vice versa?
This makes it sound like you used other programming languages before. Is that so? Which ones? This might make it easier to explain, in terms of what you already know.
I am used to matlab.
In
a.append(x)
a
is an object. append
is the method being called on the object. x
is a parameter to the method.
This is a case of object oriented programming. The gist here is that instead of having a function like:
append(my_list, new_item)
that would need to be given all things each time its called, you have append(new_item)
that is already aware of the list it is associated with (since it got that by virtue of being called via a.append(..)
.
So I can say:
a = [1,2,3]
a.append(4)
print(a)
and it would print:
[1, 2, 3, 4]
so it added 4
to the end of a
.
len()
is a built-in function that gets the length (number of elements) of the given thing. Under the hood len()
basically just calls the __len__()
method of the given object.
So for our case:
a = [1,2,3]
print(len(a))
print(a.__len__())
prints:
3
3
We typically don’t call .__len__()
as we generally would use len()
here. (.__len__()
is often an implementation detail).
I don’t really know the history of why len()
is free-function instead of a normal method on the object.
A polymorphic helper-function
It’s not difficult to look up:
The short version:
len
can do validation that’s common to all types (i.e. ensure that an integer <= sys.maxsize
is returned)len
can be optimized for primitives: at the C level, it can directly check a struct member (and avoid that validation step), whereas calling __len__
is emulated via a “slot-wrapper”Regarding optimization - for a user-defined class, __len__
is faster because it skips validation:
>>> import timeit
>>> class x:
... def __len__(self): return 0
...
>>> timeit.timeit("len(my_x)", setup="my_x=x()", globals=globals())
0.08995063393376768
>>> timeit.timeit("my_x.__len__", setup="my_x=x()", globals=globals())
0.038709620013833046
But for builtins it’s the other way around, because the __len__
is emulated in terms of primitive len
:
>>> timeit.timeit("len('')")
0.03753247996792197
>>> timeit.timeit("''.__len__()")
0.06348034297116101