Hi Im just starting to learn OOP and I use python to do so. Recently I ve been trying to code a game. I ve declared class Character that should be general and from that class my other classes will inherit. Now Im trying to create a class Player, I want to inherit everything but 1 variable. Here is a code:
class Character:
def __init__(self, x, y, width, height):
self.width = width
self.height = width
self.x = x
self.y = y
self.vel = 3
self.right = False
self.left = False
self.walk_count = 0
self.is_jump = False
self.jump_count = 10
self.standing = True
class Player(Character):
def __init__(self, x, y, width, height, right, left, walk_count, is_jump, jump_count, standing):
super().__init__(x, y, width, height, right, left, walk_count, is_jump, jump_count, standing)
self.vel = 5
in super() I keep getting pylint error:
Too many positional arguments for method call.
But I think it lets me run it even with it.
Also I want to put in only self.x, self.y, self.width and self.height when initializing, should I declare these values in class Player or let it be in class Character?
Then here I try to create an instance of class Player:
man = Player(200,410,64,64)
And I got errors missing value for argument right, left, walk_count,
is_jump, jump_count, standing
I tought that if i set values for them in class Character that I dont need to put values in when creating instance, because I want to set them to default values at the creation and then I will change them if I need it.
Later I will add class Enemy that will inherit most of the parameters from class Character also.
Then, you must call the super method with the signature (number of parameters) desired.
Change
def __init__(self, x, y, width, height, right, left, walk_count, is_jump, jump_count, standing):
super().__init__(x, y, width, height, right, left, walk_count, is_jump, jump_count, standing)
self.vel = 5
to
def __init__(self, x, y, width, height):
super().__init__(x, y, width, height)
self.vel = 5
Or, if you prefer, change Character's __init__ to match the Player's super call, and change:
class Character:
def __init__(self, x, y, width, height):
to
class Character:
def __init__(self, x, y, width, height, right, left, walk_count, is_jump, jump_count, standing):
and leave the super call as is.
The best approach is to only pass what is needed. If the only needed values to parameterize your Character object are x,y,height,weight, then you should only pass them - the remaining will be set automatically (you don't need to give them as input, since they will be discarded).
So, the correct approach is the first I mentioned.
Related
This is just academic. Consider the following example:
class Shape():
def __init__(self, x, y):
self.x = x
self.y = y
def position(self):
return self.x, self.y
class Rectangle(Shape):
def __init__(self, x, y, height, width):
#super().__init__(x, y) # OK
self.x = x # not OK!
self.y = y # not OK!
self.height = height
self.width = width
r1 = Rectangle(1, 2, 3, 4)
If I asked someone to implement the class Rectangle, and they implemented with the "not OK" statements (instead of the with the "OK" statement as they should), then r1.x would be an attribute of Rectangle instead of Shape. Is there a way I can check if r1.x is a member of the Rectangle class or of the Shape class? Essentially, I want to make sure the initialization of the super class is being run, and no unnecessary new attributes are being created.
while programming a minigame, I stumbled across something I cant explain myself (fairly new to python).
This is my code:
class Block:
def __init__(self, x, y, hitpoints=1, color=(255, 0, 0), width=75, height=35):
self.color = color
self.x = x
self.y = y
self.height = height
self.width = width
self.hitpoints = hitpoints
class Ball(Block):
def __init__(self, x, y, size, color=(255, 255, 255), velocity=1):
super().__init__(self, x, y, color)
self.velocity = velocity
self.size = size
I initialize the object ball with
ball = Ball(x=200, y=200, size=30)
Problem arises when I call ball.x, as it returns
<Objects.Ball object at 0x00000249425A3508>.
If i call ball.y it works as intended and returns 200.
I can fix the whole problem by modifying the class Ball as follows:
class Ball(Block):
def __init__(self,x, y, size, color=(255, 255, 255), velocity=1):
super().__init__(self, y, color)
self.velocity = velocity
self.size = size
self.x = x
Can somebody explain to me why this happens?
Thanks alot!
You need to call super without self argument:
super().__init__(x, y, color=color)
This PEP explains how this works:
The new syntax:
super()
is equivalent to:
super(__class__, <firstarg>)
where __class__ is the class that the method was defined in, and
is the first parameter of the method (normally self for
instance methods, and cls for class methods).
I am just trying to get a program that receives a point from one class, and then in another class, it uses that point as the center of the circle. I imagine this is simple but I don't know how to do it.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Circle(Point):
def circle(self, center, radius):
Point.x = center
Point.y = center
self.radius = radius
You shouldn't subclass Point for your Circle class, it doesn't make much sense as they are two completely different things. Instead you can take a Point as the center of your circle and pass it into the Circle class in the init
class Circle(object):
def __init__(self, center: Point, radius):
self.center = center
self.radius = radius
The way you are doing it, with inheritance, is a bit confusing.
2 options are avalaible.
First : As mention by #Iain Shelvington, you could use the Point class as a member of your Circle class.
Second : If you really want to sub class it / inherit from the point in your circle, you have to super.init() it.
class Circle(Point):
def __init__(self, x, y, radius):
super().__init__(x, y) # which is the same as creating a self.x and y for Circle
self.radius = radius
Say I have the following class definition:
class WorldObject(pygame.sprite.Sprite):
#classmethod
def fromImgRect(cls, rect, image, collideable = True):
return cls(rect.left, rect.top, rect.width, rect.height, image, collideable)
def __init__(self, x, y, w, h, image, collideable = True):
self.rect = pygame.rect.Rect(x,y,w,h)
self.collideable = collideable
self.image = image
Then I have the following child class:
class Doodad(WorldObject):
def __init__(self,c1x, c1y, c2x, c2y, color = (200,0,180)):
self.color = color
self.rect = orderPoints(c1x, c1y, c2x, c2y)
x1 = self.rect.left
y1 = self.rect.top
w = self.rect.width
h = self.rect.height
super(Doodad, self).__init__(x1,y1,w,h,self.surface, False)
This works just fine, however it is annoying to have to unpack self.rect like this all throughout my code, instead of just doing it once in the class method. This is happening in many places throughout my project, where several of my methods return a rectangle object, but I need to pass coordinates to a super constructor. It doesn't look like its possible to have everything return either coordinates or a rectangle, sometimes it just makes more sense to do one or the other. Since python doesn't support overloading methods, I'd like to be able to use the class method to initialize the object. However I haven't been able to figure out the syntax. Is this possible? If so, how?
In your situation, I would add a method for "sub-initializing". This would post-process the given data:
class WorldObject(pygame.sprite.Sprite):
#classmethod
def fromImgRect(cls, rect, *a, **k):
return cls(rect.left, rect.top, rect.width, rect.height, *a, **k)
def __init__(self, x, y, w, h, image, collideable=True):
self._init_coords(x, y, w, h)
self.collideable = collideable
self.image = image
def _init_coords(self, x, y, w, h):
self.rect = pygame.rect.Rect(x,y,w,h)
Then you can have the following child class:
class Doodad(WorldObject):
def _init_coords(self, c1x, c1y, c2x, c2y):
self.rect = orderPoints(c1x, c1y, c2x, c2y)
def __init__(self,c1x, c1y, c2x, c2y, color=(200, 0, 180)):
super(Doodad, self).__init__(c1x, c1y, c2x, c2y, self.surface, False)
self.color = color
Besides, you might want to have
def unpack_rect(rect):
return rect.left, rect.top, rect.width, rect.height
You can even have
class WorldObject(pygame.sprite.Sprite):
def __init__(self, *a, **k):
if hasattr(a[0], 'left'):
rect = a[0]
self._init_coords(rect.left, rect.top, rect.width, rect.height)
rest = a[1:]
else:
self._init_coords(*a[0:4])
rest = a[4:]
self._init_rest(*rest, **k)
def _init_coords(self, x, y, w, h):
self.rect = pygame.rect.Rect(x,y,w,h)
def _init_rest(self, image, collideable=True):
self.collideable = collideable
self.image = image
class Doodad(WorldObject):
def _init_coords(self, c1x, c1y, c2x, c2y):
self.rect = orderPoints(c1x, c1y, c2x, c2y)
def _init_rest(color=(200, 0, 180)):
super(Doodad, self)._init_rest(self.surface, False)
self.color = color
(I didn't change self.surface here, but it is not defined at this moment. You should change that.)
I have the following code.py file:
class Shape:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, delta_x, delta_y):
self.x += delta_x
self.y += delta_y
class Square(Shape):
def __init__(self, side=1, x=0, y=0):
super().__init__(x, y)
self.side = side
class Circle(Shape):
def __init__(self, rad=1, x=0, y=0):
super().__init__(x, y)
self.radius = rad
I'm running the code in the Python interpreter like this:
>>> import code
>>> c = code.Circle(1)
I'm getting this error:
Traceback (most recent call last):<br>
...<br>
File "code.py", line 18, in __init__<br>
super().__init__(x, y)<br>
TypeError: super() takes at least 1 argument (0 given)<br>
I don't understand why I'm getting this error. I'm specifying a rad value of 1 and I would assume that since I didn't specify x and y values, Circle should be using the default values of x=0 and y=0 and passing them to Shape via the super() function. What am I missing?
BTW, I'm using Python 2.7.1.
Thanks.
super requires an argument and this is exactly what the error message is saying. In your case you need to use super(Circle, self) and super(Square, self).
For the gory details you can see this SO question or you can just check the official documentation.
Note that unless you want to do funny things the code can be simplified in
Shape.__init__(self, x, y)
in both cases. Until you understand super and why it can be useful I would suggest to simply stay away from it. You can live an happy life as a productive Python programmer without touching that.
Use super(Shape, self) instead, you can help(super) in python.
Finally fixed it. :D Searching through python docs and old Stackoverflow posts for the win.
class Shape(object):
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, delta_x, delta_y):
self.x += delta_x
self.y += delta_y
class Square(Shape):
def __init__(self, side=1, x=0, y=0):
super(Square,self).__init__(x, y)
self.side = side
class Circle(Shape):
def __init__(self, rad=1, x=0, y=0):
super(Circle,self).__init__(x, y)
self.radius = rad
c = Circle(5)
This works. You need to use new style classes by making the top parent (Shape) inherit from object.
References:
http://docs.python.org/reference/datamodel.html#newstyle
Chain-calling parent constructors in python
Here's some code that does what you need, you also need to be using the "new style class" meaning the base type needs to inherit from object:
class Shape(object):
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, delta_x, delta_y):
self.x += delta_x
self.y += delta_y
class Square(Shape):
def __init__(self, side=1, x=0, y=0):
super().__init__(x, y)
self.side = side
class Circle(Shape):
def __init__(self, rad=1, x=0, y=0):
super(Circle, self).__init__(x, y)
self.radius = rad
P.S. I only fixed Circle and left Square for you to fix.