() vs. [] operator

O

Ole Streicher

Hi,

I am curious when one should implement a "__call__()" and when a
"__getitem__()" method.

For example, I want to display functions and data in the same plot. For
a function, the natural interface would to be called as "f(x)", while
the natural interface for data would be "f[x]". On the other hand,
whether a certain data object is a function or a data table is just an
inner detail of the object (imagine f.e. a complex function that
contains a data table as cache), and there is no reason to distinguish
them by interface.

So what is the reason that Python has separate __call__()/() and
__getitem__()/[] interfaces and what is the rule to choose between them?

Regards

Ole
 
S

Steven D'Aprano

So what is the reason that Python has separate __call__()/() and
__getitem__()/[] interfaces and what is the rule to choose between them?

They are separate so you can implement both, or just one, or neither,
whichever makes the most sense for your data type.

If something is function-like, then implement __call__. If something is
sequence- or dictionary-like, then implement __getitem__. If it's both,
then make an arbitrary choice of which one you want to support, or
implement both, whichever you prefer.

The best thing to do is follow the lead of build-in objects. For example,
chr() is a function which takes an integer and returns a character, but
it makes little sense to think of it as a table of values. You wouldn't
sensibly expect to do something like:

chr[32:39] = 'abc'

and have the table replace chars ' !"#$%&' with 'abc' (changing the
length of the table). Even if chr() is implemented as a table internally,
it's actually a function.

Contrast that with xrange objects, which are implemented as lazy
sequences, i.e. something like a function. But xrange objects themselves
(not the xrange function) use the sequence interface:
33

with the limitation that it doesn't support slices.
 
C

Chris Rebert

Hi,

I am curious when one should implement a "__call__()" and when a
"__getitem__()" method.

For example, I want to display functions and data in the same plot. For
a function, the natural interface would to be called as "f(x)", while
the natural interface for data would be "f[x]". On the other hand,
whether a certain data object is a function or a data table is just an
inner detail of the object (imagine f.e. a complex function that
contains a data table as cache), and there is no reason to distinguish
them by interface.

So what is the reason that Python has separate __call__()/() and
__getitem__()/[] interfaces and what is the rule to choose between them?

Because it'd seem somewhat weird to "call" a container (e.g.
list/dict) as if it were a function, in order to subscript it. And,
like many things, the syntax/distinction is inherited from C.
Also, I'm not entirely sure on this, but I don't believe subscripting
allows for the full function call syntax (with e.g. keyword
parameters, etc).
Further, subscripting generally implies the related notion of
keys/indices and values, whereas callables carry no such association.

So that's why there's both.

Personally, I'd say you should choose subscripting if the notion of
"keys" and "values" makes sense in whatever your use case is, and call
syntax if the notion of "operation that performs work/computation" or
"non-simple query" is more applicable, especially if side-effects are
involved; subscripting is generally for fairly cheap operations, call
syntax for non-generally-cheap ones.
In the particular example you gave, I'd favor call syntax because it
ties more strongly to the notion of functions, whereas subscripting
lightly implies the data-table representation, which you rightly point
out should probably be an implementation detail.

However, there's absolutely nothing stopping you from implementing
both __call__ and __getitem__ and just having them do the same thing,
so that's also an option (though the redundancy isn't satisfying from
an aesthetic point of view).

Cheers,
Chris
 
U

Ulrich Eckhardt

Ole said:
I am curious when one should implement a "__call__()" and when a
"__getitem__()" method.

For example, I want to display functions and data in the same plot.

Wait: The term 'function' is overloaded. In Python and programming in
general, a function is a piece of code with optional input, output and side
effects. Alternative names are procedure, operation, subroutine.

In mathematics, the term 'function' refers to an algorithm that takes some
parameters, transforms them and returns a result. Note that here no side
effects can ever occur and that you always have both input parameters and
output parameters. Also, a mathematic function will always yield the same
results for the same input, which is basically a result from not having
side effects and not having variables at all.
For a function, the natural interface would to be called as "f(x)",
while the natural interface for data would be "f[x]".

In math, a function invocation is written f(x). Since this is a mere
retrieval of a value, regardless of how complicated the implementation may
be, I'd say that the natural syntax would be f[x] in Python. However, since
[] also supports writing a mapping and since an implementation may have a
significant overhead, I'd rather tend towards the function call syntax.
On the other hand, whether a certain data object is a function or a
data table is just an inner detail of the object (imagine f.e. a
complex function that contains a data table as cache), and there is
no reason to distinguish them by interface.

So what is the reason that Python has separate __call__()/() and
__getitem__()/[] interfaces and what is the rule to choose between them?

As their name implies, one invokes a function (procedure, subroutine etc)
while the other retrieves an item from a mapping. I agree that the exact
difference is not really that easy to explain and that there are corner
cases.

Uli
 
C

Carl Banks

Hi,

I am curious when one should implement a "__call__()" and when a
"__getitem__()" method.

For example, I want to display functions and data in the same plot. For
a function, the natural interface would to be called as "f(x)", while
the natural interface for data would be "f[x]". On the other hand,
whether a certain data object is a function or a data table is just an
inner detail of the object (imagine f.e. a complex function that
contains a data table as cache), and there is no reason to distinguish
them by interface.

So what is the reason that Python has separate __call__()/() and
__getitem__()/[] interfaces and what is the rule to choose between them?

It's just a language design decision. You can go either way, Python
chose to be like C instead of Fortran or Ada. I've used both kinds of
languages, and I prefer to have an external clue about the nature of
the object I'm dealing with. However, I use many languages that don't
distinguish between the two and it is not that big of a deal, and does
have some small advantages.


Carl Banks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top