Does callable(obj) make an attempt to call? - python

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?

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.

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.

Related

AttributeError: 'Player' Object has no attribute (attributes) [duplicate]

If your question was closed as a duplicate of this, it is because you had a code sample including something along the lines of either:
class Example:
def __int__(self, parameter):
self.attribute = parameter
or:
class Example:
def _init_(self, parameter):
self.attribute = parameter
When you subsequently attempt to create an instance of the class, an error occurs:
>>> Example("an argument")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Example() takes no arguments
Alternately, instances of the class seem to be missing attributes:
>>> class Example:
... def __int__(self): # or _init_
... self.attribute = 'value'
>>> Example().attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute 'attribute'
You might also wonder: what do these exception messages mean, and how do they relate to the problem? Why didn't a problem occur earlier, for example, with the class definition itself? How else might the problem manifest? How can I guard against this problem in the future?
This is an artificial canonical duplicate created specifically to head off two of the most common typographical errors in code written by new Python programmers. While questions caused by a typo are normally closed for that reason, there are some useful things to explain in this case, and having a duplicate target allows for closing questions faster. I have tried to design the question to be easy to search for.
This is because the code has a simple typographical error: the method should instead be named __init__ - note the spelling, and note that there are two underscores on each side.
What do the exception messages mean, and how do they relate to the problem?
As one might guess, a TypeError is an Error that has to do with the Type of something. In this case, the meaning is a bit strained: Python also uses this error type for function calls where the arguments (the things you put in between () in order to call a function, class constructor or other "callable") cannot be properly assigned to the parameters (the things you put between () when writing a function using the def syntax).
In the examples where a TypeError occurs, the class constructor for Example does not take arguments. Why? Because it is using the base object constructor, which does not take arguments. That is just following the normal rules of inheritance: there is no __init__ defined locally, so the one from the superclass - in this case, object - is used.
Similarly, an AttributeError is an Error that has to do with the Attributes of something. This is quite straightforward: the instance of Example doesn't have any .attribute attribute, because the constructor (which, again, comes from object due to the typo) did not set one.
Why didn't a problem occur earlier, for example, with the class definition itself?
Because the method with a wrongly typed name is still syntactically valid. Only syntax errors (reported as SyntaxError; yes, it's an exception, and yes, there are valid uses for it in real programs) can be caught before the code runs. Python does not assign any special meaning to methods named _init_ (with one underscore on each side), so it does not care what the parameters are. While __int__ is used for converting instances of the class to integer, and shouldn't have any parameters besides self, it is still syntactically valid.
Your IDE might be able to warn you about an __int__ method that takes suspicious parameters (i.e., anything besides self). However, a) that doesn't completely solve the problem (see below), and b) the IDE might have helped you get it wrong in the first place (by making a bad autocomplete suggestion).
The _init_ typo seems to be much less common nowadays. My guess is that people used to do this after reading example code out of books with poor typesetting.
How else might the problem manifest?
In the case where an instance is successfully created (but not properly initialized), any kind of problem could potentially happen later (depending on why proper initialization was needed). For example:
BOMB_IS_SET = True
class DefusalExpert():
def __int__(self):
global BOMB_IS_SET
BOMB_IS_SET = False
def congratulate(self):
global BOMB_IS_SET
if BOMB_IS_SET:
raise RuntimeError("everything blew up, gg")
else:
print("hooray!")
If you intend for the class to be convertible to integer and also wrote __int__ deliberately, the last one will take precedence:
class LoneliestNumber:
def __int__(self):
return 1
def __int__(self): # was supposed to be __init__
self.two = "can be as bad"
>>> int(LoneliestNumber())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __int__ returned non-int (type NoneType)
(Note that __int__ will not be used implicitly to convert instances of the class to an index for a list or tuple. That's done by __index__.)
How might I guard against the problem in the future?
There is no magic bullet. I find it helps a little to have the convention of always putting __init__ (and/or __new__) as the first method in a class, if the class needs one. However, there is no substitute for proofreading, or for training.

Why isn't my class initialized by "def __int__" or "def _init_"? Why do I get a "takes no arguments" TypeError, or an AttributeError?

If your question was closed as a duplicate of this, it is because you had a code sample including something along the lines of either:
class Example:
def __int__(self, parameter):
self.attribute = parameter
or:
class Example:
def _init_(self, parameter):
self.attribute = parameter
When you subsequently attempt to create an instance of the class, an error occurs:
>>> Example("an argument")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Example() takes no arguments
Alternately, instances of the class seem to be missing attributes:
>>> class Example:
... def __int__(self): # or _init_
... self.attribute = 'value'
>>> Example().attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute 'attribute'
You might also wonder: what do these exception messages mean, and how do they relate to the problem? Why didn't a problem occur earlier, for example, with the class definition itself? How else might the problem manifest? How can I guard against this problem in the future?
This is an artificial canonical duplicate created specifically to head off two of the most common typographical errors in code written by new Python programmers. While questions caused by a typo are normally closed for that reason, there are some useful things to explain in this case, and having a duplicate target allows for closing questions faster. I have tried to design the question to be easy to search for.
This is because the code has a simple typographical error: the method should instead be named __init__ - note the spelling, and note that there are two underscores on each side.
What do the exception messages mean, and how do they relate to the problem?
As one might guess, a TypeError is an Error that has to do with the Type of something. In this case, the meaning is a bit strained: Python also uses this error type for function calls where the arguments (the things you put in between () in order to call a function, class constructor or other "callable") cannot be properly assigned to the parameters (the things you put between () when writing a function using the def syntax).
In the examples where a TypeError occurs, the class constructor for Example does not take arguments. Why? Because it is using the base object constructor, which does not take arguments. That is just following the normal rules of inheritance: there is no __init__ defined locally, so the one from the superclass - in this case, object - is used.
Similarly, an AttributeError is an Error that has to do with the Attributes of something. This is quite straightforward: the instance of Example doesn't have any .attribute attribute, because the constructor (which, again, comes from object due to the typo) did not set one.
Why didn't a problem occur earlier, for example, with the class definition itself?
Because the method with a wrongly typed name is still syntactically valid. Only syntax errors (reported as SyntaxError; yes, it's an exception, and yes, there are valid uses for it in real programs) can be caught before the code runs. Python does not assign any special meaning to methods named _init_ (with one underscore on each side), so it does not care what the parameters are. While __int__ is used for converting instances of the class to integer, and shouldn't have any parameters besides self, it is still syntactically valid.
Your IDE might be able to warn you about an __int__ method that takes suspicious parameters (i.e., anything besides self). However, a) that doesn't completely solve the problem (see below), and b) the IDE might have helped you get it wrong in the first place (by making a bad autocomplete suggestion).
The _init_ typo seems to be much less common nowadays. My guess is that people used to do this after reading example code out of books with poor typesetting.
How else might the problem manifest?
In the case where an instance is successfully created (but not properly initialized), any kind of problem could potentially happen later (depending on why proper initialization was needed). For example:
BOMB_IS_SET = True
class DefusalExpert():
def __int__(self):
global BOMB_IS_SET
BOMB_IS_SET = False
def congratulate(self):
global BOMB_IS_SET
if BOMB_IS_SET:
raise RuntimeError("everything blew up, gg")
else:
print("hooray!")
If you intend for the class to be convertible to integer and also wrote __int__ deliberately, the last one will take precedence:
class LoneliestNumber:
def __int__(self):
return 1
def __int__(self): # was supposed to be __init__
self.two = "can be as bad"
>>> int(LoneliestNumber())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __int__ returned non-int (type NoneType)
(Note that __int__ will not be used implicitly to convert instances of the class to an index for a list or tuple. That's done by __index__.)
How might I guard against the problem in the future?
There is no magic bullet. I find it helps a little to have the convention of always putting __init__ (and/or __new__) as the first method in a class, if the class needs one. However, there is no substitute for proofreading, or for training.

TypeError: 'list' object is not callable when using a property

Hope this hasn't already been answered out here.
When I try to print:
import gparser
gp = gparser.I_Parser()
print(gp._z_matrix())
it's firing:
Traceback (most recent call last):
File ".\__init__.py", line 4, in <module>
print(gp._z_matrix())
TypeError: 'list' object is not callable
In gparser.py, property _z_matrix is defined as such:
#property
def _z_matrix(self):
coords = []
p = re.compile('^ [a-zA-Z] +-?[0-9]')
for line in self._file:
m = p.match(line)
if m:
coords.append(line)
return coords
I really don't understand how I'm causing this error to pop, can someone explain me this?
Properties don't need to be called in order for them to execute. Simply accessing them (the dot . used) triggers the function attached.
In short, you're invoking the property _z_matrix via gp._z_matrix and then, after it has executed and returned a list (coords) as defined, you're calling the list object by using ().
Apart from the explanation, the solution is simply to remove () to avoid the TypeError.
You need not pass parenthesis to access a property. Just do print(gp._z_matrix).

Python sixohsix twitter wrapper

i was looking at sixohsix Twitter wrapper trying to understand the code and found out that for example:
t = Twitter(...)
t.statuses.home_timeline()
Theres no statuses or home_timeline methods or attributes in the Twitter class or TwitterCall, so clearly im missing some python magic in here. Could anyone explain me whats going on there?
thanks so much in advance!
Basically Twitter is a subclass of TwitterCall and the magic takes place in __getattr__. If you're accessing an attribute that doesn't exist you'll get an AttributeError.
When that happens it runs extend_call with that attribute as argument and that'll call self.callable_cls (which also happens to be TwitterCall). This result in another TwitterCall object. The same trick is then repeated because it'll discover that home_timeline doesn't exist on that object either. It'll then call this object (because you're writing home_timeline()) and that makes a HTTP request to Twitter.
The easiest way is to step through the code to see what's going on. When you're accessing an attribute you need to read __getattr__ and when you're making a method call you need to read __call__.
There is, line 141. You should read about __getattr__.
In your example, all attributes not defined for TwitterCall class (or its descendant Twitter), that is, if AttributeError is raised by object.__getattr__, are recursively translated to a call to Twitter API, with uriparts combining all the attributes in a tuple.
So in your example, a call to statuses.home_timeline uri will be made in the end of recursion.

__class_ data member in python, how it is different from static data member in java

i am trying to execute following code to understand Class data member in python, but it is throwing StopIteration error,
class PizzaShop():
pizza_stock = 10
def get_pizza(self):
while not PizzaShop.pizza_stock:
PizzaShop.pizza_stock -= 1
yield "take yours pizza order, total pizzas left {}".format(PizzaShop.pizza_stock)
mypizza_shop = PizzaShop()
pizza_order = mypizza_shop.get_pizza()
print "{}".format(repr(pizza_order.next()))
i am expecting that it should first print some message and then any exception
i am using python 2.7, ubuntu 32bits os
output:
Traceback (most recent call last):
File "/home/scott/pythonfiles/core_python/pizza.py", line 10, in <module>
print "{}".format(repr(pizza_order.next()))
StopIteration
The problem is this line
while not PizzaShop.pizza_stock:
This will stop immediately if pizza_stock is nonzero. Which it always is. You probably intended to write
while PizzaShop.pizza_stock:
Anyway, if you want to find the details on how values, classes, etc. behave in Python, you should check the docs. It's very different from Java.
P.S. The following is unnecessary as str.format has a shorthand for calling repr. Also, you shouldn't call magic methods like .next directly. Use the builtin next() instead.
print "{}".format(repr(pizza_order.next()))
Should be
print "{!r}".format(next(pizza_order))

Categories

Resources