superclass method not working as Expected, Why? - python-3.x

This is my self defined class. But error occurs.
>>> class Int(int):
def __add__(self, other):
return super() + other
>>> f = Int(10)
>>> f + 4
Traceback (most recent call last):
File "<pyshell#110>", line 1, in <module>
f + 4
File "<pyshell#108>", line 3, in __add__
return super() + other
TypeError: unsupported operand type(s) for +: 'super' and 'int'
I know replacing return super() + other with return super().__add__(other) solves the problem. But why doesn't the previous code work. I am confused. Can anyone please explain.
I know super() returns a type: <class 'super'>. Then why super.__add__(other) work and super() + other doesn't ?

You need to overload operators in this case to perform the customized addition. Unlike typical scalar addition, python doesn't know how to perform the addition of custom type that you are asking for and hence it complain. There is a good reference available here which will help you as a starting point to do further research.

Related

Class assignment: object not callable [duplicate]

As a starting developer in Python I've seen this error message many times appearing in my console but I don't fully understand what does it means.
Could anyone tell me, in a general way, what kind of action produces this error?
That error occurs when you try to call, with (), an object that is not callable.
A callable object can be a function or a class (that implements __call__ method). According to Python Docs:
object.__call__(self[, args...]): Called when the instance is “called” as a function
For example:
x = 1
print x()
x is not a callable object, but you are trying to call it as if it were it. This example produces the error:
TypeError: 'int' object is not callable
For better understaing of what is a callable object read this answer in another SO post.
The other answers detail the reason for the error. A possible cause (to check) may be your class has a variable and method with the same name, which you then call. Python accesses the variable as a callable - with ().
e.g. Class A defines self.a and self.a():
>>> class A:
... def __init__(self, val):
... self.a = val
... def a(self):
... return self.a
...
>>> my_a = A(12)
>>> val = my_a.a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>>
The action occurs when you attempt to call an object which is not a function, as with (). For instance, this will produce the error:
>>> a = 5
>>> a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
Class instances can also be called if they define a method __call__
One common mistake that causes this error is trying to look up a list or dictionary element, but using parentheses instead of square brackets, i.e. (0) instead of [0]
The exception is raised when you try to call not callable object. Callable objects are (functions, methods, objects with __call__)
>>> f = 1
>>> callable(f)
False
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
I came across this error message through a silly mistake. A classic example of Python giving you plenty of room to make a fool of yourself. Observe:
class DOH(object):
def __init__(self, property=None):
self.property=property
def property():
return property
x = DOH(1)
print(x.property())
Results
$ python3 t.py
Traceback (most recent call last):
File "t.py", line 9, in <module>
print(x.property())
TypeError: 'int' object is not callable
The problem here of course is that the function is overwritten with a property.

How to fix Operand error for method and int

I have this simple script but i get an operand error in Line 16
Code:
class Person:
number_of_people = 0
Gravity = -9.5
def __init__(self, name):
self.name = name
Person.add_person()
#classmethod
def number_of_people(cls):
return cls.number_of_people
#classmethod
def add_person(cls):
cls.number_of_people += 1
p1 = Person("joe")
p2 = Person("frank")
print(Person.number_of_peple())
Error message:
Traceback (most recent call last):
File "app4.py", line 19, in <module>
p1 = Person("joe")
File "app4.py", line 7, in __init__
Person.add_person()
File "app4.py", line 16, in add_person
cls.number_of_people += 1
TypeError: unsupported operand type(s) for +=: 'method' and 'int'
What can i do to fix this error?
In this question it say i need to take the varaible name but I only want to increment and not have a variable for that
TypeError: unsupported operand type(s) for +=: 'method' and 'int' (Python)
Your static variable number_of_people and your class method def number_of_people(cls) are named the exact same thing.
Thus when you add one to cls.number_of_people, the interpreter thinks you want to add a number to the class method which doesn't make sense. You have to change the name of one of those things.

Python 3: How to judge if the given function can be called successfully (i.e. reach the first line of the function body) with the given arguments?

I need to write a function f. It takes a function g and a set of *args and **kwargs as input. It's supposed to call the input function g with the arguments and return its result. One requirement: if the given arguments are not accepted by the function, I should raise a custom exception instead of letting python trigger it's own TypeError. How do I know that the given arguments cannot be used to call the given function successfully?
Example:
def f(g, *args, **kwargs):
# How to implement bad_arguments()?
if bad_arguments(g, *args, **kwargs):
raise CustomTypeError()
else:
return g(*args, **kwargs)
My first guess is to use the inspect module. I know I can look at all the expected arguments by inspecting the function. But then how do I determine whether or not the provided arguments fulfill the requirement, specially considering there might be variable args (i.e. *args and **kwargs) in g's signature and the calling arguments might specify positional arguments by names. It seems complicated enough to me that manual logic just seem to be unreliable here.
EDIT
Please see my comments to this question. I hope they clarify my question a bit more.
Also, to ask the question in a different way: you know how python checks the arguments before actually invoking your function body and raises TypeError if it finds something mismatching (e.g. when an argument is not provided, or when a named parameter which is not on the argument list is provided)? I basically want to do the same logic here then raise my CustomTypeError.
** EDIT in reply to #SigmaPiEpsilon:**
I seemed to have found a bug in your example code (which is totally fine considering it was just an example to illustrate your idea).
My point being, manual reproduction of this standard python logic might be erroneous. And that's why I prefer a more systematic way, if you will.
from inspect import signature
def check_args(f, *args, **kwargs):
sig = signature(f)
parameters = {"POSITIONAL_OR_KEYWORD" : [], "KEYWORD_ONLY" : []}
for elem in sig.parameters.values():
parameters[str(elem.kind)].append(elem.name)
print(parameters)
if len(args) > len(parameters["POSITIONAL_OR_KEYWORD"]):
print("More positional arguments")
elif len(kwargs) != len(parameters["KEYWORD_ONLY"]):
print("Insufficient keyword arguments")
elif set(kwargs.keys()) != set(parameters["KEYWORD_ONLY"]):
print("Provided keywords %s does not match function keywords %s" %(list(kwargs.keys()),parameters["KEYWORD_ONLY"]))
else:
z,u = f(*args,**kwargs)
def f(x, y, z, kw="Hello"):
u = x + y
v = x/y
print(z)
print(kw)
return z, u
f(3, 4, 5, kw='a')
check_args(f, 3, 4, 5, kw='a')
The output is:
$ python test.py
5
a
{'POSITIONAL_OR_KEYWORD': ['x', 'y', 'z', 'kw'], 'KEYWORD_ONLY': []}
Insufficient keyword arguments
This is a difficult problem to solve generally due to the flexibility of python function arguments (positional, keywords, keyword only etc). As such it is probably better to solve specific cases that suits your applications. For details look into python Signature and Parameter objects of python inspect module. A crude example is provided below to illustrate one approach that uses the bind() method of the signature object. You can adapt this to fit your specific example.
Edit: Added a version of the check in line with OP's requirement. Check previous edits for more customized checking of arguments
from inspect import signature
def check_args(f, *args, **kwargs):
sig = signature(f)
try:
bound = sig.bind(*args,**kwargs)
except TypeError:
return False
else:
return True
def f(g, *args, **kwargs):
if not check_args(g, *args, **kwargs):
raise Exception("Bad Arguments")
else:
return g(*args, **kwargs)
def g(x, y,*,z,kw="Hello"):
u = x + y
v = x*y
print(z)
print(kw)
return u
f(g,3,4,z = 5, kw = "Hello")
Test in python 3.4
$ python3.4 -i function_check2.py
5
Hello
>>> f(g,3,4,5,z = 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "function_check2.py", line 16, in f
raise Exception("Bad Arguments")
Exception: Bad Arguments
>>> f(g,3,4,z = 5)
5
Hello
7
>>> f(g,3,4,kw = "Hello")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "function_check2.py", line 16, in f
raise Exception("Bad Arguments")
Exception: Bad Arguments

Keep getting error `TypeError: 'float' object is not callable' when trying to run file using numpy library

I intend to perform a Newton Raphson iteration on some data I read in from a file. I use the following function in my python program.
def newton_raphson(r1, r2):
guess1 = 2 * numpy.log(2) / (numpy.pi() * (r1 + r2))
I call this function as so:
if answer == "f": # if data is in file
fileName = input("What is the name of the file you want to open?")
dataArray = extract_data_from_file(fileName)
resistivityArray = []
for i in range(0, len(dataArray[0])):
resistivity_point = newton_raphson(dataArray[0][i], dataArray[1][i])
resistivityArray += [resistivity_point]
On running the program and entering my file, this returns `TypeError: 'float' object is not callable'. Everything I've read online suggests this is due to missing an operator somewhere in my code, but I can't see where I have. Why do I keep getting this error and how do I avoid it?
numpy.pi is not a function, it is a constant:
>>> import numpy
>>> numpy.pi
3.141592653589793
Remove the () call from it:
def newton_raphson(r1, r2):
guess1 = 2 * numpy.log(2) / (numpy.pi * (r1 + r2))
as that is causing your error:
>>> numpy.pi()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'float' object is not callable

Utilizing collections module in Python 3

Relatively pointed question. Currently running Python 3.4.1 and am just working on an object-orientated exercise where I need to overwrite some functions from an inherited class.
Goal:
importing from builtin module collections and utilizing collections.UserList rewrite the append, extend so that it will not "add" any duplicates if detected. (this part accomplished)
Problem:
The main problem is that I still am learning object oriented programming and I want to build objects which can be easily typed in and returned so I am writing a str and repr for my class
Currently my class looks like the below: (omitted the "goal" stuff because it works)
import collections
class UList (collections.UserList):
def __init__(self, entry =[]):
self.entry = entry
def __str__ (self):
print (self.entry)
return
def __repr__(self):
return self.__str__()
Then I decide to run some sample code for good measure:
>>> x = UList ([4,5,6])
>>> x.entry
[4, 5, 6]
>>> x
[4, 5, 6]
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
x
TypeError: __repr__ returned non-string (type NoneType)
>>> print(x)
[4, 5, 6]
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
print(x)
TypeError: __str__ returned non-string (type NoneType)
usually I look straight to the objects and try to figure out what went wrong but I am a little confused as I am still new =(. Can someone help explain why it is returning a NoneType even after I have overwritten the init? (also, a possible solution on how I can rectify so no error would be extremely helpful)
Consider (note no explicit return at the end of __str__) :
>>> class Foo:
... def __str__(self):
... print('Foo!!')
...
>>> f=Foo()
>>> f
<__main__.Foo object at 0x10a655080>
>>> print(f)
Foo!!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __str__ returned non-string (type NoneType)
Vs:
>>> class Foo:
... def __str__(self):
... return 'Foo!!!'
...
>>> f=Foo()
>>> print(f)
Foo!!!
The issue is that __repr__ and __str__ need to return a return a string. The return from __repr__ should, if possible, be the 'official' string representation of the object for eval to recreate the object or some other <useful definition> according the the docs on __repr__
The docs on __str__ a more convenient or concise representation can be used' other than a Python expression.

Resources