Python dynamic function & parameters call - str object is not callable - python

I´m trying to come up with a dynamic function calling system. I have a database with a bunch of differents levels:
Decision Evaluator > Function (response curve) parameters > Inputs.
Choosing a Decision Evaluator may call 10 different functions but only 5 inputs, treated differently through the parameters. So it would be way easier to have a dynamic system rather than create all the sub-calls for each main level.
In the test below, I can dynamically call a lower-level function from an upper level ('test'). When I try to pass arguments, I get the error 'str' object is not callable. Here's the trace:
C:\ProgramData\Anaconda3\lib\site-packages\openpyxl\worksheet\_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed
warn(msg)
Traceback (most recent call last):
File "C:\Users\*\considerations.py", line 28, in <module>
ich.dynamic_call(abcd_3(show_test))
TypeError: 'str' object is not callable
init ICH...
oouh weee look at me
Process finished with exit code 1
considerations.py:
from input_clearing_house import InputClearingHouse
import pandas as pd
inputs = pd.read_excel(r'AXIS_DB.xlsx', sheet_name='Inputs')
considerations = pd.read_excel(r'AXIS_DB.xlsx', sheet_name='Considerations')
decision_score_evaluator = pd.read_excel(r'AXIS_DB.xlsx', sheet_name='DecisionScoreEvaluator')
decision_maker = pd.read_excel(r'AXIS_DB.xlsx', sheet_name='DecisionMaker')
considerations = pd.merge(considerations, inputs, on='input_name')
# print(considerations)
ich = InputClearingHouse()
abcd_2 = 'test'
abcd_3 = 'multi21'
show_test = 'dynamite'
ich.dynamic_call(abcd_2)
ich.dynamic_call(abcd_3(show_test))
input_clearing_house.py:
import math
class InputClearingHouse:
def __init__(self):
print('init ICH...')
def dynamic_call(self, name, *args, **kwargs):
call_fct = f'{name}'
if hasattr(self, call_fct) and callable(func := getattr(self, call_fct)):
func(*args, **kwargs)
def test(self):
print("oouh weee look at me")
def multi21(self, *args):
for arg in args:
print(arg)
def distance_to_target(self, source: tuple, target: tuple) -> float:
return math.sqrt((source[0] - target[0]) ** 2 + (source[1] - target[1]) ** 2)
def my_endurance(self, current: int, maximum: int) -> float:
return current / maximum

abcd_3(show_test) is trying to use abcd_3 as a function, but it's a string that names a function.
ich.dynamic_call() expects the name and arguments of the function to call to be separate arguments, so you should use
ich.dynamic_call(abcd_3, show_test)

Your dynamic_call() method already copes with variable numbers of arguments.
I think you just meant to add arguments:
ich.dynamic_call(abcd_3, show_test)

Related

TypeError: read_csv() takes from 0 to 1 positional arguments but 2 were given

What am I missing here? I have tried looking at the code but I do not know where the extra positional argument is located at,
def read_csv(path: str = None) -> List[List] :
lead = Path(__file__).parent / f'../data/{path}'
entries = []
print('Reading dataset...')
with open(lead, 'r') as csvfile:
video_reader = csv.reader(csvfile)
for row in video_reader:
entries.append(row)
return print(entries)
Traceback (most recent call last):
File "C:/Users/MEDIAMARKT/Desktop/booking/__main__.py", line 15, in <module>
gui = GUI()
File "C:\Users\MEDIAMARKT\Desktop\booking\gui.py", line 22, in init
self.upload_data()
File "C:\Users\MEDIAMARKT\Desktop\booking\gui.py", line 84, in upload_data
self.booking.read_csv(path)
TypeError: read_csv() takes from 0 to 1 positional arguments but 2 were given
Your error is elsewhere, not in the snippet provided, since as a standalone function, that code should work fine.
Looking at your traceback, you've introduced classes, so reading your error
2 were given
When you call a class function, the instance of that class is always supplied as a parameter
example
class Foo:
def bar(self, other=None): # self is a required argument for instance methods
pass
xyz = 'something'
booking = Foo()
booking.bar() # 1 parameter provided - the instance itself
booking.bar(xyz) # 2 parameters provided - the instance and the string
So, to fix your function, you need to add the self parameter, even if you don't plan on using it.
Before, the path variable you used wasn't actually a string, so the type checker should have been throwing an error as well
class Booking():
def read_csv(self, path:str = None) -> List[List]:
# TODO
return []

Python Troubles (Missing 1 required positional argument: 'self')

i'm trying to solve the adventofcode riddles, but this year i decided to take the chance to learn a new programming language: Python.
Since i already have some knowledge about other OOP languages like Java and C++, i immediately created an "interface" system for the Solutions objects.
My project setup at the moment is like:
Project Setup
Now what i want is to dynamically output solutions through the main class, that basically has to call all .solve() method of each dayX.py class that is in the /solutions/ directory.
I think i'm next to do it but i get an error:
Traceback (most recent call last):
File "C:\Users\siste\j-workspace\adventofcode2020\main.py", line 16, in <module>
print(solution.solve())
TypeError: solve() missing 1 required positional argument: 'self'
Here are my files:
main.py
import os
def days():
classes = []
path = "C:\\path"
for file in os.listdir(path):
if(file.startswith("day")) :
classes.append(str(file.replace(".py", "")))
return classes
if __name__ == '__main__':
for day in days() :
solution = getattr(__import__(str("solutions." + day)), day.replace("d", "D"))
print(solution.solve())
solution.py
path = "C:\\path\\inputs\\day{}.txt"
class Solution:
def __init__(self, dayNumber):
self.dayNumber = dayNumber
self.inputPath = path.format(self.dayNumber)
def part1(self):
pass
def part2(self):
pass
def solve(self):
return ("Day {} Solutions: \n\tPart1: {}\n\tPart2: {}"
.format(self.dayNumber, self.part1(), self.part2()))
day1.py
import fileinput
from solutions.solution import Solution
class Day1(Solution):
def __init__(self):
super().__init__(1)
def part1(self):
return "sol"
def part2(self):
return "sol2"
When you're using the getattr on the imported module, you're getting the class definition. Methods are only callable on class instances, otherwise they throw the error you're seeing:
class A:
def a(self):
pass
A.a() // Will throw "TypeError: a() missing 1 required positional argument: 'self'"
A().a() // OK
Changing the __main__ part this way should solve the issue:
if __name__ == '__main__':
for day in days() :
day_class = getattr(__import__(str("solutions." + day)), day.replace("d", "D"))
day_instance = day_class()
print(day_instance.solve())

Missing 2 required positional arguments - Classmethod Python

Sorry, I'm struggling at this for quite some time. I'm trying to use function totalPayments which uses the monthlyPayment class function with parameters pass through in the initialisation phase. I'm getting an error missing 2 required positional arguments
class Loan(object):
def __init__(self, asset, face, rate , term):
self._asset = asset
self._face = face
self._rate = rate
self._term = term
#classmethod
def monthlyPayment(cls,face,rate,term,period=None):
return ((rate*face*((1+rate)**term)))/(((1+rate)**term)-1)
def totalPayments(self):
return (self.monthlyPayment(self) * self._term)
l = Loan(None,1000,0.025,10)
print(l.totalPayments()) # gets an error missing 2 required positional arguments
edit:
Thank you very much for the hekp and I should be amending my def monthlyPayment function to take in the arguments
You are calling monthlyPayment from the instance (self), and you're not providing arguments for face, rate, and term.
It also shouldn't be a classmethod, since you use attributes of the instance:
class Loan(object):
def __init__(self, asset, face, rate , term):
self._asset = asset
self._face = face
self._rate = rate
self._term = term
def monthlyPayment(self, period=None):
return ((self._rate*self._face*((1+self._rate)**self._term)))/(((1+self._rate)**self._term)-1)
def totalPayments(self):
return (self.monthlyPayment() * self._term)
The stack error you get is:
Traceback (most recent call last):
File "C:/Users/cd00119621/PycharmProjects/ideas/stackoverflow.py", line 16, in <module>
print(l.totalPayments())
File "C:/Users/cd00119621/PycharmProjects/ideas/stackoverflow.py", line 13, in totalPayments
return (self.monthlyPayment(self) * self._term)
TypeError: monthlyPayment() missing 2 required positional arguments: 'rate' and 'term'
The clue here is that its the monthlyPayment() method thats giving the error missing 2 args. this method expects 3 args passed to it (excluding self) and the 4th is optional.
def monthlyPayment(cls,face,rate,term,period=None):
but when you call this from your totalPayments method you only pass one argument which is self.
return (self.monthlyPayment(self) * self._term)
you dont need to pass self, it will be passed automatically, so you need to pass the other 3 expected params face,rate,term

Subclassing builtin types -- Python 2 and 3

I have code that looks like the following:
class Token(object):
'''
Resulting from parse
'''
def __new__(cls,text,begin,end,*args,**kargs):
self = super(Token,cls).__new__(cls,*args,**kargs)
return self
def __init__(self,text,begin,end,*args,**kargs):
super(Token,self).__init__(*args,**kargs)
self.text = text
self.begin = begin
self.end = end
class List(Token,list):
pass
class Str(Token,str):
pass
class Int(Token,int):
pass
s = Str('hey there',0,3,'hey there'[0:3])
print(s)
x = Int('55 12',0,2,'55 12'[0:2])
print(x)
Basically what I want to do is to easily create types that are just normal Python types, but with some extra information to them.
Python 2 seems to be OK with the above code, but Python 3 complains
Traceback (most recent call last):
File "simple.py", line 71, in <module>
s = Str('',1,2,'hey')
File "simple.py", line 12, in __init__
super(Token,self).__init__(*args,**kargs)
TypeError: object.__init__() takes no parameters
I think the interpreters would be happy if I did something like
class List(list):
def __init__(self,text,begin,end,*args,**kargs):
list.__init__(*args,**kargs)
But this would mean I would have to repeat something similar for every new class I want to make... and I would rather stay relatively DRY...
Is there a 'proper' way I should handle this situation so that both Python 2 and Python 3 are happy?
Your best bet is to use exception handling here:
def __init__(self,text,begin,end,*args,**kargs):
try:
super(Token,self).__init__(*args,**kargs)
except TypeError:
# Python 3 and the mixed in type is immutable.
# Ignoring this is fine, `__new__` took care of this.
pass
self.text = text
self.begin = begin
self.end = end

not enough arguments passed to __init__()

What is the error below? Also, is there a better way to implement the following classes?
#!/usr/bin/python
class Datacenters:
def __init__(self,name,location,cpu,mem):
self.name=name
self.location=location
self.cpu=cpu
self.mem=mem
def getparam(self):
return self.name,self.location ,self.cpu,self.mem
def getname(self):
return self.name
class WS(Datacenters):
def __init__(self,name,location,cpu,mem,obj):
#datacentername = Datacenters.__init__(self) #To which data center it is associated
self.dcname =obj.name #To which data center it is associated
Datacenters.__init__(obj,name,location,cpu,mem)
def getparam(self,obj):
self.name,self.location ,self.cpu,self.mem = obj.getparam()
print self.dcname
#return self.name,self.location ,self.cpu,self.mem,obj.name
def getwsname(self):
return self.name
class Pcs(WS):
def __init__(self,name,location,cpu,mem,obj):
self.wsname = obj.getwsname() #To which WS it is associated
WS.__init__(obj,name,location,cpu,mem)
def getparam(self,obj):
print obj.getparam()
print self.wsname
a = Datacenters("dc1","Bl1",20,30)
print a.getparam()
b = WS("WS1","Bl1",21,31,a)
print b.getparam(a)
c = Pcs("PC1","Bl1",20,30,b)
#print c.getparam(b)
output:
Press ENTER or type command to continue
('dc1', 'Bl1', 20, 30)
dc1
None
Traceback (most recent call last):
File "class1.py", line 45, in <module>
c = Pcs("PC1","Bl1",20,30,b)
File "class1.py", line 34, in __init__
WS.__init__(obj,name,location,cpu,mem)
TypeError: __init__() takes exactly 6 arguments (5 given)
The error is that you pass in five arguments, but the __init__ needs six. Count them:
def __init__(self,name,location,cpu,mem,obj):
Six arguments. You call it like so:
WS.__init__(obj,name,location,cpu,mem)
Five arguments. The first one, self is missing. What you should ask yourself is why you don't have to pass in six arguments all the time.
And that is because self is passed in automatically when you call the method on an instance. However, in this case you don't call it on an instance, you call it directly on the class. There is of course no need to do so in this case, the correct syntax is:
WS(obj,name,location,cpu,mem)
As you indeed above note works further up.

Categories