Call function of class using a variable function call - python

I'm trying to call a function from a Class thats name will change depending on what type of enemy is being instantiated. How can I accomplish this?
My attempt was this: AssignClass.[self.Class](self)
but obviously that sintax makes no sense
class Creature:
def __init__(self, Name, Class):
self.Name = Name
self.Class = Class
# Using a variable function call to remove
# the need for a ton of 'if' statements
AssignClass.[self.Class](self)
# Basically automate doing this:
if self.Class = "Orc":
AssignClass.Orc(self)
elif self.Class = "Wizard"
AssignClass.Wizard(self)
class AssignClass:
def Orc(Creature):
Creature.Class='Orc'
Creature.Health=100
Creature.Mana=0
def Wizard(Creature):
Creature.Class='Wizard'
Creature.Health=75
Creature.Mana=200
Evil_Wizard = Creature("Evil Wizard", "Wizard")

You can retrieve class methods using getattr() and then just pass your Creature instance, e.g.:
class Creature:
def __init__(self, Name, Class):
self.Name = Name
self.Class = Class
getattr(AssignClass, Class)(self)
Btw. this is everything but a recommended style for Python classes, the least of which is that you're shadowing the Creature class in your AssignClass (which shouldn't be a class in the first place). I'd recommend you to read the PEP 8 -- Style Guide for Python Code thoroughly.

Played around a little more and found that I can use eval for this. (Safe as no user input can be added here)
class Creature:
def __init__(self, Name, Class):
self.Name = Name
self.Class = Class
eval('AssignClass.'+Class)(self)

Related

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

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.

Syntax confusion with class

This is the given code:
class Person:
def __init__(self, name):
self.name = name
def greeting(self):
return "hi, my name is " + self.name
some_person = Person("yeabsira")
print(some_person.greeting())
However, I was expecting the syntax in which the constructor method uses like:
class Name:
def __init__(self,atribute1,atribute2):
self.atribute1=atribute1
self.atribute2=atribute2
new_instance=Name("example")
print(new_instance.atribute1)
expect answer="example"
So my question is how "some_person.greeting()" symantic works?
some_person.name returns the value of the person's name, while some_person.greeting() returns a greeting with the name, it is just a function defined within the class Person and works normally like any other function. You could use some_person.name if you only need the name.
However, by using some_person.greeting(), you implemented data hiding, which hides internal object details, and the user (in the future) only needs to access greeting() and not the value of name itself.

Python OOP: Are all self."something" attributes in __init__ available to other class methods?

Simple, silly question.
But say I had
class Stuff:
def __init__(self, name):
self.name = name:
def get_name(self):
print(name)
new_name = Stuff(name = "Richard")
new_name.get_name()
Would this work? Would get_name be able to access the name attribute and print it out?
I can't get this code to work...
There are a few things that you need to change but this works:
class Stuff:
def __init__(self, name):
self.name = name
def get_name(self):
print(self.name)
new_name = Stuff(name = "Richard")
new_name.get_name()
Besides a few syntax errors (class needs to be lowercase and some missing :) the main thing you were missing was accessing name by means of the self identifier. Since name is defined on the class you need to access it via self.

How remove a variable that appears in __init__?

If i have this:
class One(object):
def __init__(self, name):
self.name = name
I want to use One but altering the name name and relace it by other
The solution I supposed is inheriting:
class Two(One):
def __init__(self, other):
super(Two, self).__init__(other)
The idea is : How to delete or change the variable names that appears in __init__ ?
There is no relation at all between the name of the parameter passed to __init__ and the name of the instance variable that might eventuality be initialized by that argument. This is only a matter of convention than both are called the same.
Both code fragments below will perform exactly the same:
class One(object):
def __init__(self, name):
self.name = name
class One(object):
def __init__(self, xyz):
self.name = xyz
As about renaming an instance variable, you might do something like that, but this is (very) bad style and has (great) chances to break something in (the base class and/or in any client code that expects a proper One instance):
class Two(One):
def __init__(self, other):
super(Two, self).__init__(other)
self.other = self.name # <- no, seriously,
del self.name # <- don't do that !!!
You can't do what you want, not if you are calling One.__init__ from Two.__init__.
If you want to alter what attributes are set, simply don't call One.__init__() here. Set your own attributes instead:
class One(object):
def __init__(self, name):
self.name = name
class Two(One):
def __init__(self, other):
self.other = other
Now self.name will never be set. This most likely will break the rest of functionality in One, something you probably don't want to do. The rest of the methods in that class are likely to rely on certain attributes having been set.
In OOP terms, if Two is not a special kind of One object, don't inherit from One. If Two is a kind of One object, don't try to make it into something else.

Two Python classes identical except for superclass - how to avoid duplication?

I have some functionality wrapped up in a Python class (classa). classa inherits from another class supera.
I want exactly the same functionality as classa except that I want to inherit from superb.
I could just copy the class classa to a new class classb and then change the superclass for classb but obviously this very tacky, a maintenance headache and and I'm quite sure there's much better way - can anyone tell me what it is ?
EDIT: Thanks for answers so far. I should have said initially the my classa invokes super in its methods in order to invoke supera methods. It seems that this has some significance when looking at mixins as an option
This can be done with Python's multiple inheritance if none of the methods need to invoke super().
class Dog(object):
name = "Spot"
class Cat(object):
name = "Whiskers"
class SpeakingAnimalMixin(object):
def speak(self):
print "My name is", self.name, "and I can speak!"
class SpeakingDog(SpeakingAnimalMixin, Dog):
pass
class SpeakingCat(SpeakingAnimalMixin, Cat):
pass
SpeakingDog().speak()
My name is Spot and I can speak!
If you do need to invoke super() from a method then you need to create the class dynamically. This works fine, but the generated class's name will be less helpful and IDEs and other static analysis tools may be less useful.
You can create the class using a function, passing the superclass as an argument:
def make_speaking_animal_class(SpeechlessAnimal):
class SpeakingAnimal(SpeechlessAnimal):
def get_name(self):
return "Speaking " + super(SpeakingAnimal, self).get_name()
def speak(self):
print "My name is", self.get_name()
return SpeakingAnimal
class Dog(object):
def get_name(self):
return "Spot"
class Cat(object):
def get_name(self):
return "Whiskers"
SpeakingDog = make_speaking_animal_class(Dog)
SpeakingCat = make_speaking_animal_class(Cat)
SpeakingCat().speak()
My name is Speaking Whiskers
However as mentioned, the class's __name__ attribute may not be what you expect.
print SpeakingDog
print SpeakingDog()
<class '__main__.SpeakingAnimal'>
<__main__.SpeakingAnimal object at 0x1004a3b50>
You can fix this by assigning them unique __name__ attributes yourself:
SpeakingDog.__name__ = 'SpeakingDog'
print SpeakingDog
<class '__main__.SpeakingDog'>
(Credit to Andrew Jaffe for suggesting this in an answer, but he deleted it.)
There's another way to create a class dynamically, but I discourage you from using it unless you need to; it's even less clear. The type function has a second use, apart from its main one of determining the class of an object: it can be used to dynamically create a new class.
When used this way, the type function takes three parameters:
name, the __name__ the new class will have.
bases, a tuple of of base classes that the new class will inherit from.
dict, a dictionary containing the methods and attributes the new class will have.
You could use it like this:
def make_speaking_animal_class(SpeechlessAnimal, name):
def get_name(self):
return "Speaking " + super(SpeakingAnimal, self).get_name()
def speak(self):
print "My name is", self.get_name()
bases = (SpeechlessAnimal,)
# We need to define SpeakingAnimal in a variable so that get_name can refer
# to it for the super() call, otherwise we could just return it directly.
SpeakingAnimal = type(name, bases, {
'get_name': get_name,
'speak': speak
})
return SpeakingAnimal
class Dog(object):
def get_name(self):
return "Spot"
class Cat(object):
def get_name(self):
return "Whiskers"
SpeakingDog = make_speaking_animal_class(Dog, 'SpeakingDog')
SpeakingCat = make_speaking_animal_class(Cat, 'SpeakingCat')
SpeakingDog().speak()
SpeakingCat().speak()
My name is Speaking Spot
My name is Speaking Whiskers

Categories

Resources