Converting code from Py3.0 to 2.7Py Super() and Print Statement - python

So I've got this piece of code from this nice guy at redblob games ( http://www.redblobgames.com/) and I'm having some difficulties converting his Py3.0 code to Py2.7.
The code can be found here. It is quite large so I get if you don't want to look at it: (http://www.redblobgames.com/pathfinding/a-star/implementation.py)
If you can please suggest some changes I can make to it that would be greatly appreciated. Currently I've found 3 errors, 2 of which are syntax which I don't really understand.
Syntax 1
def from_id_width(id, *, width):
The error is the "*,"
Syntax 2
print("%%-%ds" % width % draw_tile(graph, (x, y), style, width), end="")
the error is the end=""
Type Error
class GridWithWeights(SquareGrid):
def __init__(self, width, height):
super().__init__(width, height)
self.weights = {}
super() takes at least 1 argument (0 given)
But when I put GridWithWeights in super():
TypeError: must be type, not classobj

To make from_id_width to work you need to remove the keyword arg marker *:
def from_id_width(id, width):
return (id % width, id // width)
print can be fixed with importing it from __future__:
from __future__ import print_function
Finally __init__ needs to call super bit differently:
class GridWithWeights(SquareGrid):
def __init__(self, width, height):
super(GridWithWeights, self).__init__(width, height)
self.weights = {}
And the parent class must be converted to new style class:
class SquareGrid(object):

Related

Class function returning 'None'

I am trying to learn class inheritance for OOP in python. The following code does what I want it to so far, but returns None after printing the pipe data when the function in the parent class is called. At first I didn't have the function returning the print statement, so I added in the return keyword, but that didn't get rid of the issue. I know it must be a return issue that I am overlooking. Any help would be appreciated.
import numpy as np
class piping:
def __init__(self, diameter, length):
self.d = diameter
self.len = length
def getPipeData(self):
return print('The pipe length is %.1fm, and the diameter is %.1fm.' % (self.len, self.d))
class hydrodynamics(piping):
def __init__(self, diameter, length, fluid, density):
super().__init__(diameter, length)
self.fluid = fluid
self.density = density
self.volume = self.getVolume()
def getVolume(self):
return np.pi*self.d**2/4
sec1 = hydrodynamics(1, 10, 'water', 1000)
sec2 = hydrodynamics(0.5, 30, 'water', 1000)
print(sec1.getPipeData())
print(sec2.getPipeData())
print(sec1.volume)
print(sec2.volume)
This is what is being returned...(as I said, everything works fine so far, except that I am having issues with the return None)
The pipe length is 10.0m, and the diameter is 1.0m.
None
The pipe length is 30.0m, and the diameter is 0.5m.
None
0.7853981633974483
0.19634954084936207
The output I was expecting is:
The pipe length is 10.0m, and the diameter is 1.0m.
The pipe length is 30.0m, and the diameter is 0.5m.
0.7853981633974483
0.19634954084936207
If that really is what you want from your program then you could change your calling code to this:
sec1.getPipeData()
sec2.getPipeData()
print(sec1.volume)
print(sec2.volume)
However, better is to not print anything inside member functions. If you change your class to the following, you can keep your driving code as is.
class piping:
def __init__(self, diameter, length):
self.d = diameter
self.len = length
def getPipeData(self):
return 'The pipe length is %.1fm, and the diameter is %.1fm.' % (self.len, self.d)
You should leave out the print statement in your definition of getPipeData and only return the string.
OR:
Call sec1.getPipeData() without the print, since the print will be executed when you call sec1.getPipeData()

What is a 'rect style object' and how do I implement it into my code?

I am trying to learn python by making a space game where you travel around the map fighting enemies(drones) that are randomly placed around the map. So far I have been successful in moving the playable spaceship around the map(with rotation), firing lasers, and blitting drones around the map(The drones follow the spaceship around). Though I don't entirely understand classes, I seem to have been able to pull it off so far.
Now, I want to input enemy hp with Laser/Drone collision. I gave the Drone class self.rect = self.image.get_rect() and called an instance of it in the Laser1 class using self.c = pygame.Rect.colliderect(drone.rect) but it just gives me this:
Traceback (most recent call last):
File "space.py", line 85, in <module>
blist.append(Laser1 (beamx, beamy))
File "space.py", line 79, in __init__
self.c = pygame.Rect.colliderect(drone.rect)
TypeError: Argument must be rect style object
I have searched a lot online for a way to fix this but I don't understand it much and nothing seems to work for me. Any help would be greatly appreciated!
Here is my code:
class Drone:
def __init__(self, dronex, droney):
self.x = dronex
self.y = droney
self.hp = dronehp
self.image = pygame.image.load("Androne.png").convert_alpha()
self.rect = self.image.get_rect()
dlist = []
for i in range(10):
dronex = random.randint(0, 7700)
droney = random.randint(0, 4520)
dronehp = 3
dlist.append(Drone (dronex, droney))
drone = Drone(dronex, droney) #-----------instance i think...
class Roid:
def __init__(self, roidx, roidy):
self.x = roidx
self.y = roidy
self.type = random.randint(0, 2)
rlist = []
for i in range(811):
roidx = random.randint(-1000, 9104)
roidy = random.randint(-800, 7200)
rlist.append(Roid (roidx, roidy))
class Laser1:
def __init__(self, beamx, beamy):
self.x = beamx
self.y = beamy
self.laser1 = pygame.image.load("laser1.png").convert_alpha()
self.rect = self.laser1.get_rect()
self.c = pygame.Rect.colliderect(drone.rect) #---line 79...
blist = []
for i in range(2):
beamx = batx
beamy = baty
blist.append(Laser1 (beamx, beamy)) #---line 85...
class Laser2:
def __init__(self, beamx2, beamy2):
self.x2 = beamx2
self.y2 = beamy2
self.laser1 = pygame.image.load("laser1.png").convert_alpha()
self.rect = self.laser1.get_rect()
self.c = pygame.Rect.colliderect(drone.rect)
b2list = []
for i in range(2):
beamx2 = batx
beamy2 = baty
b2list.append(Laser2 (beamx2, beamy2))
Also, this is my first question to ask on here. If there is anything I can do to make this question better do tell. I will except any and all feedback!
To answer the title: A rect style object is a pygame.Rect, a tuple or a list with 4 elements. So you can usually pass a 4-tuple or list to methods that expect a pygame.Rect as well.
As Paul Cornelius mentioned, the exception is raised because you use the colliderect method of the pygame.Rect class, but should instead use the colliderect of the self.rect instance.
self.c = self.rect.colliderect(drone.rect)
You can actually use pygame.Rect.colliderect directly and pass the two rects that you want to check, but that's unusual and would be a bit confusing for everyone else.
# `self.rect` is passed as the `self` argument.
self.c = pygame.Rect.colliderect(self.rect, drone.rect)
Paul Cornelius is in the right direction. Since you're learning python I'll explain briefly. The colliderect method is implemented in C:
static PyObject*
rect_colliderect (PyObject* oself, PyObject* args)
{
PyRectObject* self = (PyRectObject*)oself;
GAME_Rect *argrect, temp;
if (!(argrect = GameRect_FromObject (args, &temp)))
return RAISE (PyExc_TypeError, "Argument must be rect style object");
return PyInt_FromLong (DoRectsIntersect (&self->r, argrect));
}
Since you called it through the class definition and not an instance, drone.rect was assigned to oself by the python wrapper to this method, and args was probably assigned some equivalent of NULL. Hence the error message you saw (and not a 'missing required positional argument' as one would expect).
Don't have any experience with Pygame, but with a little searching it seems the problem you are having is a result of passing an improper argument to your pygame.Rect.colliderect() on line 79. The object you are passing the pygame.Rect.colliderect() method is not being read as a Rectangle object. Try printing the object drone.rect data and object type to see where the problem might be.

Python - AttributeError

So for a line class I'm doing, I keep getting an error that says
AttributeError: Line instance has no attribute 'point0'
I'm declaring the line like this:
def __init__(self, point0, point1):
self.x = point0
self.y = point1
def __str__(self):
return '%d %d' % (int(round(self.point0)), int(round(self.point1)))
And I get the x and y from my point class which should already be float values so I don't need to check for an error in my init method however I do check to see if point0 and point1 are floats in my rotate method:
def rotate(self, a):
if not isinstance(a, float) or not isinstance(self.point0, float) or not isinstance(self.point1, float):
raise Error("Parameter \"a\" illegal.")
self.point0 = math.cos(a) * self.point0 - math.sin(a) * self.point1
self.point1 = math.sin(a) * self.point0 + math.cos(a) * self.point1
So why does python keep saying that it has no attribute point0? I also tried changing my init method to look like this:
def __init__(self, point0, point1):
self.point0 = point0
self.point1 = point1
But when I do that the error says point0 has no attribute float. So why do I keep getting this error? Here's the code I'm using to test:
p0 = Point(0.0, 1.0)
p1 = Point(2.0, 3.0)
line = Line(p0,p1)
print line
I'm curious... how much do you know about scope in Python?
In your class, you have a member variable named x and another named y. Your init function accepts an argument called point0 and another called point1. It saves point0 in the x member variable, and point1 in y. Then, in your rotate function, you attempt to access a variable called point0. Do you see the problem?
An important thing to understand when programming (and this is true in most programming languages, if not all of them) is that the name of an argument doesn't affect the name of that data elsewhere. I can pass a variable called foo into a function that takes an argument called bar. In that function, I have to refer to the data as bar because that's the name of the variable. Later, after I've called that function, the name of the variable is still foo, because only the variable inside the function is called bar. Does that make sense?
your class accept point0 and point1 parameters when you call it. If you want to get values of these parameters you should use self.x(for point0) and self.y(for point1)
or another way;
class Line:
def __init__(self, point0, point1):
self.point0 = point0
self.point1 = point1
I suggest you to read;
Python __init__ and self what do they do?
https://www.ibiblio.org/swaroopch/byteofpython/read/class-init.html
https://docs.python.org/2/tutorial/classes.html
A few overall points before displaying your corrected code. (Note that not much actually changed):
Don't bother checking argument types. Python programmers are assumed to be responsible enough to read the documentation and pass values of the correct value.
Your Line class was duplicating code that you had already defined in the Point class. The attributes of a line are Point instances, so you can use the methods you defined to implement the Line methods.
There's no reason to round the point coordinates to integers when displaying them; show the actual floating-point values that define the point. Your Line.__str__ method can take advantage of the fact that you've defined Point.__str__.
And now, your much shorter and corrected code, with some interspersed comments.
import math
class Point:
def __init__(self, x, y):
'''x and y should be floats'''
self.x = x
self.y = y
def rotate(self, a):
'''Rotate the point around the origin by a radians'''
self.x = math.cos(a) * self.x - math.sin(a) * self.y
self.y = math.sin(a) * self.x + math.cos(a) * self.y
# If you *were* going to check if a is a float, you
# need to do it *before* you use it.
def scale(self, f):
'''Scale the point by f units''' # you get the idea
self.x = f * self.x
self.y = f * self.y
def translate(self, delta_x, delta_y):
self.x = self.x + delta_x
self.y = self.y + delta_y
def __str__(self):
# If you're storing floats, it's probably useful
# to output them.
return '(%f, %f)' % (self.x, self.y)
# Operations on a line all involve applying the same operations
# to each of its end points.
class Line:
def __init__(self, point0, point1):
self.point0 = point0
self.point1 = point1
def rotate(self, a):
self.point0.rotate(a)
self.point1.rotate(a)
def scale(self, factor):
self.point0.scale(factor)
self.point1.scale(factor)
# If for whatever reason you didn't want to use Point.scale
# here, the code would be...
# self.point0.x = f * self.point0.x
# self.point0.y = f * self.point0.y
# self.point1.x = f * self.point0.x
# self.point1.y = f * self.point0.y
def translate(self, delta_x, delta_y):
self.point0.translate(delta_x, delta_y)
self.point1.translate(delta_x, delta_y)
def __str__(self):
# You've already defined out to turn a Point into
# a string, so you can take advantage of that here.
return "%s -- %s" % (self.point0, self.point1)
I'm going to add another answer here, both because I lack the reputation to comment on the other answer and because I feel this answer is unrelated to my previous answer (which addressed a different problem than what you're seeing now).
So. That said, look at this line of code:
return '%d %d' % (int(round(self.point0)), int(round(self.point1)))
round is a function that takes a numeric argument. However, self.point0 and self.point1 are not numbers. They are points. If you want the numbers from them, you'll have to refer to those explicitly (i.e. self.point0.x).

Pygame, inheritance issue

I am either new nor experience in python and i find myself in a fat problem that even after many hours in Google and Bing i can find the answer for. My problem starts with this code:
class Rectangulo(object):
def __init__ (self, x, y, color, largo, alto, cambio_x, cambio_y):
self.alto = alto
self.largo = largo
self.color = color
self.cambio_x = cambio_x
self.cambio_y = cambio_y
self.x = x
self.y = y
def dibujar(self):
pygame.draw.rect(pantalla, self.color, (self.x, self.y, self.alto, self.largo))
def mover(self):
self.x += self.cambio_x
self.y += self.cambio_y
class Elipse(Rectangulo):
def __init__(self):
Rectangulo.__init__(self)
def dibujar (self):
pygame.draw.ellipse(pantalla, Rectangulo.color,(Rectangulo.x, Rectangulo.y, Rectangulo.alto, Rectangulo.largo))
THis is the most important piece of code right now. I have find the problem laid in Elipse and have tried many ways to make the inheritance to work, but the console continue showing this message.
Traceback (most recent call last):
File "/home/josh/Escritorio/Codigo python/Jueguito.py", line 63, in <module>
miEl = Elipse(x,y,VERDE,alto,largo,cam_x,cam_y)
TypeError: __init__() takes 1 positional argument but 8 were given
Everytime i tried to call the class function dibujar() with this code:
for item in range(10):
x = random.randrange(685)
y = random.randrange(485)
alto = random.randrange(20, 71)
largo = random.randrange(20, 71)
cam_x = random.randrange(1, 2)
cam_y = random.randrange(-3, 3)
miObjeto = Rectangulo(x,y,VERDE,alto,largo,cam_x,cam_y)
miLista.append(miObjeto)
miEl = Elipse(x,y,VERDE,alto,largo,cam_x,cam_y)
miEl variable used to have their own for loop but i thought in this way would be less confusing for me. I still can't figure out what is happening. I fear i need some help.
Your Eclipse instance is failing to initialise, because when it calls the initialise of its base class Rectangulo, that class takes 7 parameters (x, y color, ... etc) and you aren't providing any.
So you have a number of options, but the two most common approaches would be:
Pass the same 7 params into Eclipse's __init__ method, and then pass those same params into the call to Rectangulo.__init__(self, ...)
Decide on the params to be used for the Rectangulo within the Elipse e.g. Rectangulo.__init__(self, 1, 2, "red", ...).
Generally speaking you will probably want the first option. e.g.
class Elipse(Rectangulo):
def __init__(self, x, y, color, largo, alto, cambio_x, cambio_y):
Rectangulo.__init__(self, x, y, color, largo, alto, cambio_x, cambio_y)
If your Elipse class needs no additional parameters of its own, then you can simplify the above a little by doing this:
class Elipse(Rectangulo):
def __init__(self, *args, **kwargs):
Rectangulo.__init__(self, *args, **kwargs)
This will basically pass any and all arguments given to the instantiation of Elipse through to the Elipse.__init__ call.

How do I rewrite this function now that it needs to call upon a method in a class from a different file?

Here is the function (it's in a file, "worldmodel.py"):
def add_entity(world, entity):
pt = entities.get_position(entity)
if within_bounds(world, pt):
old_entity = occ_grid.get_cell(world.occupancy, pt)
if old_entity != None:
entities.clear_pending_actions(old_entity)
occ_grid.set_cell(world.occupancy, pt, entity)
world.entities.append(entity)
And here is the class in a file named, "occ_grid.py":
class Grid:
def __init__(self, width, height, occupancy_value):
self.width = width
self.height = height
self.cells = []
# initialize grid to all specified occupancy value
for row in range(0, self.height):
self.cells.append([])
for col in range(0, self.width):
self.cells[row].append(occupancy_value)
def set_cell(self, point, value):
self.cells[point.y][point.x] = value
My question is, how would I rewrite the line of code in "def add_entity" that refers to "set_cell"? (Now that I've made set_cell a method of the class Grid) NOTE: Before I made set_cell part of the grid class, it was a function outside of the class (but still in the same file as the class) Thanks!
You'll need to import occ_grid in your worldmodel.py, then instantiate a Grid object and call that objects set_cell()-method. The add_entity needs to get the Grid-object as its parameter unless it can safely instantiate new ones at will.
Here's a naive example which does not work but demonstrates what I mean:
import occ_grid
g = occ_grid.Grid(your_width, your_height, occupancy)
def add_entity(world, entity, grid):
pt = entities.get_position(entity)
if within_bounds(world, pt):
old_entity = grid.get_cell(world.occupancy, pt)
if old_entity != None:
entities.clear_pending_actions(old_entity)
grid.set_cell(world.occupancy, pt, entity)
world.entities.append(entity)
add_entity(world, entity, g)
Unless you make the set_cell function a static method of the Grid class, you're going to need and instance of Grid.
from occ_grid import Grid
I am going to make an assumption here, and say that your want your grid to be part of the world? Either way, this is an example of instantiating that class.
class World:
grid = Grid()
def add_entity(world, entity):
# All that other stuff.
world.grid.set_cell(pt, entity)
There are two issues here, (1) calling functions across modules and (2) calling methods of classes.
It seems you can already do (1).
The trick is that although methods are defined as
def methodName(self, ...)
They are called as
object.methodName(...)
And object implicitly becomes the "self" Parameter. Here is an example:
import occ_grid # Import the module (file) that contains Grid.
.
.
world.occupancy = occ_grid.Grid() # Create an instance of Grid.
.
.
def add_entity(world, entity):
pt = entities.get_position(entity)
.
.
world.occupancy.set_cell(pt, entity)
In this example, grid is a global variable, which is probably not a good design. I guess it should be a property of world, but that's only a guess.

Categories