Python 3x class methods - python

I'm currently learning the basics of classes, and I came up with some basic code as follows:
class shape(object):
def __init__(self, num_sides, type):
self.num_sides = num_sides
self.type = type
class square(shape):
def __init__(self, side_length):
self.num_sides = 4
self.type = 'regular quadrilateral'
self.side_length = side_length
def perim():
return side_length * 4
def area():
return side_length ** 2
class circle(shape):
def __init__(self, radius):
self.num_sides = 1
self.type = 'ellipsis'
self.radius = radius
Now, when I type the following:
shape1 = square(5)
shape1.perim()
I get the following output:
<bound method square.perim of <__main__.square object at 0x0000000003D5FB38>>
What is this? How can I get python to actually return the perimeter of the square?
Also, I have another question:
Do any class methods exist other than __init__() and __str__()? If so, can you please list them so I can go off and research them?

as shown, you are going to have some problems with this. If you are trying to have circle and square be subset set classes of shape, then the two sub classes need to be indented. Also, on class circle and square, you really do not need the (shape). also note the things I commented out as not needed.
This does not come out as I am posting it. the class shape (object):does not show up and the subclasses are not indented and I can not seem to make it show up
class shape(object):
def init(self, num_sides, type):
#self.num_sides = num_sides
self.type = type
class square:
def __init__(self, side_length):
#self.num_sides = 4
#self.type = 'regular quadrilateral'
self.side_length = side_length
def perim(self):
return self.side_length * 4
def area(self):
return self.side_length ** 2
class circle:
def __init__(self, radius):
#self.num_sides = 1
#self.type = 'ellipsis'
self.radius = radius
def area (self):
return 3.14 * self.radius ** 2
shape2 = circle (5)
print ('test of circle: ',shape2.area ())
shape1 = square(5)
print('test of square: ', shape1.perim())

Two things, indentation of the init of shape and add self. to the perim and area methods.
class shape(object):
def __init__(self, num_sides, type):
self.num_sides = num_sides
self.type = type
class square(shape):
def __init__(self, side_length):
self.num_sides = 4
self.type = 'regular quadrilateral'
self.side_length = side_length
def perim(self):
return self.side_length * 4
def area(self):
return self.side_length ** 2
class circle(shape):
def __init__(self, radius):
self.num_sides = 1
self.type = 'ellipsis'
self.radius = radius
shape1 = square(5)
print( shape1.perim())

Access instance variable with self
class square(shape):
def __init__(self, side_length):
self.num_sides = 4
self.type = 'regular quadrilateral'
self.side_length = side_length
def perim(self):
return self.side_length * 4
def area(self):
return self.side_length ** 2

Related

How to access the stored array in class

I want to access the array i have filled throughout the for loop,however what i get it is still empty array when call fill_particles().particles, is there any way to get rid of this problem? here is my code.
class particle(object):
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z
class fill_particles():
def __init__(self):
self.particles=[]
def fill(self):
for i in range(5):
self.particles.append(particle(i,i+1,i+2))
You need to instantiate the class and call fill(). Here's a working example, along with extra functions for display purposes:
class Particle(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return f'Particle(x={self.x}, y={self.y}, z={self.z})'
class Particles:
def __init__(self):
self.particles = []
def fill(self):
for i in range(5):
self.particles.append(Particle(i, i + 1, i + 2))
def __repr__(self):
return f'Particles({self.particles!r})'
particles = Particles()
print(particles)
particles.fill()
print(particles)
Output:
Particles([])
Particles([Particle(x=0, y=1, z=2), Particle(x=1, y=2, z=3), Particle(x=2, y=3, z=4), Particle(x=3, y=4, z=5), Particle(x=4, y=5, z=6)])

How to assign a data attribute of a subclass to attributes of its parent class

I have a class Rectangle with data attributes width and height, I want a subclass Square with data attribute side_length.
How do I make it so that square.width and square.height give its side length? i.e same as square.side
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
class Square(Rectangle):
def __init__(self, side)
self.side = side
This is what I have so far.
You could call the constructor for Rectangle.
super(Square,self).__init__(side, side)
or you could have properties to return those attributes. I'd edge towards the super.
#property
def length(self):
return self.side
#property
def width(self):
return self.side
Things get more complicated if you can change the side, height or width attribute after creating the object. You need to keep width and height synched and coherent. One possible way is to do away entirely with side as a stored attribute on Square and instead have it as a read-write property that updates Rectangle's width and height.
to keep height/width/side sorted after the initial constructors:
class Rectangle:
#property
def height(self):
return self._height
#height.setter
def height(self, value):
self._height = value
#property
def width(self):
return self._width
#width.setter
def width(self, value):
self._width = value
def __repr__(self):
return(f"{self.__class__.__name__}:{self.height=} {self.width=}")
def __init__(self, height, width):
self.height = height
self.width = width
class Square(Rectangle):
def __repr__(self):
return(f"{self.__class__.__name__}:{self.side=}")
#property
def side(self):
return self._width
#side.setter
def side(self, value):
self._width = value
self._height = value
def __init__(self, side):
super(Square, self).__init__(side, side)
#these are here so you can't cheat and vary height and width
#independently on a square
#property
def width(self):
return self.side
#width.setter
def width(self, value):
self.side = value
#property
def height(self):
return self._side
#height.setter
def height(self, value):
self.side = value
rectangle = Rectangle(5,2)
print(rectangle)
rectangle.height = 6
print(rectangle)
square = Square(3)
print(square)
square.side = 6
print(square)
square.height = 9
print(square)
output:
$ py test_square.py
Rectangle:self.height=5 self.width=2
Rectangle:self.height=6 self.width=2
Square:self.side=3
Square:self.side=6
Square:self.side=9

Class function doesn't return correct value

This is my code:
class Rectangle(object):
def __init__(self, height, width):
self.height = height
self.width = width
def __str__(self):
return '{} x {} = {}'.format(self.height, self.width, self.area)
def area(self):
self.area=self.height*self.width
return self.area
def primarySchool(height, width):
return str(Rectangle(height, width))
For input height=7 and width=4 the output is
>>> primarySchool(7, 4):
7 x 4 = <bound method _runjcbjp.<locals>.Rectangle.area of
<__main__._runjcbjp.<locals>.Rectangle object at 0x2b482cd637f0>>
instead of 7 x 4 = 28.
How can I fix this?
In your Rectangle class, the area member is defined as a method.
As a consequence, print(self.area) will give you the representation of that method object, which is that <...> thing.
What you want is the result of the area method, not the method itself.
Therefore, you need to call the method, by writing parentheses after its name.
Your code should be:
return '{} x {} = {}'.format(self.height, self.width, self.area())
Additionnally, be careful not to reassign the same name in your method.
In your area method, you write:
self.area = self.height * self.width
As a consequence, after the first call to instance.area(), the area member will be overwritten, from a function to a number.
Subsequent calls would thus fail, with something like "Int object is not callable".
area is a method of your class, so you have to call it to get the return value (and not the method itself).
But given the fact that you assign to self.area inside the method it seems like you want it as "cached" property (accessible without calling it explicitly):
class Rectangle(object):
def __init__(self, height, width):
self.height = height
self.width = width
def __str__(self):
return '{} x {} = {}'.format(self.height, self.width, self.area)
#property
def area(self): # cached version
try:
return self._area
except AttributeError:
self._area=self.height*self.width
return self._area
def primarySchool(height, width):
return str(Rectangle(height, width))
primarySchool(7, 4)
# '7 x 4 = 28'
Or as uncached version:
class Rectangle(object):
def __init__(self, height, width):
self.height = height
self.width = width
def __str__(self):
return '{} x {} = {}'.format(self.height, self.width, self.area)
#property
def area(self):
return self.height*self.width
Or just calculate it in the __init__ and also set it as attribute:
class Rectangle(object):
def __init__(self, height, width):
self.height = height
self.width = width
self.area = height * width
def __str__(self):
return '{} x {} = {}'.format(self.height, self.width, self.area)
You're trying to have both a function and property called "area".
Why not simply:
def area(self):
return self.height*self.width
Call with:
self.area()

Python inherit variables from parent class

Sorry if I don't explain it that well but I'll try my best:
So I want to inherit the variables from the Parent class, but I don't want to pass them again when creating an instance of the Child class because I think that is redundant. I just want to use the eye color from the Parent for example. See the example code below for what I mean
This is what works:
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender, eye_color, length):
super().__init__(eye_color, length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men", "Blue", 2)
print(x.eye_color, x.length)
print(y.gender, x.length)
This is what I somehow want:
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender):
super().__init__(eye_color, length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men")
print(x.length, x.eye_color)
print(y.gender, x.length)
What you ask does not make sense:
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender):
super().__init__(eye_color, length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men")
print(x.length, x.eye_color)
print(y.gender, x.length)
In child, the parameters eye_color and length come from nowhere.
rassar example is good if you want to reuse a parent object.
You can also do the following:
class Parent:
# def __init__(self, eye_color=(default value here), length=(default value here)):
def __init__(self, eye_color="", length=0):
self.eye_color = str(eye_color)
self.length = length
OR
class Parent:
def __init__(self, eye_color="", length=0):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender, *args, **kwargs):
super().__init__(*args, **kwargs)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men") # Work with first example of Parent
y = Child("Men", eye_color="Blue", length=2) # Work with first
y = Child("Men", "Blue", 2) # Work with second example
print(x.length, x.eye_color)
print(y.gender, y.length)
You could try passing a Parent instance to the Child initializer...That's probably the closest you'll get.
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender, parent):
super().__init__(parent.eye_color, parent.length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men", x)
print(x.length, x.eye_color)
print(y.gender, x.length)
Another thing you could do is hold a last_parent variable:
global last_parent
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
last_parent = self
class Child(Parent):
def __init__(self, gender):
super().__init__(last_parent.eye_color, last_parent.length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men")
print(x.length, x.eye_color)
print(y.gender, x.length)

How should I implement, and what should I call, a common base class for Area and Point?

So I want a Point and an Area classes similar to how C# has Point and Size. Here are simple implementations of the two classes:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
# Many other magic methods too!
class Area:
def __init__(self, width=0, height=0):
self.width = width
self.height = height
def __add__(self, other):
return Area(self.width + other.width, self.height + other.height)
# Many other magic methods too!
As you can see, the two classes are exact duplicates, except one has x, y while the other has width, height.
What would be a good solution for implementing some kind of base class for these two?
If you don't mind using immutable objects, you could subclass tuple to craete a base class for all of the two dimensional stuff:
class _2dTuple(tuple):
def __new__(cls, hor=0, ver=0):
super().__new__(cls, (hor, ver))
def __add__(self, other):
return type(self)(self[0] + other[0], self[1] + other[1])
Now when you subclass your _2dTuple, you can just create property getters for your x, y and width, height:
class Point(_2dTuple):
#property
def x(self):
return self[0]
#property
def y(self):
return self[1]
class Area(_2dTuple):
#property
def width(self):
return self[0]
#property
def height(self):
return self[1]

Categories