() vs. [] operator

Discussion in 'Python' started by Ole Streicher, Oct 15, 2009.

  1. 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
     
    Ole Streicher, Oct 15, 2009
    #1
    1. Advertising

  2. On Thu, 15 Oct 2009 09:14:35 +0200, Ole Streicher wrote:

    > 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:

    >>> obj = xrange(23, 42)
    >>> obj[10]

    33

    with the limitation that it doesn't support slices.



    --
    Steven
     
    Steven D'Aprano, Oct 15, 2009
    #2
    1. Advertising

  3. Ole Streicher

    Chris Rebert Guest

    On Thu, Oct 15, 2009 at 12:14 AM, Ole Streicher <> wrote:
    > 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
    --
    http://blog.rebertia.com
     
    Chris Rebert, Oct 15, 2009
    #3
  4. Ole Streicher wrote:
    > 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

    --
    Sator Laser GmbH
    Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
     
    Ulrich Eckhardt, Oct 15, 2009
    #4
  5. Ole Streicher

    Carl Banks Guest

    On Oct 15, 12:14 am, Ole Streicher <> wrote:
    > 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
     
    Carl Banks, Oct 15, 2009
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jakob Bieling

    Q: operator void* or operator bool?

    Jakob Bieling, Mar 5, 2004, in forum: C++
    Replies:
    2
    Views:
    626
    Rob Williscroft
    Mar 5, 2004
  2. John Smith
    Replies:
    2
    Views:
    453
    Ivan Vecerina
    Oct 6, 2004
  3. Alex Vinokur
    Replies:
    4
    Views:
    3,082
    Peter Koch Larsen
    Nov 26, 2004
  4. Alex Vinokur
    Replies:
    3
    Views:
    5,068
    Jeff Schwab
    Mar 20, 2005
  5. Tim Clacy
    Replies:
    15
    Views:
    2,756
    Kanenas
    May 30, 2005
Loading...

Share This Page