Will
Will

Reputation: 4469

Does callable(obj) make an attempt to call?

I am exploring an API, and using the following to see what methods are available without searching through all attributes by eye with dir():

methods = [m for m in dir(kt) if callable(getattr(kt, m))]

which throws an exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Python/2.7/site-packages/soco/core.py", line 103, in inner_function
    raise SoCoSlaveException(message)
soco.exceptions.SoCoSlaveException: The method or property "cross_fade" can only be called/used on the coordinator in a group

Ok, so I can't use cross_fade, that's fine. But I didn't try to call it, I was just trying to find out if I could.

I would have thought that callable() would be able to check using something similar to type(), but it seems like it's attempting to make a call and only catching certain types of exceptions.

I get the same exception when I tried type(kt.cross_fade), and when I just try >>> kt.cross_fade in the terminal.

So I guess there are two questions here: Does callable make an attempt to call? And, what can cause a method to "exist" but be completely unavailable?

Upvotes: 1

Views: 65

Answers (2)

user2357112
user2357112

Reputation: 281476

callable doesn't attempt to call the object. It only checks that the object has an implementation of the call operator.

The exception is occurring in the attempt to retrieve the attribute in the first place. Attribute access can be overridden to do just about anything in Python, and the cross_fade attribute of this object is implemented as a property with an only_on_master decorator on the getter that raises an exception if you try to retrieve the attribute on a slave.

Upvotes: 3

bereal
bereal

Reputation: 34292

If we look at the source code, we'll see that cross_fade is actually a property:

@property
@only_on_master  # Only for symmetry with the setter
def cross_fade(self):
    """The speaker's cross fade state.
    True if enabled, False otherwise
    """
    # ...

In turn, the getter is wrapped into only_on_master which is where the exception is raised.

Upvotes: 1

Related Questions