Passing class parameters python - python

I have 2 classes
class Robot1:
def __init__(self, name):
self.name = name
def sayHi(self):
return "Hi, I am " + self.name
class Robot2:
def __init__(self, name):
self.name = name
def sayHello(self):
return "Hello, I am " + self.name
robot_directory = {1: Robot1(), 2: Robot2()}
def object_creator(robo_id, name):
robot_object = robot_directory[robo_id]
return robot_object
But I don't know how to pass the variable name while instantiating the class on the line robot_object = robot_directory[robo_id]. How can I pass the variable?

You are storing already-created instances in the dictionary. Store the class itself instead:
# ...
robot_directory = {1: Robot1, 2: Robot2}
def object_creator(robo_id, name):
robot_class = robot_directory[robo_id]
# Here, the object is created using the class
return robot_class(name)
Obviously, this requires that all your robot classes have the same __init__ parameters.
Going further, you might want to look into inheritance and use a common base class for your robots.

maybe you can try
class Robot1:
def __init__(self):
pass
def set_name(self, name):
return "Hi, I am " + name
class Robot2:
def __init__(self):
pass
def set_name(self, name):
return "Hello, I am " + name
robot_directory = {1: Robot1(), 2: Robot2()}
def object_creator(robo_id, name):
robot_object = robot_directory[robo_id]
return robot_object.set_name(name)

Related

Problems with inheriting the correct property with the child class in python

I am needing to have the child class inherit from the parent class. I continue to either get "TypeError: init() missing 1 required positional argument: 'species'" or the name is often getting assigned to the name and name continues to return back as none.
import unittest
import time
class Mammal:
""" A Mammal class to further populate our animal kingdom """
def __init__(self, species, name):
""" mammal constructor can initialize class attributes """
self.species = species
self.name = None
def eat(self, food):
""" a method that will 'eat' in O(n) time """
i = food
print(self.name, "the", self.species, "is about to eat")
while i >= 1:
time.sleep(0.1)
i = i // 2
print(" ", self.name, "is done eating!")
def makeNoise(self):
""" a method that should be implemented by children classes """
raise NotImplementedError("this method should be implemented by child class")
ADD ANY OTHER BASE CLASS METHODS YOU NEED/WANT TO HERE
def __eq__(self, object):
return isinstance(object, Mammal) and object.species == self.species
THE FOLLOWING TWO CLASSES NEED TO BE COMPLETED, AND YOU
NEED TO REPLACE/DELETE ALL OF THE ELLIPSES SHOWN BELOW
class Hippo(Mammal):
def __init__(self, name, species):
self.name = name
self.species = 'hippo'
def getName(self):
return self.name
def setName(self, h):
self.name = h
def makeNoise(self):
return 'grunting'
class Elephant(Mammal):
def __init__(self, name, species):
self.name = name
self.species = 'elephant'
def getName(self):
return self.name
def setName(self, e):
self.name = e
def makeNoise(self):
return 'trumpeting'
class TestMammals(unittest.TestCase):
""" a class that is derived from TestCase to allow for unit tests to run """
def testInheritance(self):
""" confirm that Elephant and Hippo are children classes of Mammal """
self.assertTrue(issubclass(Elephant, Mammal) and issubclass(Hippo, Mammal))
def testEqOperator(self):
hip1 = Hippo('John')
hip2 = Hippo('Arnold')
self.assertEqual(hip1, hip2)
def main():
""" a 'main' function to keep program clean and organized """
print("-------------------- start main --------------------")
e = Elephant("Ellie")
h = Hippo("Henry")
if(e == h):
print(e.getName(), "and", h.getName(), "are of the same species")
else:
print(e.getName(), "and", h.getName(), "are *not* of the same species")
def listenToMammal(Mammal):
print(Mammal.makeNoise())
listenToMammal(e)
listenToMammal(h)
e.eat(100)
print("--------------------- end main ---------------------")
if __name__ == "__main__":
main()
unittest.main()
enter image description here
this is what the output should look like but im confused
You are still defining Hippo.__init__ to take 2 arguments, even though you ignore the species argument. You can drop that one. You should also use Mammal.__init__ rather than setting the attributes yourself.
class Hippo(Mammal):
def __init__(self, name):
super().__init__(self, name, species='hippo')
def getName(self):
return self.name
def setName(self, h):
self.name = h
def makeNoise(self):
return 'grunting'
getName and setName aren't necessary; you can access the name attribute directly

self not defined when trying to access

I have the following code:
class Person:
def __init__(self,name):
self.name = name
self.balance = 0
def setBalance(self, value):
self.balance = vale
def setName(self, name):
self.name = name
class Main:
def __init__(self):
self.people = []
def addPerson(self,name):
self.people.append(Person(name))
def updateBalance(self,balance,index):
self.people[index].setBalance(50)
print self.people[0]
main = Main()
main.addPerson("Jack")
main.updateBalance(30,0)
I made the following code just to see how objects works with array. But, when I try to run it I get NameError: name 'self' is not defined. I'm not sure what I'm doing wrong ?
If something is not clear or needs editing then please let me know in the comments before down voting.
Many thanks
There a several issues with your code:
Class methods, need to refer to the class def ...(self, ...)
print(...) is a function in Python3 and has to be called from within a method.
The following adjustments make your code work:
class Person:
def __init__(self, name):
self.name = name
self.balance = 0
def setBalance(self, value):
self.balance = value
def setName(self, name):
self.name = name
class Main:
def __init__(self):
self.people = []
def addPerson(self, name):
self.people.append(Person(name))
def updateBalance(self, balance, index):
self.people[index].setBalance(50)
print("Updating people at index %d" % index)
main = Main()
main.addPerson("Jack")
main.updateBalance(30, 0)
print (main.people[0])
Prints:
Updating people at index 0
<__main__.Person instance at 0x100d065f0>
You should pass self as a parameter as well:
class Main:
def __init__(self):
self.people = []
def addPerson(self, name):
self.people.append(Person(name))
def updateBalance(self, balance,index):
self.people[index].setBalance(50)
print people[0] #no need for self if you are calling local variable of class but this will print an empty array
Also you have type error
class Person:
def __init__(self,name):
self.name = name
self.balance = 0
def setBalance(self, value):
self.balance = vale --> not vale but value
def setName(self, name):
self.name = name
Whereas languages like Java or C++ make the "self"/"this" argument implicit in their method definitions, Python makes it explicit. So, the method definitions in your Main class should look like this:
class Main:
def __init__(self):
self.people = []
def addPerson(self, name):
self.people.append(Person(name))
def updateBalance(self, balance, index):
self.people[index].setBalance(50)
In effect, what you had before was an addPerson() method that accepted zero arguments from the caller... and it had renamed self to name, quite unintuitively. Calling the first parameter to a method "self" in Python is only by convention... you could just as easily define addPerson() like this:
class Main:
def addPerson(something_other_t_self, name):
something_other_than_self.people.append(Person(name))
...and it would work exactly the same.

python `getattr` like function that accepts dotted string

I would like to implement a function which is similar to getattr but will accept a dotted string and traverse through each attributes.
def getattr_multiple_level(obj, attr_string):
attr_names = attr_string.split('.')
next_level = obj
for attr_name in attr_names:
next_level = getattr(next_level, attr_name)
return next_level
class Test():
def make_name(self, pre, suffix=""):
return str(pre) + "_my_office_" + suffix
p = Test()
p.room = Test()
p.room.office = Test()
attr = getattr_multiple_level(p, 'room.office.make_name')
Is there already a built-in way to do this? Or what improvements can be made in above code to handle all possible exceptions and edge cases?
Yes, there is "build-in way". You can use property decorator. https://docs.python.org/2/library/functions.html#property
class Author(object):
def __init__(self, full_name):
self.full_name = full_name
class Book(object):
def __init__(self, name):
self.name = name
#property
def author(self):
return Author("Philip Kindred Dick")
class Library(object):
#property
def book_ubik(self):
return Book("ubik")
library = Library()
print(library.book_ubik.name)
print(library.book_ubik.author.full_name)
Result:
grzegorz#grzegorz-GA-78LMT-USB3:~/tmp$ python3 propery_test.py
ubik
Philip Kindred Dick

Mutually Reference-able Instances in Python

Say I have a pair of instances that reference one another mutually. Is there a preferable manner to structure this relationship than the following.
class Human():
def __init__(self, name):
self.name = name
self.pet = Dog('Sparky', self)
def pet(self, animal):
self.pet.receive_petting()
class Dog(Pet):
def __init__(self, name, owner):
self.name = name
self.owner = owner
def receive_petting(self):
pass
def bark_at(self, person):
"do something"
The thing I don't like is that the relationship needs to be specified in two places. Any ideas on how to make this dryer?
I would break this into three classes:
class Human():
def __init__(self, name):
self.name = name
class Dog(Pet):
def __init__(self, name):
self.name = name
def bark_at(self, person):
"do something"
class OwnerPetRelation():
def __init__(self, dog, human):
self.owner=human
self.pet=dog
Now, one owner can also have many dogs, we just need to define as many OwnerPetRelations.
Similarly, a dog can also belong to multiple owners now.
I would create a method on Human that allows you to add pets (since a human might have many pets):
class Human():
def __init__(self, name):
self.name = name
self.pets = []
def add_pet(self, pet):
pet.owner = self
self.pets.append(pet)
def pet(self, animal):
for pet in self.pets:
pet.receive_petting()
class Dog(Pet):
def __init__(self, name):
self.name = name
self.owner = None
def receive_petting(self):
pass
def bark_at(self, person):
"do something"
This can be used as follows
human = Human('Jim')
human.add_pet(Dog('Woof'))
This approach can of course also be used for just a single pet and one could also extend it to allow pets to be owned by many humans.
There's nothing really Python-specific here; this is just a limitation of constructor-based dependency injection. It's hard to inject a reference to another object that cannot have been created yet. Instead, you can create an object that has a reference to something that will have a reference to the other object. For instance, you can pass a function to the constructor that will be able to return the value:
class Human():
def __init__(self,name,dog):
self.name = name
self._dog = dog
#property
def dog(self):
return self._dog()
class Dog():
def __init__(self,name,human):
self.name = name
self._human = human
#property
def human(self):
return self._human()
Then you can use it like this:
human = None
dog = Dog('fido',lambda: human)
human = Human('john',lambda: dog)
print(dog.human.name)
print(human.dog.name)
john
fido
It is not hard to update this so that the property function caches the value, of course. E.g.:
class Dog():
def __init__(self,name,human):
self.name = name
self._human = human
#property
def human(self):
try:
return self._human_
except AttributeError:
self._human_ = self._human()
return self._human_

Dynamically mixin a base class to an instance in Python

Is it possible to add a base class to an object instance (not a class!) at runtime? Something along the lines of how Object#extend works in Ruby:
class Gentleman(object):
def introduce_self(self):
return "Hello, my name is %s" % self.name
class Person(object):
def __init__(self, name):
self.name = name
p = Person("John")
# how to implement this method?
extend(p, Gentleman)
p.introduce_self() # => "Hello, my name is John"
This dynamically defines a new class GentlePerson, and reassigns p's class to it:
class Gentleman(object):
def introduce_self(self):
return "Hello, my name is %s" % self.name
class Person(object):
def __init__(self, name):
self.name = name
p = Person("John")
p.__class__ = type('GentlePerson',(Person,Gentleman),{})
print(p.introduce_self())
# "Hello, my name is John"
Per your request, this modifies p's bases, but does not alter p's original class Person. Thus, other instances of Person are unaffected (and would raise an AttributeError if introduce_self were called).
Although it was not directly asked in the question, I'll add for googlers and curiosity seekers, that it is also possible to dynamically change a class's bases but (AFAIK) only if the class does not inherit directly from object:
class Gentleman(object):
def introduce_self(self):
return "Hello, my name is %s" % self.name
class Base(object):pass
class Person(Base):
def __init__(self, name):
self.name = name
p = Person("John")
Person.__bases__=(Gentleman,object,)
print(p.introduce_self())
# "Hello, my name is John"
q = Person("Pete")
print(q.introduce_self())
# Hello, my name is Pete
Slightly cleaner version:
def extend_instance(obj, cls):
"""Apply mixins to a class instance after creation"""
base_cls = obj.__class__
base_cls_name = obj.__class__.__name__
obj.__class__ = type(base_cls_name, (base_cls, cls),{})
Although it's already answered, here is a function:
def extend(instance, new_class):
instance.__class__ = type(
'%s_extended_with_%s' % (instance.__class__.__name__, new_class.__name__),
(instance.__class__, new_class),
{},
)

Categories

Resources