Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python property callable

Is there any way to have a property and a method with the same name? I mean a property that can be used the usual way and to be callable at the same time? Like this:

>>> b = Book()
>>> b.pages
123
>>> b.pages()
123
>>> b.pages(including_toc=False)
123
>>> b.pages(including_toc=True)
127
like image 218
Zahory Avatar asked Oct 23 '12 11:10

Zahory


People also ask

Is property callable in Python?

Python callable() Method The callable() method returns True if the object passed is callable, False if not. In Python, classes, methods, and instances are callable because calling a class returns a new instance. Instances are callable if their class includes __call__() method.

What is callable () type in Python?

Definition and Usage The callable() function returns True if the specified object is callable, otherwise it returns False.

What objects in Python are callable?

Python's functions are callable objects print("Hi", name) ... So, every function in Python is a callable, meaning it's an object that you're able to call.


1 Answers

A instance of your Book class can only have one attribute called pages. That attribute can be anything (an integer, a callable function, anything really), but it can only be one thing.

Another way of viewing things is at the byte-code level - given two lines of code:

>>> def a():
...     book.pages
...     book.pages()
... 

Here is what it disassembles:

>>> dis.dis(a)
  2           0 LOAD_GLOBAL              0 (book)
              3 LOAD_ATTR                1 (pages)
              6 POP_TOP

  3           7 LOAD_GLOBAL              2 (book)
             10 LOAD_ATTR                1 (pages)
             13 CALL_FUNCTION            0
  [...a few more irrelevant lines...]

The first line (book.pages) loads the book object, and from that loads the pages attribute (LOAD_ATTR)

The second line (book.pages()) does the exact same thing, loads the book object, loads the pages attribute, then calls the CALL_FUNCTION attribute.

There is no sane way you can make the LOAD_ATTR return something different based on how it will eventually be used. The closest you can get is to return a weird object which acts like both

>>> class WeirdInteger(int):
...   def __call__(self, including_toc):
...     print "WeirdInteger(%s) called" % (self)
...
>>> a = WeirdInteger(10)
>>> a
10
>>> a*2
20
>>> a()
WeirdInteger(10) called

..but, don't do that. No one using you code will expect the pages attribute to work like this, and bits of code the pages will be passed to might require an actual integer.

Instead design your Books class differently (maybe make pages an regular function, or add a separate property for the pages_without_toc)

like image 198
dbr Avatar answered Oct 02 '22 14:10

dbr