class Tesla_car:
def __init__(self,yourname):
self.name = yourname
print("Hey'%s',I am a bot and I will tell you about....." %self.name)
self.cells = self.batteries()
def material(self,model_no):
self.model = model_no
print("your car",self.model," made from aluminium")
def color(self,color):
self.color = color
print("the color of your car is:'%s'" %self.color)
class batteries:
def __init__(self):
pass
def materials(self):
self.battery_name = "Tesla tabless 4680 cells"
self.chemicals = "Tesla uses Lithium-Nickle-cobalt-magnesium(NMC) mixed in 8:1:1 ratio"
EV_car = Tesla_car('Blah')
EV_car()
Hey everyone, I am trying to use nested classes but whenever I try to use the inner class by writing self.cells = self.batteries() It raises an error:"Tesla_car' object has no attribute 'batteries"
How do I fix it
It seems that you're trying to compose objects, but in the wrong way.
Actually your classes reflect a perfect irl scenario for implementing composition: cars are equipped (composed) with a set of different objects, batteries included.
When using composition, you'd typically define TeslaCar and Batteries as separate classes, and then you would assign an instance of Batteries to one of TeslaCar instance variables. E.g.:
class Batteries:
def __init__(self):
...
class TeslaCar:
def __init__(self):
self.batteries = Batteries()
...
The above code is just a simple skeleton of how composition is implemented, but you can adapt it to your case very easily.
Finally FYI, avoid nesting classes at all. It's unpythonic and you'll discover that it's useless as soon as you dive deep into simple oop patterns like composition and inheritance.
Change
self.batteries()
to
Tesla_car.batteries()
your batteries inner class is wrongly indented.
Currently it is inside the color method instead of being at the same level as the method.
class TeslaCar:
def color(...):
...
class Batteries:
...
instead, do:
class TeslaCar:
def color(...):
...
class Batteries:
...
Related
I have a class which contains a list like so:
class Zoo:
def __init__(self):
self._animals = []
I populate the list of animals with animal objects that have various properties:
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
You can imagine subclasses of Animal that have other properties. I want to be able to write methods that perform the same calculation but on different attributes of the Animal. For example, an average. I could write the following in Zoo:
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self.animals) / len(self.animals)
That string lookup not only messes with my ability to document nicely, but using getattr seems odd (and maybe I'm just nervous passing strings around?). If this is good standard practice, that's fine. Creating get_average_speed(), get_average_height(), and get_average_length() methods, especially as I add more properties, seems unwise, too.
I realize I am trying to encapsulate a one-liner in this example, but is there a better way to go about creating methods like this based on properties of the objects in the Zoo's list? I've looked a little bit at factory functions, so when I understand them better, I think I could write something like this:
all_properties = ['speed', 'height', 'length']
for p in all_properties:
Zoo.make_average_function(p)
And then any instance of Zoo will have methods called get_average_speed(), get_average_height(), and get_average_length(), ideally with nice docstrings. Taking it one step further, I'd really like the Animal objects themselves to tell my Zoo what properties can be turned into get_average() methods. Going to the very end, let's say I subclass Animal and would like it to indicate it creates a new average method: (the following is pseudo-code, I don't know if decorators can be used like this)
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
#Zoo.make_average_function
#property
def tail_length(self):
return self._tail_length
Then, upon adding a Tiger to a Zoo, my method that adds animals to Zoo object would know to create a get_average_tail_length() method for that instance of the Zoo. Instead of having to keep a list of what average methods I need to make, the Animal-type objects indicate what things can be averaged.
Is there a nice way to get this sort of method generation? Or is there another approach besides getattr() to say "do some computation/work on an a particular property of every member in this list"?
Try this:
import functools
class Zoo:
def __init__(self):
self._animals = []
#classmethod
def make_average_function(cls, func):
setattr(cls, "get_average_{}".format(func.__name__), functools.partialmethod(cls.get_average, propertyname=func.__name__))
return func
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self._animals) / len(self._animals)
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
#property
#Zoo.make_average_function
def tail_length(self):
return self._tail_length
my_zoo = Zoo()
my_zoo._animals.append(Tiger(10))
my_zoo._animals.append(Tiger(1))
my_zoo._animals.append(Tiger(13))
print(my_zoo.get_average_tail_length())
Note: If there are different zoos have different types of animals, it will lead to confusion.
Example
class Bird(Animal):
def __init__(self, speed):
self._speed = speed
#property
#Zoo.make_average_function
def speed(self):
return self._speed
my_zoo2 = Zoo()
my_zoo2._animals.append(Bird(13))
print(my_zoo2.get_average_speed()) # ok
print(my_zoo.get_average_speed()) # wrong
print(my_zoo2.get_average_tail_length()) # wrong
I want to be able to create objects based on an enumeration class, and use a dictionary. Something like this:
class IngredientType(Enum):
SPAM = auto() # Some spam
BAKE_BEANS = auto() # Baked beans
EGG = auto() # Fried egg
class Ingredient(object):
pass
class Spam(Ingredient):
pass
class BakedBeans(Ingredient):
pass
class Egg(Ingredient):
pass
class IngredientFactory(object):
"""Factory makes ingredients"""
choice = {
IngredientType.SPAM: IngredientFactory.MakeSpam,
IngredientType.BAKED_BEANS: IngredientFactory.MakeBakedBeans,
IngredientType.EGG: IngredientFactory.MakeEgg
}
#staticmethod
def make(type):
method = choice[type]
return method()
#staticmethod
def makeSpam():
return Spam()
#staticmethod
def makeBakedBeans():
return BakedBeans()
#staticmethod
def makeEgg():
return Egg()
But I get the error:
NameError: name 'IngredientFactory' is not defined
For some reason the dictionary can't be created.
Where am I going wrong here?
Python is not Java and doesn't require everything to be in a class. Here your IngredientFactory class has no states and only staticmethods, so it's actually just a singleton namespace, which in python is canonically done using the module as singleton namespace and plain functions. Also since Python classes are already callable, wrapping the instanciation in a function doesn't make sense. The simple, straightforwrad pythonic implementation would be:
# ingredients.py
class IngredientType(Enum):
SPAM = auto() # Some spam
BAKE_BEANS = auto() # Baked beans
EGG = auto() # Fried egg
class Ingredient(object):
pass
class Spam(Ingredient):
pass
class Beans(Ingredient):
pass
class Egg(Ingredient):
pass
_choice = {
IngredientType.SPAM: Spam,
IngredientType.BAKED_BEANS: Beans,
IngredientType.EGG: Egg
}
def make(ingredient_type):
cls = _choice[ingredient_type]
return cls()
And the client code:
import ingredients
egg = ingredients.make(ingredients.IngredientType.EGG)
# or much more simply:
egg = ingredients.Egg()
FWIW the IngredientType enum doesn't bring much here, and even makes things more complicated that they have to be - you could just use plain strings:
# ingredients.py
class Ingredient(object):
pass
class Spam(Ingredient):
pass
class Beans(Ingredient):
pass
class Egg(Ingredient):
pass
_choice = {
"spam": Spam,
"beans": Beans,
"egg": Egg
}
def make(ingredient_type):
cls = _choice[ingredient_type]
return cls()
And the client code:
import ingredients
egg = ingredients.make("egg")
Or if you really want to use an Enum, you can at least get rid of the choices dict by using the classes themselves as values for the enum as suggested by MadPhysicist:
# ingredients.py
class Ingredient(object):
pass
class Spam(Ingredient):
pass
class Beans(Ingredient):
pass
class Egg(Ingredient):
pass
class IngredientType(Enum):
SPAM = Spam
BEANS = Beans
EGG = Egg
#staticmethod
def make(ingredient_type):
return ingredient_type.value()
and the client code
from ingredients import IngredientType
egg = IngredientType.make(IngredientType.EGG)
But I really don't see any benefit here either
EDIT: you mention:
I am trying to implement the factory pattern, with the intent of hiding the creation of objects away. The user of the factory then just handles 'Ingredients' without knowledge of the concrete type
The user still have to specify what kind of ingredients he wants (the ingredient_type argument) so I'm not sure I understand the benefit here. What's your real use case actually ? (the problem with made up / dumbed down examples is that they don't tell the whole story).
After looking at Bruce Eckel's book I came up with this:
#Based on Bruce Eckel's book Python 3 example
# A simple static factory method.
from __future__ import generators
import random
from enum import Enum, auto
class ShapeType(Enum):
CIRCLE = auto() # Some circles
SQUARE = auto() # some squares
class Shape(object):
pass
class Circle(Shape):
def draw(self): print("Circle.draw")
def erase(self): print("Circle.erase")
class Square(Shape):
def draw(self): print("Square.draw")
def erase(self): print("Square.erase")
class ShapeFactory(object):
#staticmethod
def create(type):
#return eval(type + "()") # simple alternative
if type in ShapeFactory.choice:
return ShapeFactory.choice[type]()
assert 0, "Bad shape creation: " + type
choice = { ShapeType.CIRCLE: Circle,
ShapeType.SQUARE: Square
}
# Test factory
# Generate shape name strings:
def shapeNameGen(n):
types = list(ShapeType)
for i in range(n):
yield random.choice(types)
shapes = \
[ ShapeFactory.create(i) for i in shapeNameGen(7)]
for shape in shapes:
shape.draw()
shape.erase()
This gets the user to select a class type from the enumeration, and blocks any other type. It also means user's are less likely to write 'bad strings' with spelling mistakes. They just use the enums.
The output from the test is then, something like this:
Circle.draw
Circle.erase
Circle.draw
Circle.erase
Square.draw
Square.erase
Square.draw
Square.erase
Circle.draw
Circle.erase
Circle.draw
Circle.erase
Square.draw
Square.erase
Place your mapping at the end of the class, and reference the methods directly, since they're in the same namespace:
choice = {
IngredientType.SPAM: makeSpam,
IngredientType.BAKED_BEANS: makeBakedBeans,
IngredientType.EGG: makeEgg
}
A class object is not created until all the code in the class body, so you can't access the class itself. However, since the class body is processed in a dedicated namespace, you can access any attribute you've defined up to that point (which is why the mapping has to come at the end). Note also that while you can access globals and built-ins, you can't access the namespaces of enclosing classes or functions.
Here's the detailed but still introductory explanation from the official docs explaining how classes are executed: https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes
I have class with hundreds of methods
I want create a hierarchy of them that will let easy find method.
For example
class MyClass:
def SpectrumFrequencyStart()...
def SpectrumFrequencyStop()...
def SpectrumFrequencyCenter()...
def SignalAmplitudedBm()...
That I want to call using:
MyClassObject.Spectrum.Frequency.Start()
MyClassObject.Spectrum.Frequency.Stop()
MyClassObject.Signal.Amplitude.dBm()
Consider using a dictionary to map your methods to keys (either hierarchical dictionaries, or simply '.' separated keys).
Another option which may be more elegant is namedtuples. Something like:
from collections import namedtuple
MyClassObject = namedtuple('MyClassObject', ['Spectrum', 'Signal'])
MyClassObject.Spectrum = namedtuple('Spectrum', ['Frequency'])
MyClassObject.Spectrum.Frequency = namedtuple('Frequency', ['Start', 'Stop'])
MyClassObject.Spectrum.Frequency.Start = MyClass.SpectrumFrequencyStart
You can automate this by using inspection and parse the method names by, say camel case, to build the namedtuples automatically.
Pay attention to binding of the methods
This is just a very bad design.
It's clear that Spectrum, Signal, Frequency (and so on) should be all separate classes with much less than "hundreds of methods".
I'm not sure if MyClassObject actually represents something or is effectively just a namespace.
Objects can encapsulate objects of other classes. For example:
class Frequency(object):
def start(self):
pass
def stop(self):
pass
class Spectrum(object):
def __init__(self):
self.frequency = Frequency()
class Amplitude(object):
def dbm(self):
pass
class Signal(object):
def __init__(self):
self.amplitude = Amplitude()
class MyClass(object):
def __init__(self):
self.spectrum = Spectrum()
self.signal = Signal()
my_class_instance = MyClass()
my_class_instance.spectrum.frequency.start()
my_class_instance.spectrum.frequency.stop()
my_class_instance.spectrum.signal.amplitude.dbm()
There's a convention of code formatting in Python PEP 8 therefore I applied it in my example.
For a program that creates a timetable for a doctor(specialist) I want to use certain attributes of an object created by a different class to be used in the class that makes the timetable for the doctor.
class makePatient(object):
def __init__(self,name,room):
self.name = name
self.room = room
def getPatient(self):
print(self.name)
print(self.room)
class makeSpecialist(object):
def __init__(self,name,specialization,timetable):
self.name = name
self.specialization = specialization
self.timetable = timetable
def getSpecialist(self):
print(self.name)
print(self.specialization)
print(self.timetable)
class makeAgenda(object):
def addAgenda(self):
self.timetable.append()
#I want to append the name of the patient I have defined here.
print(self.timetable)
patient1 = makePatient("Michael","101")
specialist1 = makeSpecialist("Dr. John","Hematology",[])
What do I do now, to make sure that the name "Michael" gets added to the list [] of specialist Dr. John?
Thanks in advance, I will provide further details if necessary!
I think another approach would be better; you can put the whole makePatient object into the timetable for the specialist:
specialist1 = makeSpecialist("Dr. John", "Hematology", [patient1])
Now you can access the names and other attributes of the patients in a specialist's timetable:
for patient in specialist1.timetable:
print(patient.name)
You can also define a __repr__ method to tell Python how to display an object, rather than the current getPatient:
class makePatient(object):
# ...
def __repr__(self):
return "{0} (room {1})".format(self.name, self.room)
Now when you print the whole timetable:
>>> print(specialist1.timetable)
You get the necessary information:
[Michael (room 101)]
Note also that the classes should probably be called, simply, Patient, Specialist and Agenda; the make is implied.
Finally, you will get errors in makeAgenda.addAgenda as, without an __init__, self.timetable doesn't exist for a makeAgenda object, and an empty append() doesn't do anything anyway.
Classes are often used to represent entities and operations allowed on them, include constructing, or making, new instances of them. Therefore, your classes would be better named simplyPatient, Specialist, andAgenda. The name of the method that constructs a new instance of any class in Python is always__init__().
That said, after creating aPatientand aSpecialistyou could then add patient instances to the specialist's timetable/agenda by passing it to aSpecialistmethod specifically designed for that purpose. In other words, a Specialist "has-a" Agenda instance namedtimetableand to which patients can be added via an appropriately namedadd_to_timetable()method.
Here's what I mean -- note I've modified your code to follow PEP 8 -- Style Guide for Python Code guidelines which I also suggest that you follow:
class Agenda(object):
def __init__(self):
self.events = []
def append(self, event):
self.events.append(event)
class Patient(object):
def __init__(self, name, room):
self.name = name
self.room = room
def get_patient(self):
print(self.name)
print(self.room)
class Specialist(object):
def __init__(self, name, specialization):
self.name = name
self.specialization = specialization
self.timetable = Agenda()
def add_to_timetable(self, patient):
self.timetable.append(patient)
def get_specialist(self):
print(self.name)
print(self.specialization)
print(self.timetable)
specialist1 = Specialist("Dr. John", "Hematology")
patient1 = Patient("Michael", "101")
specialist1.add_to_timetable(patient1)
I'm not too sure what you're trying to accomplish here with method that just print values or with the makeAgenda class, but here's how you can get Michael in Dr. John's list:
specialist1.timetable.append(patient1.name)
I have an instance of a base class, and then I want to make it an instance of a child class of this base class. Maybe I'm taking the problem in a wrong way and there's something important I didn't understand in OOP. Code is only there to illustrate and a very different approach can be suggested. Any help appreciated.
class Car(object):
def __init__(self, color):
self.color = color
def drive(self):
print "Driving at 50 mph"
class FastCar(Car):
def __init__(self, color, max_speed=100):
Car.__init__(self, color)
self.max_speed = max_speed
def drive_fast(self):
print "Driving at %s mph" %self.max_speed
one_car = Car('blue')
# After the instanciation, I discovered that one_car is not just a classic car
# but also a fast one which can drive at 120 mph.
# So I want to make one_car a FastCar instance.
I see a very similar question, but none of the answers suits my problem :
I don't want to make FastCar a wrapper around Car which would know how to drive fast : I really want that FastCar extends Car ;
I don't really want to use the __new__ method in FastCar to make some tests on the arguments and decide if __new__ has to return a new instance of Car or the instance I gave to it (example: def __new__(cls, color, max_speed=100, baseclassinstance=None)).
class FastCar(Car):
def __init__(self, color, max_speed=100):
Car.__init__(self, color)
self.max_speed = max_speed
def drive_fast(self):
print "Driving at %s mph" %self.max_speed
#staticmethod
def fromOtherCar(car):
return FastCar(car.color)
actually_fast = FastCar.fromOtherCar(thought_was_classic)
This is the standard way.
Depending on the real class layout, you may be able to do something like:
classic = Car('blue')
classic.__class__ = FastCar
classic.__dict__.update(FastCar(classic.color).__dict__)
classic.drive_fast()
But I wouldn't recommend it -- it's a hack, it won't always work, and the other way is cleaner.
Edit: Was just about to add basically what #PaulMcGuire's comment says. Follow that advice, he's right.
You can borrow the C++ notion of a "copy constructor" to do something like this.
Allow Car's constructor to take a Car instance, and copy all of its properties. FastCar should then accept either Car instances or FastCar instances.
So then, to convert the car, you would just do one_car = FastCar(one_car). Note that this will not affect references to the original Car object, which will remain pointing to the same Car.
Why not just use one class?
class Car(object):
def __init__(self, color, max_speed = 50):
self.color = color
self.max_speed = max_speed
def drive(self):
print "Driving at %s mph"%self.max_speed
c=Car('blue')
c.max_speed = 100
It is not common in OOP to change type (class) of a living object after instantiation. I know barely two languages that would allow that as a dirty hack. The whole purpose of types (classes) is to know beforehand what operations an object can and can not perform. If you want something like this, you're probably mistaking the idea of OOP.