I'm not sure if I'd be framing the question correctly but I'll try my best to explain my problem.
I have the code below where x and y are set to None in the beginning. In a new function, based on a condition, x and y are updated.
class problem()
def __init__(self):
self.x = None
self.y = None
def function(self):
if some_condition:
self.x = 10
self.y = 5
else:
self.x = None
self.y = None
The problem I have here is the total number of variables in __init__() are around 10 and all of these have to set to a value or reset back to original value based on the condition.
Is there a pythonic way to reset the variables back to original __init__() values when the if condition fails?
class problem():
def __init__(self):
self.reset()
def function(self):
if self.x == None:
self.x = 10
self.y = 5
else:
self.x = None
self.y = None
def reset(self):
self.x = None
self.y = None
# These prints will help you understand how it works
per = problem()
per.function()
print(per.x, per.y)
per.reset()
print(per.x, per.y)
As easy as it looks like.
I've entered reset() into init because it's just looks better.
Also i'm highly recommend to check Corey Schafer's OOP Python tutorials, he
explaining in best way i've heard.
Related
Looking for a touch of help. This is really a Pylance (in VSCode on a Mac) troubleshooting question...
I have a class that is essentially an XY coordinate and I would like to have a function that receives another instance of the class itself to check for proximity:
class coOrd:
def __init__(self, x, y, minProx):
self.x = x
self.y = y
self.minProx = minProx
def checkProx(self, coOrdToChk)->bool:
proximity = math.sqrt((self.x - coOrdToChk.x)**2 + (self.x - coOrdToChk.x)**2)
if proximity < self.minProx or proximity < coOrdToChk.minProx:
return False
return True
The code works, Pylance just has a persistent warning, but is there a way to use type hinting without getting errors from Pylance? It would make the remaining coding way easier with the typing suggestions and typo checking.
I tried this and it also works, but is very clunky. Basically declaring the class with the properties that you want to access in a sibling-referencing-function, then overwrite the whole thing again...
# Bulky pre-declaration
class coOrd:
def __init__(self, x, y, minProx):
self.x = x
self.y = y
self.minProx = minProx
class coOrd:
def __init__(self, x, y, minProx):
self.x = x
self.y = y
self.minProx = minProx
def checkProx(self, coOrdToChk:coOrd)->bool:
proximity = math.sqrt((self.x - coOrdToChk.x)**2 + (self.x - coOrdToChk.x)**2)
if proximity < self.minProx or proximity < coOrdToChk.minProx:
return False
return True
Is there another way to do this, or am I just wanting a feature that doesn't exist?
I found this pygame project online and was curious how 'moveSpeed' is being used as a number? like below?
def move(self, moveSpeed):
self.x -= moveSpeed
class HurdleManager:
def __init__(self, scale, spawnRange):
self.img = transform.scale(image.load('homework.png'), (7 * scale, 15 * scale))
self.spawnRange = spawnRange
self.hurdleList = []
self.scale = scale
def update(self, doSpawn, moveSpeed):
if doSpawn:
self.spawn()
self.manage(moveSpeed)
def manage(self, moveSpeed):
hurdles2 = []
for hurdle in self.hurdleList:
hurdle.update(moveSpeed)
if hurdle.onScreen():
hurdles2.append(hurdle)
self.hurdleList = hurdles2
spawnTick = 0
def spawn(self):
if self.spawnTick >= self.spawnRange[1]:
newHurdle = HurdleClass(windowX, self.img, 7 * self.scale, 15 * self.scale)
self.hurdleList.append(newHurdle)
self.spawnTick = 0
elif self.spawnTick > self.spawnRange[0]:
if random.randint(0, self.spawnRange[1] - self.spawnRange[0]) == 0:
newHurdle = HurdleClass(windowX, self.img, 7 * self.scale, 15 * self.scale)
self.hurdleList.append(newHurdle)
self.spawnTick = 0
self.spawnTick += 1
hurdleManager = HurdleManager(3, (45, 90))
class HurdleClass:
def __init__(self, x, img, width, height):
self.x = x
self.img = img
self.width = width
self.height = height
self.y = ground - height
def update(self, moveSpeed):
self.move(moveSpeed)
self.show()
def move(self, moveSpeed):
self.x -= moveSpeed
def show(self):
window.blit(self.img, (self.x, self.y))
def onScreen(self):
if self.x + self.width > 0:
return True
else:
return False
def move(self, moveSpeed):
def move says "I'm creating a function definition here. When I've finished defining it, I'd like the function to be bound to the name "move" in the current scope. Also, the function can use bindings from the current scope."
(self, moveSpeed) says "To run this function, I need two arguments. The first one is called self and the second one is called moveSpeed."
An argument is also known as a parameter. Just like when being asked to cut a cake, you might ask "Which cake?" and "Which knife?". In most programming languages, you pass parameters (also known as arguments) in the order each is declared. For example, given:
def cut(cake, knife):
...
writing cut(a, b) would "call" cut with the caller's "a" bound to the called function's "cake" variable and with the caller's "b" bound to the called function's "knife" variable.
In Python, you can also give the names of arguments explicitly. For example, cut(cake=a, knife=b) would do the same thing. These are called "keyword arguments." You don't need to pass things in declaration order when you use keyword arguments. For example, cut(knife=b, cake=a) would do the same thing as well.
I am programming a platformer, and trying to check if the player is in the air. If so, they fall down until they touch a platform, and then rise until they don't touch it anymore (so that they don't sink). To do this, I am checking whether the player's y position (plus height) is more than the platform's, referring to the whole 'platform' class, but this doesn't work:
Here is the initialisation code for the platform:
class platform(object):
def __init__(self, x, y, size):
self.x = x
self.y = y
self.size = size
And here is where I refer to it:
def touchGround(self):
while self.hitbox[1] + self.hitbox[3] > platform.y:
self.speedY -= 1
self.y += speedY
def fall(self):
while self.hitbox[1] + self.hitbox[3] < platform.y:
self.speedY += 1
self.y += speedY
touchGround()
However, I get an error:
AttributeError: type object 'platform' has no attribute 'y'
You need to create an instance of platform in order for it to have the y attribute. Here's a simpler example of why this is the case:
class Something:
def __init__(self, x, y):
self.x = x
self.y = y
if Something.y > 2:
print('success')
No values have been defined at all, so it's unreasonable that any kind of comparison could be made. We could fix this with:
my_something = Something(1, 3)
if my_something.y > 2:
print('success')
Or, you could fix it with defining a class variable:
class Something:
x = 1
y = 3
if Something.y > 2:
print('success')
In your case, I assume you will have multiple platforms, so defining x and y at the class level probably doesn't make sense, since you'll want multiple instances with different attributes.
Separately, please see PEP8 for naming conventions. These are important for clear understanding of code between people.
I think this question has been asked before but I have not found an answer suited to my problem. I basically have a class for different characters, which each have a cost. When creating a character, I want to take their cost away from the players score.
Here is an example of a class:
class Assassin(pygame.sprite.Sprite):
def __init__(self, x, y, row, column):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("assassin.png")
self.x = x
self.type = "assassin"
self.y = y
self.rect = self.image.get_rect(center=(self.x, self.y))
self.damage = 60
self.health = 40
self.speed = 2
self.move = False
self.cost = 4
self.row = row
self.column = column
And here is the code where I would want to use the variable:
if assassin.collidepoint(pygame.mouse.get_pos()) and mouseDown[0]:
for block in blockGroup:
if block.team1Taken == False and block.column ==1:
team1.add(Assassin(block.team1[0], block.team1[1], block.row, block.column))
block.team1Taken = True
score -= Assassin.__init__.cost #Example of what I think you would do
break
I hope I have explained this well enough to understand what I want.
You can't call score -= Assassin.__init__.cost in python.
The init method is the constructor of the Class and should be used to do so.
The value that you want is inside the object that you created, so you could call assassin.cost directly, assuming that assassin is the object.
So, you just need to change to:
if assassin.collidepoint(pygame.mouse.get_pos()) and mouseDown[0]:
for block in blockGroup:
if block.team1Taken == False and block.column ==1:
current_assassin = Assassin(block.team1[0], block.team1[1], block.row, block.column)
team1.add(current_assassin)
block.team1Taken = True
score -= current_assassin.cost
break
You will need to keep a reference to the Assassin instance you create and then access its cost attribute:
if assassin.collidepoint(pygame.mouse.get_pos()) and mouseDown[0]:
for block in blockGroup:
if block.team1Taken == False and block.column == 1:
new_assassin = Assassin(block.team1[0], block.team1[1],
block.row, block.column)
team1.add(new_assassin)
block.team1Taken = True
score -= new_assassin.cost
break
I have problem with my program. When I try to change object value (which is in list) I changed all object's value in that list.
My code:
class obj:
def __init__(self, x, y):
self.x = x
self.y = y
def mirrorise(self, mirror):
self.mirror = mirror
if self.mirror.type == 'teleporterx':
self.x -= (self.x-(self.mirror.x+self.mirror.x1/2))*2
class person(obj):
def __init__(self, x, y):
self.x = x
self.y = y
self.pos = [obj(self.x, self.y)]
def mirrored(self, mirrors):
self.count = 0
self.mirrors = mirrors
self.mens = 0
for men in self.pos:
self.mens += 1
for mirror in self.mirrors:
if self.count == 1:
for men in range(self.mens):
self.pos.append(self.pos[men])
self.count = 1
self.count = 0
for men in self.pos:
men.mirrorise(self.mirrors[self.count])
self.count += 1
if self.mirrors[self.count-1] == self.mirrors[-1]:
self.count = 0
class mirror:
def __init__(self, x, y, x1, y1, type):
self.x = x
self.y = y
self.x1 = x1
self.y1 = y1
self.type = type
After in code I call person object called I and two mirror objects called mirr and mirr2 with type teleportx. When I write:
I.mirrored([mirr, mirr2])
it changes x for all objects in I.pos. If I write
I.pos[3].mirrorise(mirr)
it still changes all x. Even if I write:
I.pos[3].x -= (I.pos[3].x-(mirr2.x+mirr.x1/2))*2
it changes all values. So, is it some Python rule or I have mistake?
You are adding references to your one original obj() instance:
self.pos.append(self.pos[men])
That's not a copy; that's just another reference to the same object.
Create a new obj() instance instead:
self.pos.append(obj(self.pos[men].x, self.pos[men].y))