I have class Dot
class Dot:
def __init__(self, x, y):
self.x=x
self.y=y
I have class Cluster
class Cluster:
ic=0
List=[Dot]
colour=0
def __init__(self, Dot):
self.List[self.ic]=Dot
self.ic=self.ic+1
def includeDot(self, Dot):
self.List[self.ic]=Dot
self.ic=self.ic+1
Which include list of dots(List).
And I have class ClusterMaker where is list of clusters(and some other procedures, but this is not important for this question)
class ClusterMaker:
total=0
i=0
CList=[Cluster]
def addCluster(self,Cluster):
self.CList.append(Cluster)
Finally, there is button on my form which starts creating dots and clusters
def onChoose(self):
# ClMaker=ClusterMaker()
self.total=self.ent.get().strip() #how many dots we haver
self.CM=ClusterMaker()
i=0
while (i < int(self.total)):
dot=Dot(randint(0, 575), randint(0,670))
clst=Cluster(dot)
clst.colour= randrange(100, 999, 15)
self.CM.addCluster(clst)
box.showerror('j', str(str(self.CM.CList[i].List[0].x)+str(clst.List[0].x)))
this box shows us x coord of every dot in our cluster list
self.canvas.create_oval(clst.List[0].x, clst.List[0].y, clst.List[0].x+10, clst.List[0].y+10, fill=str("#"+str(clst.colour)))
i=i+1
b=0
while(b<6):
box.showerror('j', str(self.CM.CList[b].List[0].x))
and this box shows us x coords too
b=b+1
But what is going on in my lists? Why when I ask to show x coords for the second time it show the same x coord for all dots in all clusters?
Class attributes are instantiated once and shared between instances. You have to create fresh list in __init__:
def __init__(self, Dot):
self.List = [Dot]
self.List[self.ic]=Dot
self.ic=self.ic+1
Related
This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 7 months ago.
I have code that creates a "Box" object, with a unique number assigned to each Box, then a unique number assigned as the contents for each Box. multiple boxes then make up a "Room" object.
Here's the thing, when I run multiple iterations to create a new Room object, each room iteration creates the exact same room object. By running this code, you see that box 0 prints the same for every iteration. Why is that, and how can I get a unique combination of box contents on each iteration?
import random
class Box:
def __init__(self, box_number, box_content):
self.number = box_number
self.content = box_content
def __str__(self):
return f"Box: {self.number} | Content: {self.content}"
class Room:
boxes = []
def __init__(self, num_of_boxes):
box_contents = [*range(num_of_boxes)]
random.shuffle(box_contents)
for i in range(num_of_boxes):
self.boxes.append(Box(i + 1, box_contents[i] + 1))
def run_cycle():
room = Room(5)
print(room.boxes[0])
for _ in range(5):
run_cycle()
class Room:
def __init__(self, num_of_boxes):
self.boxes = []
...
def 'boxes' inside init belong to an instance.
Your code's all Room instance has same box attrib which belong to class.
When i try to put my objects into a list, i can not get an output with object names, it gives a weird output like "_ main _.object at 0x029E7210". I want to select my objects randomly to blit ONE of them onto the screen. But i could not figure this out.
car_main = pygame.image.load("car_main.png")
car_red_ = pygame.image.load("car_red.png")
car_blue = pygame.image.load("car_blue.png")
class cars:
def __init__(self,x,y,car_type,w=50,h=100,s=5):
self.x = x
self.y = y
self.w = w
self.h = h
self.s = s
self.car_type = car_type
def draw(self):
dp.blit(self.car_type,(self.x,self.y))
car1 = cars(x,y,car_main)
car2 = cars(x,y,car_red)
car3 = cars(x,y,car_blue)
car_list = [car1,car2,car3]
rc = random.choice(car_list)
print(rc)
# output> __main__.object at 0x02A97230
When I change
car_list = [car1,car2,car3] with;
car_list = [car1.car_type,car2.car_type,car3.car_type]
# output > Surface(50x100x32 SW)
But I want to see an output as my object names. Not as a string type ("car_main"). I want to get an output as the object name (car_main) directly. Because in the main loop, i will choose one of them to blit onto the screen everytime when the loop renews itself.
You need to define __str__ for your class Car to let it properly handle object to string:
class Car:
def __str__(self):
for k, var in globals().items():
if var == self:
return k
# default
return "Car"
Note1: Usually use uppercased Car for a class and car for an instance.
Note2: Look up variable strings in globals is not reliable. You may not want to make all variables global, and manually search them in scope is tedious. Actually why don't you give your Car a name attribute? Then you nicely have:
class Car:
def __init__(self, name):
self.name=name
def __str__(self):
return self.name
car = Car(name='first car')
print(car) # 'first car'
More read about "magic methods": https://rszalski.github.io/magicmethods/#representations
Add a __str()__ magic method to your car class like so:
def __str__(self):
return f'car with x of {self.x}, y of {self.y}, and type of {self.car_type}'
I wanted to know what the modules you recommend for plotting lists of coordinates on the X-Y plane are. The purpose is to implement Game of Life; I've tried matplotlib.pyplot but I've got some issues with axes ratio and in general it doesn't seem like the best way to plot some sort of animation. The main idea in the script is to plot the world in which the cells live, with a tick given from time.sleep.
import matplotlib.pyplot as plt
class Cell:
#Cell class, with coordinates and an ON-OFF state
def __init__(self,x=0,y=0,state=0):
self.state=state
self.x=x
self.y=y
self.coord=[self.x,self.y]
def __repr__(self):
if self.state:
return "*"
else:
return " "
#methods to turn on and off the cells:
def turn_on(self):
self.state=1
return self
def turn_off(self):
self.state=0
return self
class Mondo:
#the world in which the cells live:
def __init__(self,width=10,height=30,starting_cells=[]):
self.width=width
self.height=height
self.grid=[[Cell(i,j) for j in range(height)] for i in range(width)]
for cell in starting_cells:
self.grid[cell.x][cell.y]=cell
def __repr__(self):
#this method is needed just if I wanted to use just the print statement instead of matplotlib
return "_"*(2*self.height+3)+"\n"+"\n".join([" ".join(["|"]+[" "+str(cell)+" " for cell in self.grid[row]]+["|"]) for row in range(self.width)])+"\n"+"_"*(2*self.height+3)
def plotlib(self):
#this is the best I can do:
Xaxis=[cell.x for i in range(self.width) for cell in self.grid[i] if cell.state]
Yaxis=[cell.y for i in range(self.width) for cell in self.grid[i] if cell.state]
plt.axis([0,self.width, 0, self.height])
return plt.show(plt.scatter(Xaxis,Yaxis,c="000000", marker='s'))
def __getitem__(self,row):
return self.grid[row]
def pos_cell(self,coord):
#retrieves the cell given the coordinates
return self.grid[coord[0]][coord[1]]
def cell_state(self,coord):
#outputs the cell's state on given coord
return self.pos_cell(coord).state
def neighbors_state(self,coord,cont=0):
#sums the neghbors' cell state
cell=self.pos_cell(coord)
x,y=cell.x,cell.y
for hor in [-1,0,1]:
for ver in [-1,0,1]:
if not hor==ver==0 and (0<=x+hor<self.width and 0<=y+ver<self.height):
cont+=self.cell_state([(x+hor)%self.width,(y+ver)%self.height])
return cont
def alive_dead(self,coord):
#for each cell, tells wether it must switch its state or not
cell=self.pos_cell(coord)
if not cell.state:
if self.neighbors_state(cell.coord)==3:
return True
else:
return False
elif cell.state:
if self.neighbors_state(cell.coord) in [2,3]:
return True
else:
return False
#NB starting cells must be given as a list, not as a grid
def game_of_life(width,height,starting_cells):
#the heart of the script
test=[[Cell(i,j) for j in range(height)] for i in range(width)]
world=Mondo(width,height,starting_cells)
world.plotlib()
for i in range(world.width):
for j in range(world.height):
if world.alive_dead([i,j]):
test[i][j].turn_on()
starting_cells=[test[i][j] for i in range(width) for j in range(height)]
plt.pause(0.5)
return game_of_life(width,height,starting_cells)
#Example of an oscillator:
#print game_of_life(10,10,[Cell(1,2,1),Cell(2,3,1),Cell(3,1,1),Cell(3,2,1),Cell(3,3,1)])
#Example of the Gosper gun:
gosper=[[Cell(i,j) for j in range(70)] for i in range(30)]
for i in range(len(gosper)):
for j in range(len(gosper[0])):
if [i,j] in [[1,26],[2,24],[2,26],[3,14],[3,15],[3,22],[3,23],[3,36],[3,37],[4,36],[4,37],[4,22],[4,23],[4,13],[4,17],[5,12],[5,18],[5,22],[5,23],[5,1],[5,2],[6,1],[6,2],[6,12],[6,16],[6,18],[6,19],[6,24],[6,26],[7,26],[7,18],[7,12],[8,13],[8,17],[9,14],[9,15]]:
gosper[i][j].turn_on()
gosp=[gosper[i][j] for i in range(len(gosper)) for j in range(len(gosper[0])) if gosper[i][j].state]
print game_of_life(30,70,gosp)
#Mondo(30,70,gosp).plotlib()
#print Mondo(30,70,gosp)
I gave a look at the matplotlib.animation but maybe there's too much stuff for me to use just for a Uni assignment.
Is there some module I can use to print some simple animation? Should I try harder with matplotlib.pyplot, and if so, how can I adjust axes ratio and stuff?
SUrfing the questions I found the module graphics, may it be useful?
Thank you
I'm working under python pyramid, with Python3.
I have a model that looks like this:
class OneTimeCode(Base):
__tablename__ = 'otc_one_time_codes'
otc_one_time_code_id = Column(Integer, primary_key=True)
otc_one_time_code = Column(String(32))
otc_usr_user_id = Column(Integer, ForeignKey('usr_users.usr_user_id'), nullable=True)
otc_expire_time = Column(DateTime)
def __init__(self, otc_usr_user_id, otc_expire_time=None):
self.otc_usr_user_id = otc_usr_user_id
if otc_expire_time is None:
self.otc_expire_time = (datetime.now() + timedelta(6*365/12)).isoformat()
else:
self.otc_expire_time = otc_expire_time
#classmethod
def get_code(self, hlength=6):
seed = datetime.now() + timedelta(random.randrange(1,10000))
tmp_hash = hashlib.md5(seed.strftime("%Y-%m-%d %H:%M:%S.%F").encode('utf-8')).hexdigest()
if hlength == 32:
self.otc_one_time_code = tmp_hash
else:
self.otc_one_time_code = tmp_hash[0 : hlength]
print(self.otc_one_time_code)
The problem is, when I instantiate one of these objects and then explicitly call get_code, the print line at the end prints to the screen the code successfully.
However, in my view, if I explicitly try to print that property, it's 'None'
Here's what my view code looks like:
otc = OneTimeCode(
otc_usr_user_id = user.usr_user_id
)
otc.get_code()
pprint.pprint(vars(otc))
session.add(otc)
And the console output looks like this:
0d097c
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x50877d0>, 'otc_expire_time': '2015-02-13T10:56:14.244447', 'otc_usr_user_id': 1} 2014-08-14 22:56:14,245
INFO [sqlalchemy.engine.base.Engine][Dummy-2] INSERT INTO otc_one_time_codes (otc_one_time_code, otc_usr_user_id, otc_expire_time) VALUES (%(otc_one_time_code)s, %(otc_usr_user_id)s, %(otc_expire_time)s) RETURNING otc_one_time_codes.otc_one_time_code_id 2014-08-14 22:56:14,245
INFO [sqlalchemy.engine.base.Engine][Dummy-2] {'otc_one_time_code': None, 'otc_expire_time': '2015-02-13T10:56:14.244447', 'otc_usr_user_id': 1} 2014-08-14 22:56:14,247
INFO [sqlalchemy.engine.base.Engine][Dummy-2] COMMIT
You can see the value inside the model: 0d097c, and also the pprint object, where it doesn't look like the property exists.
Why can't I get access to this property?
Looks like you should be using a #property instead of a OTC, however it also seems like this may be something you DON'T want to calculate each time!
# for all the docstrings, let multi = Multi(2)
class Multi(object):
def __init__(self, attribute):
"""When instantiated, set self.attribute to attribute"""
self.attribute = attribute
#property
def attribute_times_ten(self):
"""accessed via multi.attribute_times_ten
and will return 20. Use properties to signify
a variable that requires some work done to it
that needs to calculated each time it's called."""
return attribute_times_ten
#classmethod
def times_ten(cls, num):
"""Not the best example, but a #classmethod will
give the class as its first argument, NOT the
instance. This is useful in lots of constructor
settings, e.g. CreateClass.fromstring("attributes")"""
return num * 5
def generate_number(self, multiplier):
"""This is just a normal method. This is what I think
you want, tbh, and you should probably call it in your
__init__ method since you NEED this to run in your OTC
for it to work as intended. Methods (like properties)
are automagically passed the instance as the first
argument, so we can CHANGE self.attribute with that."""
self.attribute = self.attribute * multiplier
Docstrings should be self descriptive, but:
multi = Multi(2)
multi.attribute_times_ten # returns 20
Multi.times_ten(8) # returns 80, note the capital M!
multi.generate_number(3) # self.attribute is now 6
multi.attribute_times_ten # returns 60
A real-world case where you might need all of the above:
class _Tile(object):
def __init__(self, x, y):
"""A naive implementation of Tile that doesn't care
what its side length is and doesn't have any properties
to hide its attributes"""
self.x = x
self.y = y
#classmethod
def tiles_to_pixels(cls, tile):
return cls(tile._x * tile.side_length, tile._y * tile.side_length)
#classmethod
def tiles_to_tiles(cls, tile):
return cls(tile._x, tile._y)
class Tile(object):
def __init__(self, x, y, side_length):
"""A tile object in a map"""
self._x = x # x-coord in tiles
self._y = y # y-coord in tiles
self.side_length = side_length # pixels per tile
#property
def in_pixels(self):
"""self.in_pixels returns an object whose .x and .y
correspond to the x and y position IN PIXELS of the
top-left corner of the tile."""
_tile = _Tile.tiles_to_pixels(self)
return _tile
#property
def in_tiles(self):
"""self.in_tiles returns an object whose .x and .y
correspond to the x and y position IN TILES of the
top-left corner of the tile."""
_tile = _Tile.tiles_to_tiles(self)
return _tile
def change_side_length(self, new_length):
"""Use to change the side length. This can break
your whole map since it's naive, so be careful."""
self.side_length = new_length
my_tile = Tile(0,0,32) # 32 pixel tile starting at (0,0)
my_tile.x # NameError, since it's called my_tile._x
my_tile.in_tiles.x # 0
my_tile.in_pixels.y # 0
other_tile = Tile(4,7,32) # 32 pixel tile starting at (4,7)
other_tile.y # NameError, see above
other_tile.in_tiles.y # 7
other_tile.in_pixels.x # 128
I'm having another problem with the game I'm making, I want the Asteroids sprite to be randomized every time I new asteroid is created by the spawner class, but I keep getting this error 'non-default argument follows default argument', and I'm pretty much stumped on what to do, The actual randomized image is stored inside the spawner and is then imported to the Asteroid class. Any help would be greatly appreciated, the images list is a global variable.
images = [games.load_image("asteroid_small.bmp"),
games.load_image("asteroid_med.bmp"),
games.load_image("asteroid_big.bmp")]
def check_drop(self):
""" Decrease countdown or drop asteroid and reset countdown. """
if self.time_til_drop > 0:
self.time_til_drop -= 0.7
else:
asteroid_size = random.choice(images)
new_asteroid = Asteroid(x = self.x,image = asteroid_size)
games.screen.add(new_asteroid)
And then this is the part of the asteroid class that the randomized image will be stored in
def __init__(self, x, y = 10,image):
""" Initialize a asteroid object. """
super(Asteroid, self).__init__(image = image,
x = x, y = y,
dy = Asteroid.speed)
Your problem isn't with how you instantiate the asteroid, it is how you define it:
def __init__(self, x, y = 10,image):
If you look, image is last, after y, which has a default argument. In Python you cannot do such things. You have two options:
def __init__(self, x, y = 10, image = None):
# default the argument to some sentinel value
# Test for sentinel and the reassign if not matched.
image = image if image else random.choice(images)
or
def __init__(self, x, image, y = 10):
# re-order your arguments.
# Also note that image, x, y might be a better order
# (#see comment by Micael0x2a)