Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #50441 > unrolled thread
| Started by | Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> |
|---|---|
| First post | 2013-07-11 15:05 +0200 |
| Last post | 2013-07-12 01:11 -0600 |
| Articles | 9 — 6 participants |
Back to article view | Back to comp.lang.python
Callable or not callable, that is the question! Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> - 2013-07-11 15:05 +0200
Re: Callable or not callable, that is the question! Peter Otten <__peter__@web.de> - 2013-07-11 16:11 +0200
Re: Callable or not callable, that is the question! Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> - 2013-07-12 08:41 +0200
Re: Callable or not callable, that is the question! Duncan Booth <duncan.booth@invalid.invalid> - 2013-07-12 07:36 +0000
Re: Callable or not callable, that is the question! Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-12 09:49 +0000
Re: Callable or not callable, that is the question! Peter Otten <__peter__@web.de> - 2013-07-12 12:36 +0200
Re: Callable or not callable, that is the question! Jason Swails <jason.swails@gmail.com> - 2013-07-11 10:28 -0400
Re: Callable or not callable, that is the question! Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-12 02:12 +0000
Re: Callable or not callable, that is the question! Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-12 01:11 -0600
| From | Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> |
|---|---|
| Date | 2013-07-11 15:05 +0200 |
| Subject | Callable or not callable, that is the question! |
| Message-ID | <n6n2ba-ubg.ln1@satorlaser.homedns.org> |
Hello!
I just stumbled over a case where Python (2.7 and 3.3 on MS Windows)
fail to detect that an object is a function, using the callable()
builtin function. Investigating, I found out that the object was indeed
not callable, but in a way that was very unexpected to me:
class X:
@staticmethod
def example():
pass
test1 = example
test2 = [example,]
X.example() # OK
X.test1() # OK
X.test2[0]() # TypeError: 'staticmethod' object is not callable
Bug or feature?
Thanks!
Uli
[toc] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-07-11 16:11 +0200 |
| Message-ID | <mailman.4586.1373551911.3114.python-list@python.org> |
| In reply to | #50441 |
Ulrich Eckhardt wrote: > Hello! > > I just stumbled over a case where Python (2.7 and 3.3 on MS Windows) > fail to detect that an object is a function, using the callable() > builtin function. Investigating, I found out that the object was indeed > not callable, but in a way that was very unexpected to me: > > class X: > @staticmethod > def example(): > pass > test1 = example > test2 = [example,] > > X.example() # OK > X.test1() # OK > X.test2[0]() # TypeError: 'staticmethod' object is not callable Slightly modified example: >>> @staticmethod ... def example(): return 42 ... >>> class X: ... example = example ... >>> X.example() 42 >>> example() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'staticmethod' object is not callable When you access an attribute its __get__() method is implicitly called. This is part of the descriptor protocol: >>> X.example <function example at 0x7fe45c0ea3b0> >>> example <staticmethod object at 0x7fe45aafc090> >>> example.__get__(X) <function example at 0x7fe45c0ea3b0> While it would be easy to make staticmethod callable >>> class Staticmethod(staticmethod): ... def __call__(self, *args, **kw): ... return self.__func__(*args, **kw) ... >>> @Staticmethod ... def foo(): return "bar" ... >>> foo() 'bar' >>> X.baz = foo >>> X.baz() 'bar' I see no clear advantage over the current situation. > Bug or feature? No bug. Missing feature if you come up with a convincing use-case.
[toc] | [prev] | [next] | [standalone]
| From | Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> |
|---|---|
| Date | 2013-07-12 08:41 +0200 |
| Message-ID | <11l4ba-u4l.ln1@satorlaser.homedns.org> |
| In reply to | #50446 |
Am 11.07.2013 16:11, schrieb Peter Otten:
> Ulrich Eckhardt wrote:
>> Bug or feature?
>
> No bug. Missing feature if you come up with a convincing use-case.
class Parser:
def _handle_bool(input):
# ...
pass
types = {'bool': _handle_bool,
'boolean': _handle_bool,}
def parse(self, line):
t,s,v = line.partition(':')
handler = types[t]
return handler(v)
I want a utility function that really behaves just like a function. I'd
prefer to nest it inside the class that uses it, to make the code easier
to understand. Since I don't want the implicit self-binding either, I
would use staticmethod to make this clear, too.
Since I can live without any of this, it's not a big issue. What is to
me a big issue though is the fact that Python behaves unexpectedly and
reading Steven's response and the link there, it seems I'm not alone.
Greetings!
Uli
[toc] | [prev] | [next] | [standalone]
| From | Duncan Booth <duncan.booth@invalid.invalid> |
|---|---|
| Date | 2013-07-12 07:36 +0000 |
| Message-ID | <XnsA1FB578CDBB3Cduncanbooth@127.0.0.1> |
| In reply to | #50501 |
Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> wrote:
> Am 11.07.2013 16:11, schrieb Peter Otten:
>> Ulrich Eckhardt wrote:
>>> Bug or feature?
>>
>> No bug. Missing feature if you come up with a convincing use-case.
>
> class Parser:
> def _handle_bool(input):
> # ...
> pass
>
> types = {'bool': _handle_bool,
> 'boolean': _handle_bool,}
>
> def parse(self, line):
> t,s,v = line.partition(':')
> handler = types[t]
> return handler(v)
>
> I want a utility function that really behaves just like a function. I'd
> prefer to nest it inside the class that uses it, to make the code easier
> to understand. Since I don't want the implicit self-binding either, I
> would use staticmethod to make this clear, too.
But the example you gave works just fine as written! You are only using
your utility function as a function so there's no need for it to be a
staticmethod or indeed any other sort of method.
To be a convincing use-case you would have to show a situation where
something had to be both a static method and a utility method rather than
just one or the other and also where you couldn't just have both.
If you can persuade me that you need _handle_bool as both a static method
and a utility function, you probably also need to explain why you can't
just use both:
class Parser:
def _handle_bool(input): ...
handle_bool = staticmethod(_handle_bool)
--
Duncan Booth http://kupuguy.blogspot.com
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-07-12 09:49 +0000 |
| Message-ID | <51dfd11a$0$9505$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #50507 |
On Fri, 12 Jul 2013 07:36:30 +0000, Duncan Booth wrote:
> To be a convincing use-case you would have to show a situation where
> something had to be both a static method and a utility method rather
> than just one or the other and also where you couldn't just have both.
I have a class where I have a function that needs to be called both while
the class is being constructed, and afterwards:
class Example:
@staticmethod
def do_stuff(arg):
...
do_stuff(23) # This doesn't work.
Example.do_stuff(42)
I have work-arounds: inside the class, I call do_stuff.__func__ instead
of do_stuff, but really, that's ugly and distracting and merely a work-
around for the fact that staticmethods aren't callable. To make them
callable is trivially easy: they just need a __call__ method that calls
__func__ for you.
> If you can persuade me that you need _handle_bool as both a static
> method and a utility function, you probably also need to explain why you
> can't just use both:
>
> class Parser:
> def _handle_bool(input): ...
> handle_bool = staticmethod(_handle_bool)
That's extremely inelegant. Why have two functions for something which is
conceptually one?
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-07-12 12:36 +0200 |
| Message-ID | <mailman.4628.1373625429.3114.python-list@python.org> |
| In reply to | #50514 |
Steven D'Aprano wrote: > On Fri, 12 Jul 2013 07:36:30 +0000, Duncan Booth wrote: > >> To be a convincing use-case you would have to show a situation where >> something had to be both a static method and a utility method rather >> than just one or the other and also where you couldn't just have both. > > I have a class where I have a function that needs to be called both while > the class is being constructed, and afterwards: > > class Example: > @staticmethod > def do_stuff(arg): > ... > > do_stuff(23) # This doesn't work. > > Example.do_stuff(42) That is a bit too abstract for my taste to count as a use-case. Also, as given the example will work in Python 3 when you remove the @staticmethod ;) That said I can see that the error comes as a surprise and I would be fine with callable staticmethod objects.
[toc] | [prev] | [next] | [standalone]
| From | Jason Swails <jason.swails@gmail.com> |
|---|---|
| Date | 2013-07-11 10:28 -0400 |
| Message-ID | <mailman.4587.1373552924.3114.python-list@python.org> |
| In reply to | #50441 |
[Multipart message — attachments visible in raw view] — view raw
On Thu, Jul 11, 2013 at 9:05 AM, Ulrich Eckhardt < ulrich.eckhardt@dominolaser.com> wrote: > Hello! > > I just stumbled over a case where Python (2.7 and 3.3 on MS Windows) fail > to detect that an object is a function, using the callable() builtin > function. Investigating, I found out that the object was indeed not > callable, but in a way that was very unexpected to me: > > class X: > @staticmethod > def example(): > pass > test1 = example > test2 = [example,] > > X.example() # OK > X.test1() # OK > X.test2[0]() # TypeError: 'staticmethod' object is not callable > Interestingly, you can actually use this approach to 'fake' staticmethod before staticmethod was even introduced. By accessing example from inside the test2 class attribute list, there is no instance bound to that method (even if an instance was used to access it). Using Python 3.3: Python 3.3.2 (default, Jun 3 2013, 08:29:09) [GCC 4.5.4] on linux Type "help", "copyright", "credits" or "license" for more information. >>> class X: ... def example(): pass ... test = example, ... >>> X.test[0]() >>> Using Python 2.0 (pre-staticmethod): Python 2.0.1 (#1, Aug 28 2012, 20:25:41) [GCC 4.5.3] on linux3 Type "copyright", "credits" or "license" for more information. >>> class X: ... def example(): pass ... test = example, ... >>> X.test[0]() >>> staticmethod Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: There is no variable named 'staticmethod' Once you change test into an instance attribute, you get back to the expected behavior Python 3.3.2 (default, Jun 3 2013, 08:29:09) [GCC 4.5.4] on linux Type "help", "copyright", "credits" or "license" for more information. >>> class X: ... def example(self): pass ... test = example, ... >>> inst = X() >>> inst.example() >>> inst.test[0]() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: example() missing 1 required positional argument: 'self' >>> inst.test = inst.example, >>> inst.test[0]() >>> All the best, Jason
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-07-12 02:12 +0000 |
| Message-ID | <51df65f7$0$9505$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #50441 |
On Thu, 11 Jul 2013 15:05:59 +0200, Ulrich Eckhardt wrote: > Hello! > > I just stumbled over a case where Python (2.7 and 3.3 on MS Windows) > fail to detect that an object is a function, using the callable() > builtin function. Investigating, I found out that the object was indeed > not callable, but in a way that was very unexpected to me: [...] > X.test2[0]() # TypeError: 'staticmethod' object is not callable > > > Bug or feature? In my opinion, a bug. I thought I had actually submitted it to the bug tracker, but apparently I was a shameful slacker and did not. However there was a discussion in this thread: http://mail.python.org/pipermail/python-dev/2011-March/109090.html Here's a simpler demonstration of the issue: assert callable(staticmethod(lambda: None)) -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2013-07-12 01:11 -0600 |
| Message-ID | <mailman.4616.1373613111.3114.python-list@python.org> |
| In reply to | #50484 |
On Thu, Jul 11, 2013 at 8:12 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > On Thu, 11 Jul 2013 15:05:59 +0200, Ulrich Eckhardt wrote: > >> Hello! >> >> I just stumbled over a case where Python (2.7 and 3.3 on MS Windows) >> fail to detect that an object is a function, using the callable() >> builtin function. Investigating, I found out that the object was indeed >> not callable, but in a way that was very unexpected to me: > [...] >> X.test2[0]() # TypeError: 'staticmethod' object is not callable >> >> >> Bug or feature? > > In my opinion, a bug. I thought I had actually submitted it to the bug > tracker, but apparently I was a shameful slacker and did not. However > there was a discussion in this thread: > > http://mail.python.org/pipermail/python-dev/2011-March/109090.html > > > Here's a simpler demonstration of the issue: > > assert callable(staticmethod(lambda: None)) If staticmethod is going to be callable then classmethod should be callable also.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web