Let's suppose I have a parent class called figure:
class Figure:
def __init__(self):
self.name = " "
self.description = " "
self.data = []
def myprint(self):
# Print all variables in a special way
I want to create several childs of this class (Circle, rectangle...) and I want to use as much inheritance as possible. That's why I want to create a myprint function that outputs all the data which is common to all childs, i.e. this one:
self.name = " "
self.description = " "
self.data = []
What is the correct way to do it?
Should I include those lines in class Figure and then modify them in every child using
Figure.name = 'Circle'
... Or should I create them in every child? How would I use a common myprint function then? This way:
class Figure:
def __init__(self):
def myprint(self):
# Print all variables in a special way
class Cricle(Figure):
def __init__(self, radius):
name='Circle'
pass
class Figure:
name = 'Figure'
description = "I'm a figure"
def __init__(self):
self.data = []
def myprint(self):
print(self.name, self.description, self.data)
class Circle(Figure):
name = 'Circle'
description = "I'm a circle"
This is all you need. If the properties aren't specific to an instance, but are the same for all class instances, just define them on the class (here name and description). Only data is defined within the constructor because [] is mutable and you probably want that to be unique for each instance.
The child class then redefines name and description with different values. myprint of Figure instances will print "Figure", while myprint of Circle instances will print "Circle". That's because self.name refers to the name attribute of the current object, and that value will differ based on whether it's a Figure or Circle.
Everything you define in __init__ are instance variables.
I suppose you are looking for class variables, or rather constants which are exactly the same, but written with all capitals by convention.
Also, take a look on the __str__ method here.
The correct way therefore would be:
class Figure:
NAME = "Figure"
def __str__(self):
""" override me """
return "I am a {name} and have the default __str__".format(name=self.NAME)
class Circle(Figure):
NAME = "Circle"
def __init__(self, x, y, r):
self.x, self.y, self.r = x, y, r
def __str__(self):
return "I am a {name} at ({x}, {y}) with radius {r}".format(
name=NAME, x=self.x, y=self.y, r=self.r)
Now all you need to do to get a correct output is to run
f = Figure()
c = Circle(1, 2, 3)
print(f)
print(c)
Which will output
I am a Figure and have my __str__ not overwritten
I am a Circle at (1, 2) with radius 3
Related
I have just started learning OOP in python and I have learned basics like creating class and it's methods, variables and Constructors. Now to create an object we use following steps.
class Example: #Class
name = None
number = None
def __init__(self, name, number): #Constructor
self.name = name
self.number = number
#Step 1
harry = Example("Harry", 45) #Creates an Object
Now here we have manually created Object of Example class named harry.
I have a question that how to create an object with a function.
Like we created a function outside the class and we passed arguments to like name and number and when that function is called it will create a Object of class.
Are you looking for something like this ?
def build_object(name, number):
# returns Example object initialized with name and number
return Example(name, number)
You're talking about Factory Methods
To create objects in functions and returning it would be like:
class Example:
def __init__(self, name, number):
self.name = name
self.number = number
def object_creator(name, number):
new_obj = Example(name, number)
return new_obj
if __name__ == "__main__":
example_object = object_creator("Iago", 1)
print(example_object.name)
print(example_object.number)
Not sure what do you mean exactly.
in oop you can create a function/method then you can from it's object or class.
class Example: #Class
name = None
number = None
def __init__(self, name, number): #Constructor
self.name = name
self.number = number
def your_function(self, x, y):
return x + y
#Step 1
harry = Example("Harry", 45) #Creates an Object
result = harry.your_function(5, 2)
print (result)
output : 7
I am trying to learn how classes work on Python and new to this, I have the following class defined as 'Animal':
class Animal(object):
def __init__(self, size, color, mood):
# init: consists of statements that bind the parameters passed to init to the instance o f the class, when an instance
# is created.
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return "The", self.color, str(self), " is feeling", self.mood, "."
def colors(self, other):
return "The", str(self), "is", self.color, "and the", str(other), "is", other.color, "."
I then create an instance of the Animal object as follow:
hippo = Animal("large", "purple", 'amused')
Finally I call a method on my object as follow:
print(hippo.feeling())
My expectation is to get an output like below:
"The purple hippo is feeling amused."
But what I get in output if I print the same argument as above is:
('The', 'purple', '<__main__.Animal object at 0x7f43cc978160>', ' is feeling', 'amused', '.')
Can someone explain please why the output is similar to a list? also why str(self) returned the object name rather than the word hippo.
The original code in the tutorial was written in Python 3.5, I thought that may have caused it, but I tried the online IDE on https://www.jdoodle.com/python3-programming-online/ for Python 3.5.1 and the result was the same.
You need to pass the animal name when you initialize it — the class won't know the variable name.
class Animal(object):
def __init__(self, name, size, color, mood):
# init: consists of statements that bind the parameters passed to init to the instance of the class, when an instance
# is created.
# pass the name to the class
self.name = name
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return str("The " + self.color + " " + self.name + " is feeling " + self.mood + ".")
def colors(self, other):
return str("The ", self.name, " is " + self.color + " and the " + other.name, " is ", other.color, ".")
The output:
hippo = Animal("hippo", "large", "purple", 'amused')
print(hippo.feeling())
# The purple hippo is feeling amused.
Your method uses commas to separate arguments. Use an f-string, and print instead of returning, as such:
print(f”The {self.size} {self.color} Animal is feeling {self.mood}.”)
Also, you expect self to somehow return the name of the variable. Instead, pass the animal type to the function in init.
As answered by # Ch3steR, you can use __repr__ or __str__. Both serve for the purpose. example is as below:
>>> class Test:
... def __repr__(self):
... return "Test()"
... def __str__(self):
... return "member of Test"
...
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test
There are few things to address here
The value return from the def feeling(self) function is a tuple, whenever the return values are seprated by a comma, the function returns a tuple consiting of all the return values. Hence we you try to print it it comes looking like a list. So either return a string or modify how you are printing the returned values from the tuple.
You want to get the instance name of class object when you are printing it. i.e
hippo = Animal("large", "purple", 'amused') for this you expect str(self) to return the instance name, which is a bit non trivial. First define this funtion def __str__(self): to get desired output whenever you use str(self). Second to get the variable name either supply the name as a class variable in constructor and use it, which would be easier way or you can use python-varname package to use the varname() function to acheive this.
class Klass:
def __init__(self):
self.id = varname()
k = Klass()
# k.id == 'k'
Expandable using list comprehension,
class Animal:
def __init__(self, name, size, color, mood):
self.name = name
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return str(f"The {self.color} {self. name} is feeling {self.mood}.")
def colors(self, other):
return str(f"The {self.name} is {self.color} and the {other.name} is {other.color}.")
n = int(input("No of Animals:"))
Animals = []
for i in range(n):
print(f"Enter Details for Animal No.{i+1}")
s = Animal(*[input(f'Enter {info}: ')for info in ["Name", "Size", "Color", "Mood"]])
Animals.append(s)
for i in range(len(Animals)):
print(f"\nAnimal {i+1}")
print(Animals[i].feeling())
No of Animals:1
Enter Details for Animal No.1
Enter Name: Hippo
Enter Size: large
Enter Color: purple
Enter Mood: happy
Animal 1
The purple Hippo is feeling happy.
[Program finished]
I have a question which is more regarding OOP in general rather than python specific.
Is ist possible to store instances of ClassA in instance of ClassB without a specific method, i.e. by some kind of inheritance.
Example: let's say I have one Model class and one Variable class
class Model():
def __init__(self):
self.vars = []
def _update_vars(self,Variable):
self.vars.append(Variable)
class Variable(Model):
def __init__(self,**kwargs):
self.__dict__.update(kwargs)
Is it now possible to call _update_vars whenever an instance of variable is being created.
So if I do something like this:
mdl = Model()
varA = Variable(...)
varB = Variable(...)
that mdl.vars would now include varA and varB.
I know that I could easily do this by passing the variables as an argument to a "public" method of Model. So I am not looking for
mdl.update_vars(varA)
So my two questions are:
is this possible?
if yes: would this very non-standard OOP programming?
Thanks for your help!
That's not how class inheritance is supposed to work. You only want to inherit something if the child class is going to make use of a good amount of the attributes/methods within the parent class. If the child class has a markedly different structure it should be a class of its own.
In either case, as mentioned by #jasonharper, at some point you would need to give direction as to which Variable instance belongs in which Model instance, so you're likely to end up with something like these:
varA = Variable(mdl, ...)
# or this
mdl.varA = Variable(...)
With the first way, you would maintain the method on your Variable class:
class Foo:
def __init__(self):
self.vars = []
class Bar:
def __init__(self, foo_instance, **kwargs):
foo_instance.vars.append(self)
f = Foo()
b = Bar(f, hello='hey')
f.vars
# [<__main__.Bar object at 0x03F6B4B0>]
With the second way, you can append the Variable instances into a list each time it's added:
class Foo:
def __init__(self):
self.vars = []
def __setattr__(self, name, val):
self.__dict__.update({name: val})
if not name == 'vars': # to prevent a recursive loop
self.vars.append(val)
f = Foo()
f.vars
# []
f.a = 'bar'
f.vars
# ['bar']
Of course, an easier way would be to just look directly into the __dict__ each time you want vars:
class Bar:
#property
def vars(self):
# Or you can return .items() if you want both the name and the value
return list(self.__dict__.values())
b = Bar()
b.a = 'hello'
b.vars
# ['hello']
Both of these will work the same even if you assigned the attributes with your own class instances.
You can use super() for this and pass the instance to the parent
class Model():
vars = []
def __init__(self, other=None):
if other:
self.vars.append(other)
class Variable(Model):
def __init__(self, a):
self.a = a
super().__init__(self)
mdl = Model()
varA = Variable(3)
varB = Variable(4)
print(mdl.vars)
I would like to create an object that holds and creates different objects within itself.
I have an outer class and inner classes, like this:
class Outer:
def __init__(self, name):
self.name = name
def sayHello(self):
print "Hello " + self.name
class Inner1:
def __init__(self, name):
self.name = name
class Inner2(Inner1):
pass
class Inner3(Inner1):
pass
new = outer("new")
And then new needs to make on object of inner2 or inner3...
I tried it with new.inner2()
but I don´t get the result I want.
Any tips?
Here is how you would do nested classes and nested instantiations. When you're embedding the classes, you're only embedding the types. You have to create the instances in self.__init__
(If you're trying to do global inner instances shared among all Outer instances please update your question.)
class Outer(object):
class Inner1(object):
pass
class Inner2(Inner1):
pass
class Inner3(Inner2):
pass
def __init__(self):
self.inner1 = Outer.Inner1()
self.inner2 = Outer.Inner2()
self.inner3 = Outer.Inner3()
outer = Outer()
print outer.inner1
print outer.inner2
print outer.inner3
Note that you don't have to actually use nested classes for this -- your classes can be defined outside of your class, and is sometimes preferred as simpler and more Pythonic:
class Inner1(object):
pass
class Inner2(Inner1):
pass
class Inner3(Inner2):
pass
class Outer(object):
def __init__(self):
self.inner1 = Inner1()
self.inner2 = Inner2()
self.inner3 = Inner3()
outer = Outer()
print outer.inner1
print outer.inner2
print outer.inner3
Sometimes you'll also see a pattern of...
class Inner1(object):
pass
class Outer(object):
Inner1 = Inner1
to make a "handy" reference to the class inside the class. This is often used with custom exceptions that the class might throw.
There are many different opinions on whether nesting the classes is preferred.
Honestly inner classes are not generally a good idea, especially if you're instantiating them outside of the "containing" class.
But to answer your question, basically the inner class is just declared in a different scope, so you need to reference the scope it is in.
# Changed to a capitol letter as that is more conventional
class Outer:
name = ""
def __init__(self, name):
self.name = name
def sayHello(self):
print ("Hello" + self.name)
class Inner1:
def __init__(self, name):
self.name = name
class Inner2(Inner1):
pass
class Inner3(Inner1):
pass
newOuter = Outer("newOuter")
newInner2 = Outer.Inner2("newInner2")
I'm trying to call a method from a previous Class for the Class I'm currently working on. It's a mock GPS system using classes for different things. The class I'm trying to get the method from looks like the following :
class GPS_POI:
def __init__(self, location, name , kind):
self.location= location
self.name = str(name)
self.kind = str(kind)
def __str__ (self):
return (str(self.location) + ": "+ self.name +", " + self.kind )
The current class and method I am working on:
class GPS :
def __init__ (self, current, map = None):
self.current = current
self.map= map
self.route= []
def display_map(self):
for i in self.route:
display= GPS_POI()
return (display.__str__ + "\n")
When I run it, I just end up getting the result of "None" when the output I want (example) would be :
"(3,1): kmart, clothes \n(2,3): burger king, food\n" etc.
Would I need to include my parameter self.map from the class GPS into the display_map function for it work properly? What am I not understanding about calling a method from a previous class?
You aren't calling display.__str__; you are just referencing it. You shouldn't call __str__ explicitly anyway. Its purpose is to provide a hook for when you try to treat the object as a string, such as when passing it to str as an argument:
return str(display) + "\n"