Re: () vs. [] operator
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 -- http://mail.python.org/mailman/listinfo/python-list
Re: () vs. [] operator
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 -- http://mail.python.org/mailman/listinfo/python-list
Re: () vs. [] operator
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 -- http://mail.python.org/mailman/listinfo/python-list
Re: () vs. [] operator
On Thu, Oct 15, 2009 at 5:14 PM, 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? Hi, This is very interesting, a thought that never occured to me before. Usually, a function is a function; an array (list, iterator, whatever you have) is, well, an array of data. You access them by index. Mathematically speaking, functions are usually continuous. For any given continuous function, you can give it any value of input (1, 0.1, or even 0.01) and it'll give you one output. But obviously we don't call an item from index 0.1, but 0, 1, 2, 3, and so on. That's probably the first sign where your function might be best fitted. Also, one would normally expect a __getitem__() call to be very fast; it would be awkward to return A[1] a hundred times slower than A[1]. That said, it's a simple constant-time look up. That'll give you another clue when to distinquish the two functions. The other way also works; if a function takes any floating/decimal number, usually we expect it to be callable, with the () operator. I can think of funky things like to memorise every function call that has been done, and look up the memory if this same input has been called before; it might speed up some calculation for certain purposes. All in all, a good idea to separate the two operators. Cheers, Xav -- http://mail.python.org/mailman/listinfo/python-list
Re: () vs. [] operator
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 -- http://mail.python.org/mailman/listinfo/python-list