Is there a way to call specific classes based on a variable? - python

I want a program to call a specific class based on a parameter/variable value. However, I don't want to use any clunky if-statements. My first thought was to use the globals() function, but I couldn't get it to work. Here's an example:
class SomeClass:
def __init__():
print("Hello, world!")
class OtherClass:
def runClass(className):
# Call class based on variable className
The reason I want to do this is because there is a wide variety of classes may need to be called, and so just piling up if-statements in my code won't do it. Any help would be greatly appreciated. Thanks!

Here's how you can call a class via globals
class SomeClass:
def __init__(self):
print("Hello, world!")
def __call__(self):
return "SomeClass called"
class OtherClass:
def runClass(self, className):
globals()[className]()()
o = OtherClass()
result = o.runClass("SomeClass")
print(result)
Notice, I am instantiating and then calling it via the __call__ special method, which is the closest match to your description I could think of.

Use a dict.
name_to_class = dict(some=SomeClass,
other=OtherClass)
def factory(name):
klass = name_to_class(name)
return klass()
some_obj = factory("some")
other_obj = factory("other")

One way to solve this problem is to use a dictionary to map the values of the variable className to the corresponding class.
Try this exemple :
class SomeClass:
def init(self):
print("Hello, world!")
class OtherClass:
def init(self):
print("Goodbye, world!")
classNameToClass = {
"SomeClass": SomeClass,
"OtherClass": OtherClass
}
def runClass(className):
# Call class based on variable className
cls = classNameToClass[className]
return cls()
runClass("SomeClass") # prints "Hello, world!"
runClass("OtherClass") # prints "Goodbye, world!"
Here, the dictionary classNameToClass maps the string names of the classes (e.g. "SomeClass") to the corresponding class objects (e.g. SomeClass). Then, in the runClass function, we look up the class object using the value of the className variable, and call it to create an instance of the class.

I've found an answer. The parameter that governs the called class can just be assigned elsewhere. At first, I thought it would need some complex function, but in reality, I guess the question didn't give enough details. The class itself only uses items from whatever object is given. So, instead of having to dynamically call a class, it's as simple as:
class SomeClass:
def printHelloWorld():
print("Hello, world!")
class OtherClass:
def __init__(self, usingClass):
self.object = usingClass
def doThis():
usingClass.printHelloWorld()
x = OtherClass(SomeClass())
x.doThis()
It's on me for not giving enough information. Thank you all for your help.

Related

Instantiating and Using a Method of a Class Within a Function

I'm trying to instantiate a class within a function, then call a method within the class inside the same function, like this:
# Define the class
class myclass:
def __init__(self,string_to_print):
self.string_to_print = string_to_print
def myclass_func(self):
print(self.string_to_print)
# Define the function that utilizes the class
def func(class,func,str)
instance = class(str)
class = class.func()
# Run the function that utilizes the class
func(myclass,myclass_func,str)
But I am getting an error like "'myclass' object is not callable". Why is this? Additionally, I expect my 'class = class.func()' line is wrong; if it is, what is the correct way to call the method from the recently instantiated class?
Edit: fixed mistake in class declaration
You can't use method names as global variables. If you want to call a method dynamically, pass its name as a string and use the getattr() function.
# Define the class
class myclass:
def __init__(self,string_to_print):
self.string_to_print = string_to_print
def myclass_func(self):
print(self.string_to_print)
# Define the function that utilizes the class
def func(class,func,str)
instance = class(str)
return getattr(instance, func)()
# Run the function that utilizes the class
func(myclass,'myclass_func',str)
Define your class using the class keyword rather than def.
Create an instance of the class.
Define a function that will try to execute the function given by its name.
class myclass:
def __init__(self,string_to_print):
self.string_to_print = string_to_print
def myclass_func(self):
print(self.string_to_print)
myclass_instance = myclass('Hello world')
def execute_function(instance, function):
getattr(instance, function)()
execute_function(myclass_instance, 'myclass_func')
Output:
Hello world

How to execute BaseClass method before it gets overridden by DerivedClass method in Python

I am almost sure that there is a proper term for what I want to do but since I'm not familiar with it, I will try to describe the whole idea explicitly. So what I have is a collection of classes that all inherit from one base class. All the classes consist almost entirely of different methods that are relevant within each class only. However, there are several methods that share similar name, general functionality and also some logic but their implementation is still mostly different. So what I want to know is whether it's possible to create a method in a base class that will execute some logic that is similar to all the methods but still continue the execution in the class specific method. Hopefully that makes sense but I will try to give a basic example of what I want.
So consider a base class that looks something like that:
class App(object):
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
def access(self):
LOGIC_SHARED
And an example of a derived class:
class App1(App):
def __init__(self, testName):
. . .
super(App1, self).__init__(testName)
def access(self):
LOGIC_SPECIFIC
So what I'd like to achieve is that the LOGIC_SHARED part in base class access method to be executed when calling the access method of any App class before executing the LOGIC_SPECIFIC part which is(as it says) specific for each access method of all derived classes.
If that makes any difference, the LOGIC_SHARED mostly consists of logging and maintenance tasks.
Hope that is clear enough and the idea makes sense.
NOTE 1:
There are class specific parameters which are being used in the LOGIC_SHARED section.
NOTE 2:
It is important to implement that behavior using only Python built-in functions and modules.
NOTE 3:
The LOGIC_SHARED part looks something like that:
try:
self.localLog.info("Checking the actual link for %s", self.application)
self.link = self.checkLink(self.application)
self.localLog.info("Actual link found!: %s", self.link)
except:
self.localLog.info("No links found. Going to use the default link: %s", self.link)
So, there are plenty of specific class instance attributes that I use and I'm not sure how to use these attributes from the base class.
Sure, just put the specific logic in its own "private" function, which can overridden by the derived classes, and leave access in the Base.
class Base(object):
def access(self):
# Shared logic 1
self._specific_logic()
# Shared logic 2
def _specific_logic(self):
# Nothing special to do in the base class
pass
# Or you could even raise an exception
raise Exception('Called access on Base class instance')
class DerivedA(Base):
# overrides Base implementation
def _specific_logic(self):
# DerivedA specific logic
class DerivedB(Base):
# overrides Base implementation
def _specific_logic(self):
# DerivedB specific logic
def test():
x = Base()
x.access() # Shared logic 1
# Shared logic 2
a = DerivedA()
a.access() # Shared logic 1
# Derived A specific logic
# Shared logic 2
b = DerivedB()
b.access() # Shared logic 1
# Derived B specific logic
# Shared logic 2
The easiest method to do what you want is to simply call the parent's class access method inside the child's access method.
class App(object):
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
def access(self):
LOGIC_SHARED
class App1(App):
def __init__(self, testName):
super(App1, self).__init__(testName)
def access(self):
App.access(self)
# or use super
super(App1, self).access()
However, your shared functionality is mostly logging and maintenance. Unless there is a pressing reason to put this inside the parent class, you may want to consider is to refactor the shared functionality into a decorator function. This is particularly useful if you want to reuse similar logging and maintenance functionality for a range of methods inside your class.
You can read more about function decorators here: http://www.artima.com/weblogs/viewpost.jsp?thread=240808, or here on Stack Overflow: How to make a chain of function decorators?.
def decorated(method):
def decorated_method(self, *args, **kwargs):
LOGIC_SHARED
method(self, *args, **kwargs)
return decorated_method
Remember than in python, functions are first class objects. That means that you can take a function and pass it as a parameter to another function. A decorator function make use of this. The decorator function takes another function as a parameter (here called method) and then creates a new function (here called decorated_method) that takes the place of the original function.
Your App1 class then would look like this:
class App1(App):
#logged
def access(self):
LOGIC_SPECIFIC
This really is shorthand for this:
class App1(App):
def access(self):
LOGIC_SPECIFIC
decorated_access = logged(App.access)
App.access = decorated_access
I would find this more elegant than adding methods to the superclass to capture shared functionality.
If I understand well this commment (How to execute BaseClass method before it gets overridden by DerivedClass method in Python) you want that additional arguments passed to the parent class used in derived class
based on Jonathon Reinhart's answer
it's how you could do
class Base(object):
def access(self,
param1 ,param2, #first common parameters
*args, #second positional parameters
**kwargs #third keyword arguments
):
# Shared logic 1
self._specific_logic(param1, param2, *args, **kwargs)
# Shared logic 2
def _specific_logic(self, param1, param2, *args, **kwargs):
# Nothing special to do in the base class
pass
# Or you could even raise an exception
raise Exception('Called access on Base class instance')
class DerivedA(Base):
# overrides Base implementation
def _specific_logic(self, param1, param2, param3):
# DerivedA specific logic
class DerivedB(Base):
# overrides Base implementation
def _specific_logic(self, param1, param2, param4):
# DerivedB specific logic
def test():
x = Base()
a = DerivedA()
a.access("param1", "param2", "param3") # Shared logic 1
# Derived A specific logic
# Shared logic 2
b = DerivedB()
b.access("param1", "param2", param4="param4") # Shared logic 1
# Derived B specific logic
# Shared logic 2
I personally prefer Jonathon Reinhart's answer, but seeing as you seem to want more options, here's two more. I would probably never use the metaclass one, as cool as it is, but I might consider the second one with decorators.
With Metaclasses
This method uses a metaclass for the base class that will force the base class's access method to be called first, without having a separate private function, and without having to explicitly call super or anything like that. End result: no extra work/code goes into inheriting classes.
Plus, it works like maaaagiiiiic </spongebob>
Below is the code that will do this. Here http://dbgr.cc/W you can step through the code live and see how it works :
#!/usr/bin/env python
class ForceBaseClassFirst(type):
def __new__(cls, name, bases, attrs):
"""
"""
print("Creating class '%s'" % name)
def wrap_function(fn_name, base_fn, other_fn):
def new_fn(*args, **kwargs):
print("calling base '%s' function" % fn_name)
base_fn(*args, **kwargs)
print("calling other '%s' function" % fn_name)
other_fn(*args, **kwargs)
new_fn.__name__ = "wrapped_%s" % fn_name
return new_fn
if name != "BaseClass":
print("setting attrs['access'] to wrapped function")
attrs["access"] = wrap_function(
"access",
getattr(bases[0], "access", lambda: None),
attrs.setdefault("access", lambda: None)
)
return type.__new__(cls, name, bases, attrs)
class BaseClass(object):
__metaclass__ = ForceBaseClassFirst
def access(self):
print("in BaseClass access function")
class OtherClass(BaseClass):
def access(self):
print("in OtherClass access function")
print("OtherClass attributes:")
for k,v in OtherClass.__dict__.iteritems():
print("%15s: %r" % (k, v))
o = OtherClass()
print("Calling access on OtherClass instance")
print("-------------------------------------")
o.access()
This uses a metaclass to replace OtherClass's access function with a function that wraps a call to BaseClass's access function and a call to OtherClass's access function. See the best explanation of metaclasses here https://stackoverflow.com/a/6581949.
Stepping through the code should really help you understand the order of things.
With Decorators
This functionality could also easily be put into a decorator, as shown below. Again, a steppable/debuggable/runnable version of the code below can be found here http://dbgr.cc/0
#!/usr/bin/env python
def superfy(some_func):
def wrapped(self, *args, **kwargs):
# NOTE might need to be changed when dealing with
# multiple inheritance
base_fn = getattr(self.__class__.__bases__[0], some_func.__name__, lambda *args, **kwargs: None)
# bind the parent class' function and call it
base_fn.__get__(self, self.__class__)(*args, **kwargs)
# call the child class' function
some_func(self, *args, **kwargs)
wrapped.__name__ = "superfy(%s)" % some_func.__name__
return wrapped
class BaseClass(object):
def access(self):
print("in BaseClass access function")
class OtherClass(BaseClass):
#superfy
def access(self):
print("in OtherClass access function")
print("OtherClass attributes")
print("----------------------")
for k,v in OtherClass.__dict__.iteritems():
print("%15s: %r" % (k, v))
print("")
o = OtherClass()
print("Calling access on OtherClass instance")
print("-------------------------------------")
o.access()
The decorator above retrieves the BaseClass' function of the same name, and calls that first before calling the OtherClass' function.
May this simple approach can help.
class App:
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
self.application = None
self.link = None
def access(self):
print('There is something BaseClass must do')
print('The application is ', self.application)
print('The link is ', self.link)
class App1(App):
def __init__(self, testName):
# ...
super(App1, self).__init__(testName)
def access(self):
self.application = 'Application created by App1'
self.link = 'Link created by App1'
super(App1, self).access()
print('There is something App1 must do')
class App2(App):
def __init__(self, testName):
# ...
super(App2, self).__init__(testName)
def access(self):
self.application = 'Application created by App2'
self.link = 'Link created by App2'
super(App2, self).access()
print('There is something App2 must do')
and the test result:
>>>
>>> app = App('Baseclass')
>>> app.access()
There is something BaseClass must do
The application is None
The link is None
>>> app1 = App1('App1 test')
>>> app1.access()
There is something BaseClass must do
The application is Application created by App1
The link is Link created by App1
There is something App1 must do
>>> app2 = App2('App2 text')
>>> app2.access()
There is something BaseClass must do
The application is Application created by App2
The link is Link created by App2
There is something App2 must do
>>>
Adding a combine function we can combine two functions and execute them one after other as bellow
def combine(*fun):
def new(*s):
for i in fun:
i(*s)
return new
class base():
def x(self,i):
print 'i',i
class derived(base):
def x(self,i):
print 'i*i',i*i
x=combine(base.x,x)
new_obj=derived():
new_obj.x(3)
Output Bellow
i 3
i*i 9
it need not be single level hierarchy it can have any number of levels or nested

Is it best-practice to place __init__ in the beginning or end of a class?

Consider the following code:
class AClass():
def defaultMethod(self):
return 1
def __init__(self, methodToUse = defaultMethod):
print (methodToUse(self))
if __name__== "__main__":
AClass()
In this case one cannot move the defaultMethod below the __init__ method, if I do, it causes "NameError: name 'defaultMethod' is not defined"
This means that I need to define this method before the __init__ or else Python does not know about it. This again, means that I no longer have __init__ as the first method, which leaves me to wonder whether it is usual to place the __init__ method at the end of a class or in the beginning.
What do you mean, "I need to define this method before the init or else Python does not know about it" ?
>>> class A(object):
... def __init__(self):
... self.foo()
... def foo(self):
... print '42'
...
>>> A()
42
I usually place __ init__() before other instance methods, but after class methods/property/attributes.
I think you're doing things a little peculiarly. You should still put __init__ high up if not the first method. Readability is key and __init__ exposes what you expect the main instance fields to be.
Here are three alternatives. My preference is for the first as it documents the default method and will require the least modification to your code. The last works, but could be confusing for anyone having to maintain your code.
class A(object):
def __init__(self, method="foo"):
if callable(method):
method(self)
else:
getattr(self, method)()
def foo(self):
print "something"
class B(object):
def __init__(self, method = None):
if method is None:
self.defaultMethod()
else:
method(self)
def defaultMethod(self):
print "foo"
def _defaultMethod(self):
print self.x
class C(object):
def __init__(self, method = _defaultMethod):
self.x = "bleh"
method(self)
def anotherMethod(self):
print "doing something else"
def defaultMethodProxy(self):
_defaultMethod(self)
__init__ is most commonly placed at the beginning of a class since they are the first thing run when the class is instantiated. Since your situation requires it to exist further down in the class, it would be nice to other devs to leave a note in the comments for the class.
I prefer init at the beginning and I would actually not write the class that way, but rather something like this:
class AClass():
def __init__(self, methodToUse = 'defaultMethod'):
print getattr(self, methodToUse)()
def defaultMethod(self):
return 1
if __name__== "__main__":
AClass()
The problem is that at compile time (when the default arguments are created), there is no function defaultMethod, but if you use it inside __init__, then the method is there.

Accessing a decorator in a parent class from the child in Python

how does one go about accessing a decorator from a base class in a child?
I assumed (wrongly) that the ffg. would work:
class baseclass(object):
def __init__(self):
print 'hey this is the base'
def _deco(func):
def wrapper(*arg):
res = func(*arg)
print 'I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling'
return res
return wrapper
#_deco
def basefunc(self):
print 'I\'m a base function'
This class works fine, but then I create a child class inheriting from this:
class otherclass(baseclass):
def __init__(self):
super(otherclass, self).__init__()
print 'other class'
#_deco
def meh(self):
print 'I\'m a function'
This won't even import properly, let alone run. #_deco is undefined. Trying baseclass._deco throws an unbound method _deco() error, which isn't really surprising.
Any idea how to do this, I'd really like to encapsulate the decorator in the class, but I'm not married to the idea and I'd need to call it in the base & the child class.
class baseclass(object):
def __init__(self):
print 'hey this is the base'
def _deco(func):
def wrapper(*arg):
res = func(*arg)
print 'I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling'
return res
return wrapper
#_deco
def basefunc(self):
print 'I\'m a base function'
#_deco
def basefunc2(self):
print "I'm another base function"
#no more uses of _deco in this class
_deco = staticmethod(_deco)
# this is the key. it must be executed after all of the uses of _deco in
# the base class. this way _deco is some sort weird internal function that
# can be called from within the class namespace while said namespace is being
# created and a proper static method for subclasses or external callers.
class otherclass(baseclass):
def __init__(self):
super(otherclass, self).__init__()
print 'other class'
#baseclass._deco
def meh(self):
print 'I\'m a function'
There is also python3-specific way to use that decorator in child class without mentioning parent, exactly as OP suggested. It requires decorator to be implemented in parent's metaclass (nice explanation of metaclases can be found here), using its __prepare__() method.
aaronasterling's answer is valid and preferred way how to solve that, I am posting this only as an interesting example to help others understand the basics of language. Use metaclasses only when there is no other way to achive what you need!
class metaclass(type):
#classmethod
def __prepare__(metacls, name, bases):
def _deco(func):
def wrapper(*arg):
res = func(*arg)
print('I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling')
return res
return wrapper
return {"_deco": _deco}
class baseclass(metaclass=metaclass):
def __init__(self):
print('hey this is the base')
#_deco
def basefunc(self):
print('I\'m a base function')
class otherclass(baseclass):
def __init__(self):
super(otherclass, self).__init__()
print('other class')
#_deco
def meh(self):
print('I\'m a function')
The sample code works well in python3:
>>> obj = otherclass()
hey this is the base
other class
>>> obj.meh()
I'm a function
I'm a decorator. This is fabulous, but that colour, so last season sweetiedarling
Important notes about __prepare__() method:
If present, it runs before the object body is executed
Its return value is used as local namespace for the class body at the begining of its evaluation (this way, decorator can be availabe from child's body without using parent's namespace)
It should be implemented as classmethod() and should return mapping object (i.e. dict)
If not present, empty mapping is used as initial local namespace.

How to access the parent class during initialisation in python?

How do I find out which class I am initialising a decorator in? It makes sense that I wouldn't be able to find this out as the decorator is not yet bound to the class, but is there a way of getting round this?
class A(object):
def dec(f):
# I am in class 'A'
def func(cls):
f(cls)
return func
#dec
def test(self):
pass
I need to know which class I am (indicated by the commented line).
I don't think this is possible. At the very moment when you define test, the class doesn't exist yet.
When Python encounters
class A(object):
it creates a new namespace in which it runs all code that it finds in the class definition (including the definition of test() and the call to the decorator), and when it's done, it creates a new class object and puts everything into this class that was left in the namespace after the code was executed.
So when the decorator is called, it doesn't know anything yet. At this moment, test is just a function.
I don't get the question.
>>> class A(object):
def dec(f):
def func(cls):
print cls
return func
#dec
def test(self):
pass
>>> a=A()
>>> a.test()
<__main__.A object at 0x00C56330>
>>>
The argument (cls) is the class, A.
As Nadia pointed out you will need to be more specific. Python does not allow this kind of things, which means that what you are trying to do is probably something wrong.
In the meantime, here is my contribution: a little story about a sailor and a frog. (use a constructor after the class initialization)
class Cruise(object):
def arewelostyet(self):
print 'Young sailor: I think I am lost, help me :s'
instance = Cruise()
instance.arewelostyet()
def whereami(lostfunc):
"""
decorator
"""
def decorated(*args, **kwargs):
lostfunc(*args, **kwargs)
print 'Frog: Crôak! thou art sailing in class', lostfunc.im_class.__name__
# don't forget to write name and doc
decorated.func_name = lostfunc.func_name
decorated.func_doc = lostfunc.func_name
return decorated
print '[i]A frog pops out of nowhere[/i]'
# decorate the method:
Cruise.arewelostyet = whereami(Cruise.arewelostyet)
instance.arewelostyet()

Categories

Resources