I am trying to call a function from a class based on user input. I've tried other examples based on this but keep on getting various errors depending on which direction I try it.
The test code that I am using is
def one():
print('one hahah')
def two():
print('two hahah')
def the_count():
print('I am the count who likes to count')
dispatcher = {
'one': one, 'two': two, 'three': the_count
}
action = input('Option: - ')
jo.dispatcher[action]()
There we have what I want, but once I added the self argument things stopped working properly.
Here is my actual code...
import math
class femblem(object):
def j(self):
print('hi')
`data goes here`
...
def __init__(self,lv,name):
self.lv = lv
self.name = name
dispatcher = {
'j': j(self)
}
action = input('Character: - ')
unit1 = femblem(5,"joshua")
unit1.dispatcher[action]()
returns NameError: name 'self' is not defined
if I take out self it gives me an error saying that it needs that for an argument (which it does).
Not very experienced in python, any ideas why this isnt working?
Thanks
Essentially, your class will act like a dict here, and your instance is the dispatcher so just use getattr and the self magic will work:
>>> class Foo:
... def bar(self):
... return 42
... def baz(self):
... return 88
...
>>> foo = Foo()
>>> getattr(foo, 'bar')()
42
>>> getattr(foo, 'baz')()
88
>>>
There are several ways you could approach this problem, one of which would be to make dispatcher an instance method of the class:
class Foo(object):
def __init__(self,lv,name):
self.lv = lv
self.name = name
def one(self):
print('this is one!')
def dispatcher(self, action):
d = {'one':self.one}
return d[action]
Then you get something like:
>>> f = Foo(5, 'Joshua')
>>> action = input()
>>> f.dispatcher(action)()
'this is one!'
I can only guess what you are trying to do, but this snippet dispatches to the respective functions defined in your dispatcher for the user inputs one, two and three:
class femblem:
def __init__(self, lv, name):
self.lv = lv
self.name = name
def one(self):
print('one hahah')
def two(self):
print('two hahah')
def the_count(self):
print('I am the count who likes to count')
#property
def dispatcher(self):
return {
'one': self.one,
'two': self.two,
'three': self.the_count
}
action = input('Character: - ')
unit1 = femblem(5, "joshua")
unit1.dispatcher[action]()
An alternative answer with getattr inside the class:
class Foo:
def __init__(self):
pass
def bar(self):
print('this is foo')
def dispatcher(self):
att = input('put some input: ')
getattr(self, att)()
ob = Foo()
ob.dispatcher()
Related
I have class
class A:
def __init__(self):
print(i was used by :)
# if i call this class from the function below,
def my_func():
a = A()
# I need class A to print that "i was used in: my_func() "
Is there any solution for this ?
If you know the function name:
You could try something like:
class A:
def __init__(self, func):
print('i was used by:', func.__name__)
def my_func(func):
a = A(func)
my_func(my_func)
Output:
i was used by: my_func
This you would specify the function instance, which is the most optimal way here, then just use the __name__ to get the name of the function.
If you don't know the function name:
You could try the inspect module:
import inspect
class A:
def __init__(self):
print('i was used by:', inspect.currentframe().f_back.f_code.co_name)
def my_func():
a = A()
my_func()
Or try this:
import inspect
class A:
def __init__(self):
cur = inspect.currentframe()
a = inspect.getouterframes(cur, 2)[1][3]
print('i was used by:', a)
def my_func():
a = A()
my_func()
Both output:
i was used by: my_func
So in python, there's the getattr function to automate getting attributes of a particular class, fair enough.
What I am trying to do is create a class from a user input, similar to how I could loop through class attributes using getattr.
Here's the process that I am sort of thinking of:
# Define classes that the user could chose
class Person():
def __init__(self):
self.prop1 = 'hi'
# Define other classes
className = input() # The user would then type a class name like Person
newObj = className() # I would want this to evaluate like Person()
Basically, I'm trying to not make my code look like a bunch of
if className == "Person":
newObj = Person()
elif className == "Dog":
newObj = Dog()
Basically, is there any built in function where I can refer to a class through a string?
If both classes' __init__ take the same arguments, the simplest way is with a mapping dict. My example below involves a cheeky error handling, which you can avoid if you split the second line into several.
mapping_dict = {'Person': Person, 'Dog': Dog}
instance = mapping_dict.get(user_input, lambda: print('Invalid class name'))()
# instance is None if an invalid input was provided
Without the cheeky error handling:
mapping_dict = {'Person': Person, 'Dog': Dog}
class_obj = mapping_dict.get(user_input)
if class_obj:
instance = class_obj()
else:
print('Invalid class name')
You can use factory design pattern:
class CAR(object):
def __str__(self):
return "This is a car"
class BUS(object):
def __str__(self):
return "This is a bus"
class TRAIN(object):
def __str__(self):
return "This is a train"
def create_vehicle(vehicle_type):
target_class = vehicle_type.upper()
return globals()[target_class]()
vehicles = ['bus', 'car', 'train']
for v in vehicles:
print (create_vehicle(v))
Output would be :
This is a bus
This is a car
This is a train
There is another metaclass based solution, though, it might be overkill for this simple requirement.
_registry = {}
class MetaClass(type):
def __init__(cls, clsname, bases, methods):
super().__init__(clsname, bases, methods)
_registry[cls.__name__] = cls
class CAR(metaclass=MetaClass):
def __str__(self):
return "This is a car"
class BUS(metaclass=MetaClass):
def __str__(self):
return "This is a bus"
class TRAIN(metaclass=MetaClass):
def __str__(self):
return "This is a train"
def create_vehicle(vehicle_type):
target_class = vehicle_type.upper()
return _registry[target_class]()
vehicles = ['bus', 'car', 'train']
for v in vehicles:
print (create_vehicle(v))
A dynamic approach below
import sys, inspect
def get_classes():
return {name: obj for name, obj in inspect.getmembers(sys.modules[__name__]) if inspect.isclass(obj)}
class Person():
def __init__(self):
print('Person ..')
self.prop1 = 'hi 0'
class Student():
def __init__(self):
print('Student ..')
self.prop1 = 'hi 1'
classes_mapping = get_classes()
user_input = input('Type class name:')
clazz = classes_mapping.get(user_input)
if clazz:
obj = clazz()
else:
print(f'Unknown class {user_input}')
I want to do this:
a = TestClass1() <br>
a.test.fun() #==> this i want to call TestClass2 method fun() <br>
a.test(a=10).fun() #===> this i want to call TestClass3 method fun() <br>
Does anyone know how to separate this?
I have three classes:
class TestClass1:
aa = ""
def __init__(self):
self.aa = "ccc"
def __getattr__(self, item):
print("test 1 get attr = ",item)
return TestClass2() or TestClass3() #==> I don't how to seperate test and test(a =10)
def __getitem__(self, item):
print("__getitem__",item)
class TestClass2:
def __call__(self, *args, **kwargs):
print("TestClass2 __call__ ")
return self
def fun(self):
print("this TestClass2 fun()")
class TestClass3:
def __call__(self, *args, **kwargs):
print("TestClass3 33333 call 3 ")
return self
def fun(self):
print("this TestClass3 fun()")
in both examples given __getattr__ is called with argument "test".
you need to do something like this:
class TestClass1:
def __getattr__(self, item):
if item == 'test2':
return TestClass2()
elif item == 'test3':
return TestClass3()
a = TestClass1()
a.test2.fun()
a.test3.fun()
EDIT: Let me explain further. Well, in python there is no difference between a function and an attribute, everything in python is an object, all objects are treated the same, be it an integer or a function.
When you do a.test it is lowered to a.__getattr__('test').
And when you do a.test(a=10) it is lowered to a.__getattr__('test')(a=10).
The returned object from a.__getattr__('test') is the same.
In the second case you are fetching the attribute test then calling it with an argument a=10.
EDIT2: What you are trying to do could be achieved this way:
class TestClass1:
test = TestClass2()
class TestClass2:
def __call__(self, a):
if a == 10:
return TestClass3()
def fun():
print("this TestClass2 fun()")
a = TestClass1()
a.test # this is TestClass2
a.test.fun # this is TestClass2.fun
a.test(a=10) # this is TestClass3
a.test(a=10).fun # this is TestClass3.fun
EDIT3: A simpler approach would be making test a function:
class TestClass1:
def test(a=None):
if a is None:
return TestClass2()
if a == 10:
return TestClass3()
a = TestClass1()
a.test().fun # TestClass2.fun
a.test(a=10).fun # TestClass3.fun
I am wondering if the following strategy is a proper/pythonic way to create a dynamic function within a method. The goal is to have a class that can calculate a value based on a complex model defined by FUN(), but I want to be able to change that model within a script without rewriting it, or creating a bunch of different types of classes (since this function is the only thing that I expect to change).
I also read in a response to this question that the way I have it structured may end up being slower? I intend to call setupFunction() 1 to 3 times a simulation (changing the model) and call FUN many thousands of times.
Pseudocode...
class MyClass:
def __init__(self, model = 'A'):
self.setupFunction(model)
# Other Class Stuff...
def setupFunction(self, _model):
if _model == 'A':
def myFunc(x):
# Do something with x, store in result
return result
else:
def myFunc(x):
# Do something different with x
return result
self.FUN = myFunc
# Other Class Methods... some of which may call upon self.FUN
Model1 = MyClass('A')
Model2 = MyClass('B')
print(Model1.FUN(10))
print(Model2.FUN(10))
I have done some minor tests and the above seems to not break upon first glance. I know I could also do something similar by doing the following instead, but then it will have to test for the model on each call to FUN() and I will have many different model cases in the end:
class MyClass():
def __init__(self, model = 'A'):
def FUN(self, x):
if self.model == 'A':
# result = Stuff
else:
# result = Other Stuff
return result
Still new to python, so thanks for any feedback!
Not sure if I understood your question...
What about something like this?
class MyClass():
model_func = {'A' : funca, 'B' : funcb}
def __init__(self, model):
self.func = self.model_func[model]
def funca():
pass
def funcb():
pass
a = MyClass('A')
a.func()
b = MyClass('B')
b.func()
Other option might be something like this (better separation of concerns):
class Base(object):
def __new__(cls, category, *arguments, **keywords):
for subclass in Base.__subclasses__():
if subclass.category == category:
return super(cls, subclass).__new__(subclass, *arguments, **keywords)
raise Exception, 'Category not supported!'
class ChildA(Base):
category = 'A'
def __init__(self, *arguments, **keywords):
print 'Init for Category A', arguments, keywords
def func(self):
print 'func for Category A'
class ChildB(Base):
category = 'B'
def func(self):
print 'func for Category B'
if __name__ == '__main__':
a = Base('A')
a.func()
print type(a)
b = Base('B')
b.func()
print type(b)
You can use __new__, to return different subclasses:
class MyClass():
def __new__(self, model):
cls = {'A': ClassA, 'B': ClassB}[model]
return object.__new__(cls)
class ClassA(MyClass):
def func():
print("This is ClassA.func")
class ClassB(MyClass):
def func():
print("This is ClassB.func")
a = MyClass('A')
a.func()
b = MyClass('B')
b.func()
I have a class like this:
class MyClass(object):
def f_1(self,x):
return foo(x, self.property_1)
def f_2(self,x):
return foo(x, self.property_2)
The idea is that multiple functions f_n have a common structure, but depend on different properties property_n of the class.
I look for a more compact way to define those f_n in the __init__? I think of something like
class MyClass(object):
def __init__(self):
self.f_1 = self.construct_function(self.property_1)
self.f_2 = self.construct_function(self.property_2)
def construct_function(self, property):
# ???
That is what I have in mind, but I dont know how to define this construct_function. It is important that 'property' is of a point-by-value type.
Edit:
I simplified Martijn's very good answer to this solution, which works fine:
def construct_function(property_name):
def f_n(self, x):
return foo(x, getattr(self, property_name))
return f_n
class MyClass2(object):
f_1 = construct_function('property_1')
f_2 = construct_function('property_2')
Just wanted to mention it here, as multiline comments are not allowed...
If you want to generate these methods per class, use a class decorator:
def property_functions(**properties):
def construct_method(prop):
def f_n(self):
return foo(getattr(self, prop))
return f_n
def class_decorator(cls):
for name, prop in properties.iteritems():
setattr(cls, name, construct_method(prop))
return cls
return class_decorator
then use it like:
#property_functions(f_1='property_1', f_2='property_2')
class MyClass(object):
property_1 = 'foo'
property_2 = 'bar'
Demonstration:
>>> def foo(value): print value
...
>>> #property_functions(f_1='property_1', f_2='property_2')
... class MyClass(object):
... property_1 = 'foo'
... property_2 = 'bar'
...
>>> mc = MyClass()
>>> mc.f_1()
foo
>>> mc.f_2()
bar
You can have a look at getattr or getattribute . They allow you dynamically create and reference attributes. For ex
It works something like this:
class foo:
def __init__(self):
self.a = "a"
def __getattr__(self, attribute):
return "You asked for %s, but I'm giving you default" % attribute
>>> bar = foo()
>>> bar.a
'a'
>>> bar.b
"You asked for b, but I'm giving you default"
>>> getattr(bar, "a")
'a'
>>> getattr(bar, "b")
"You asked for b, but I'm giving you default"