Which are the differences or advantages of Circle1 and Circle2? Is there a more correct way than the other? The only advantage is that in Circle2 I can inherit it?
class Geometry(object):
def __init__(self, x, y):
self.ptsx = x
self.ptsy = y
class Circle1(Geometry):
def __init__(self, radius):
self.radius = radius
def area(self):
def circle_formula(radius):
return 3.14*radius
return circle_formula(self.radius)
class Circle2(Geometry):
def __init__(self, radius):
self.radius = radius
def area(self):
return self.circle_formula(self.radius)
#staticmethod
def circle_formula(radius):
return 3.14*radius
I know that the correct way would be that the #staticmethod of Cicle2 would be a function like area_formula and when inheriting it, rewrite it. But my doubt is, if I really have to use an auxiliary function that only is going to live inside a specific class, what is the most correct way to implement it?
The main difference between those two classes, is that, if you add staticmethod to a method, you can access to that method without instantiating the class.
I mean, I could do: Circle2.circle_formula(2).
In Circle1, you should instantiate the class to access to the method to calculate the area;
my_circle = Circle1(2)
my_circle.area()
But, in the case that you are presenting, I would add the logic inside the area method, as the Circle1 is implemented, without using a function inside of it. Like this:
class Circle1(Geometry):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14*radius
Related
def lazyproperty(func):
name = '_lazy_' + func.__name__
#property
def lazy(self):
print(self)
if hasattr(self, name):
return getattr(self, name)
else:
value = func(self)
setattr(self, name, value)
return value
return lazy
import math
class Circle:
def __init__(self, radius):
self.radius = radius
#lazyproperty
def area(self):
print('Computing area')
return math.pi * self.radius ** 2
I am new to python property and decorators. When reading some examples like above,
I have difficulty understanding how it works.
For example, I do not quite get how the "self" inside the lazy definition is the Circle object.Could any one elaborate this example? Thanks!
There is nothing special about the name self; it's just the conventional name given to the first parameter of a function intended to be used as a method. In this case, that function is defined inside lazyproperty instead of directly in the class Circle.
It might help to see the same code written without decorator syntax.
def lazyproperty(func):
name = '_lazy_' + func.__name__
# The "method" to be turned into a property
def lazy(self):
print(self)
if hasattr(self, name):
return getattr(self, name)
else:
value = func(self)
setattr(self, name, value)
return value
# Return the property
return property(lazy)
import math
class Circle:
def __init__(self, radius):
self.radius = radius
# The method to be wrapped by lazyproperty
def area(self):
print('Computing area')
return math.pi * self.radius ** 2
# The actual wrapping to make area a (lazy) property
area = lazyproperty(area)
I am learning how to create classes in python where when modifying attribute 1 will change attribute 2.
For instance a circle with an attribue radius.
class Circle():
def __init__(self,radius):
self._radius = radius
#property
def radius(self):
return self._radius
#radius.setter
def radius(self, value):
self.radius = value
#property
def area(self):
return 3.14*self.radius*self.radius
And this happens:
c = Circle(3)
c.area
All fine. but now:
c.radius = 56
print(c.area)
gives:
RecursionError: maximum recursion depth exceeded
The question is why?
What is the way to force recalculation of other attributes when one is changed?
I have consulted several answers:
Python: modifying property value
How do you change the value of one attribute by changing the value of another? (dependent attributes)
EDIT:
According to some answers (see bellow) I am in an infinite loop. So I delete the part of the setter. I remain with:
class Circle():
def __init__(self,radius):
self._radius = radius
#property
def radius(self):
return self._radius
#property
def area(self):
return 3.14*self.radius*self.radius
What happens then is:
c = Circle(3)
c.radius = 30
error: AttributeError: can't set attribute
After the comments posted here this is the answer with exploratory explanation:
class Circle():
def __init__(self, _radius, color):
print('init run')
self._radius = _radius
self.color = color
#property
def radius(self):
print('property radius run')
return self._radius
#radius.setter
def radius(self, value):
print('setter radius run')
self._radius = value
#property
def area(self):
print('property AREA run')
return 3.14*self.radius*self.radius
I added print statements because if you want to find out what really happens I recommend you to run this code in separate cells in a notebook:
c= Circle(3,'azul') # here only __init__ runs
print(c.radius) # here property radius run
print(c.area)
This is the interesting part. When printing c.area things happen. Before running the code think about what do you think it would happenI was surprised but relieved because I understood now the functioning.
This is what happens: property AREA run, property radius run, property radius run.
My lessons learnt: Accessing the radius property is done via the method. This WAS NOT AT ALL OBVIOUS FOR ME.
Now try to change the radius
c.radius = 56 # setter method runs
print(c.area) # the same ass before.
Suppose I have a base class with unimplemented methods as follows:
class Polygon():
def __init__(self):
pass
def perimeter(self):
pass
def area(self):
pass
Now, let's say one of my colleagues uses the Polygon class to create a subclass as follows:
import math
class Circle(Polygon):
def __init__(self, radius):
self.radius = radius
def perimeter(self):
return 2 * math.pi * self.radius
(H/Sh)e has forgotten to implement the area() method.
How can I force the subclass to implement the parent's area() method?
this could be your parent class:
class Polygon():
def __init__(self):
raise NotImplementedError
def perimeter(self):
raise NotImplementedError
def area(self):
raise NotImplementedError
although the problem will be spotted at runtime only, when one of the instances of the child classes tries to call one of these methods.
a different version is to use abc.abstractmethod.
from abc import ABC, abstractmethod
import math
class Polygon(ABC):
#abstractmethod
def __init__(self):
pass
#abstractmethod
def perimeter(self):
pass
#abstractmethod
def area(self):
pass
class Circle(Polygon):
def __init__(self, radius):
self.radius = radius
def perimeter(self):
return 2 * math.pi * self.radius
# def area(self):
# return math.pi * self.radius**2
c = Circle(9.0)
# TypeError: Can't instantiate abstract class Circle
# with abstract methods area
you will not be able to instantiate a Circle without it having all the methods implemented.
this is the python 3 syntax; in python 2 you'd need to
class Polygon(object):
__metaclass__ = ABCMeta
also note that for the binary special functions __eq__(), __lt__(), __add__(), ... it is better to return NotImplemented instead of raising NotImplementedError.
You can raise NotImplementedError exception in base class method.
class Polygon:
def area(self):
raise NotImplementedError
Also you can use #abc.abstractmethod, but then you need to declare metaclass to be abc.ABCMeta, which would make your class abstract. More about abc module
That's exactly what NotImplementedError are used for :)
In your base class
def area(self):
raise NotImplementedError("Hey, Don't forget to implement the area!")
The task is to define a class named 'Shape' and its subclass 'Square'. The Square class has an 'init' function which takes a given length as an argument. Both classes have an area function which can print the area of the shape, where Shape's area is 0 by default.
This is what I have at the moment:
class Shape:
area = 0
def __init__(self, ??):
class Square(Shape):
def __init__(self, length):
self.length = length
def area(self):
a = (self.length * self.length)
print('The area of a square with a side length of %f is %f' % (self.length, a))
s = Square(2)
s.area()
I am unsure of what to do in the Shape superclass.
I guess that you want to override the default function area in the Shape class. Then, when you have a list of shapes - some Shape, some Square and may be even some Polygon, you can print them all just by calling area without knowing which class it is. Polymorphism!
class Shape:
def __init__(self):
pass
def area(self):
print(0)
It is also important to invoke constructor of the super class when creating an instance of the subclass. There may be some necessary initiation for the inner structure of the superclass:
class Square:
def __init__(self, length):
self.length = length
super(Square, self).__init__()
I'm starting to define my Entity classes for a game I am writing. However, I want a lot of code re-use. I want to define classes for different functionality, and then have classes which 'have' some of these classes' functionality.
For example:
class Collidable:
def handle_collision(other, incident_vector):
pass
def __init__(self, shape):
self.shape = shape
class Movable:
def update_position(self):
self.velocity += self.acceleration
self.position += self.velocity
def __init__(self, velocity, acceleration):
self.velocity, self.acceleration = velocity, acceleration
class Drawable:
def draw(self):
pass
def __init__(self, image):
self.image = image
class Controllable:
def key_down(self, key):
pass
def __init__(self):
pass
Then have a Player class which is Collidable, Movable, Drawable, Controllable, an Invisible Barrier which is only Collidable, a Background which is only Drawable, etc. I've heard of many different ways of connecting multiple classes, (such as via Composition, (Multiple) Inheritance, Interfaces, etc), but I don't know which is most appropriate and/or pythonic for this situation.
Mix-ins (special case of Multiple Inheritance) looks to be what I'm looking for (since a Player should BE a Collidable, a Movable, a Drawable, and a Controllable), but in trying this out, I'm finding difficulty in using super to pass the right arguments to the right init functions.
Edit:
I'm using python 3.2.
Mixins are the way to go, but you don't want to call __init__ on them:
class CollidableMixin(object):
#...
def init_collidable(self, shape):
self.shape = shape
class MovableMixin(object):
#...
def init_movable(self, velocity, acceleration):
self.velocity, self.acceleration = velocity, acceleration
class DrawableMixin(object):
#...
def init_drawable(self, image):
self.image = image
As I see it, you don't need a separate class for Controllable because it just defines an interface which the inheriting class should have. While you do that a lot in statically typed languages like Java, you don't need that in Python. Instead, you just define a key_down method and be done with it. This is called duck typing.
In an example implementation, this will then look like this:
class Player(CollidableMixin, DrawableMixin, MovableMixin):
def __init__(self):
self.init_collidable(...)
self.init_drawable(...)
self.init_movable(...)
def key_down(self, key):
# ...
objects = []
objects.append(Player())
# ... add some more objects. Later we iterate through that collection,
# not knowing which of them is a player:
for o in objects:
try:
o.key_down(...)
except AttributeError:
pass
Here is a simple way to implement the inheritance using super(). For this to work you will always need to create instances of Player (and other classes that inherit from your ***able classes) with keyword arguments. Each base class will strip whatever keyword arguments it is using from kwargs and pass the rest on to the next __init__() in the mro, for example:
class Collidable(object):
def handle_collision(other, incident_vector):
pass
def __init__(self, shape, **kwargs):
self.shape = shape
super(Collidable, self).__init__(**kwargs)
class Movable(object):
def update_position(self):
self.velocity += self.acceleration
self.position += self.velocity
def __init__(self, velocity, acceleration, **kwargs):
self.velocity, self.acceleration = velocity, acceleration
super(Movable, self).__init__(**kwargs)
class Drawable(object):
def draw(self):
pass
def __init__(self, image, **kwargs):
self.image = image
super(Drawable, self).__init__(**kwargs)
class Controllable(object):
def key_down(self, key):
pass
def __init__(self, **kwargs):
super(Controllable, self).__init__(**kwargs)
Then you could define your Player class:
class Player(Collidable, Movable, Drawable, Controllable):
pass
And use it like this:
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0
If you need additional instance variables for the Player class you would define an __init__() similar to the other classes, for example:
class Player(Collidable, Movable, Drawable, Controllable):
def __init__(name, **kwargs):
self.name = name
super(Player, self).__init__(**kwargs)