Python class parameters, where to define - python

class Camera(object):
def __init__(self, win, x=0.0, y=0.0, rot=0.0, zoom=1.0):
self.win = win
self.x = x
self.y = y
self.rot = rot
self.zoom = zoom
cam = Camera(Window,1,1,1,1)
vs
class Camera(object):
def __init__(self, win, x, y, rot, zoom):
self.win = win
self.x = x
self.y = y
self.rot = rot
self.zoom = zoom
cam = Camera(Window,1,1,1,1)
So does the first block of code just make the class static where it can only be made and not adjusted with parameters? If so, what's the usefulness of this?

The first block of code just sets default values for those variables. When the class is initialised if they are passed to the class, then they will be set. Otherwise the class variables will contain the default values.
In the second block of code, by not setting a default value you are making those parameters required for the class.
See this question for a better explanation: Why do we use __init__ in python classes?

The difference between the first one and second one is: the first one has default values while the other one dosen't. For example with the first one
cam = Camera(Window) wouldn't give you an error (x=0.0, y=0.0, rot=0.0 and zoom=1.0 have a default assigned value).
But the second code block would give you an error if you were to create new instance of the class like this cam = Camera(Windows). Wich is ultimately the difference between your first code block and your second one.
Cheers!

Related

Python set class variable after calling

I'm making a game using the pygame module and I have a player class:
class Player(pygame.sprite.Sprite):
def __init__(self, name, position, axsis, movment, idle, walk = None, jump = None):
pygame.sprite.Sprite.__init__(self)
self.name = name
self.idle = idle
self.walk = walk
self.jump = jump
self.image = self.idle[0]
self.movment = movment
self.left, self.right = axsis
self.pos = vec(position[0],position[1])
I am adding my characters using json data type and trying to add animations after calling the class but i can't do it
Sample code
class Game():
def __init__(self,json_file):
self.player_attribute = json_file
def character(self):
self.npc = []
for i in self.player_attribute:
self.npc.append(Player(i['name'],
i['position'],
i['axsis'],
i['movment']))
self.animation()
return self.npc
def add_animation(self):
for i in self.npc:
i.idle = "images\ghost.png"
def main_loop()
self.character
when i try this i get an error
self.image = self.idle[0]
TypeError: init() missing 1 required positional argument: 'idle'
how can i add the variables of the class after calling the class
It is not clear what the 'idle' parameter is supposed to represent in your code. However, the reason for the exception is that you are not passing any argument for 'idle' when constructing the Player object. You need something like:
self.npc.append(Player(i['name'],
i['position'],
i['axsis'],
i['movment'],
i['idle']))
You can either do that or alternatively you can pass a default argument to the Player constructor so that, when initializing you do not need to explicitly pass idle:
class Player(pygame.sprite.Sprite):
def __init__(self, name, position, axsis, movment, idle=[1], walk = None, jump = None):
You can modify its content at a later time, however I suggest you are careful what you instantiate that object attribute as, because it might come bite you back later (type error or value error).
If it were me, I would move this out of init, or not build the object until all values and their types are known (see Builder Design Pattern).
Hope this helped :) Cheers!

How do I get python to read that () is 0?

I'm having issues trying to pass an empty parameter can someone explain to me why my code isn't working. I have a math test file that goes through my math library file but my lib file can't read the () code. When I run the code it says init() missing 1 required positional argument: 'y'
import MathLib as math
math test:
if __name__ == '__main__':
math_obj1 = math.MyMathLib(2.0)
math_obj2 = math.MyMathLib(-0.5)
math_obj3 = math.MyMathLib() # this should give 0.0
print("Math obj1 value = ",math_obj1.get_curr_value() )
print("Math obj2 value = ",math_obj2.get_curr_value() )
print("Math obj3 value = ",math_obj3.get_curr_value() )
import math
class MyMathLib:
def __init__(self, y,):
self.y = y
if self == None:
value == 0.0
As posted, your definition of the __init__() function has y as a required argument.
If you want it to be optional and have a default value of zero, then write it this way:
class MyMathLib:
def __init__(self, y=0.0):
The self variable isn't actually a passable parameter in class methods (I recommend you take another look at python classes). The first (and only) passable parameter in your init function is y. Since y has no default variable, you must pass a value for y, or give it a default value:
def __init__(self, y=0.0):
self.y = y
Also I'm not sure what you're trying to achieve with this line, it makes no sense:
if self == None:
value == 0.0
value is only local to the init function, maybe you meant self.value? Even then, self will never be None (unless you assign self = None within the method), so the statement will never trigger. Ontop of that, you've used a double == instead of =.
You have to set default value in __init__
def __init__(self, y=0.0):
self.y = y
and then you don't have to check None
Or using None
def __init__(self, y=None):
self.y = y
if self.y is None:
self.y = 0.0
It can be useful if you want to recognize if someone used MyMathLib() or MyMathLib(0.0)
That is because your __init__ requires two arguments instead of one. Instead of doing this, you can pass a default variable like #Jay Mody's answer. And also:
self == None will never be true because self always passes in a value y.
Here is another way you can do it:
class MyMathLib:
def __init__(self):
self.y = 0.0
def passNumber(y):
self.y = y
As you can see, if the number is passed using passNumber, that means that the number isn't 0.0. This is another way to do it.

how to reference an attribute before it exists python

I'm writing a game in pygame, and I have a class that makes a heads up display with stats for each building when you click on it. the class variable current_hud starts as None, but when a building is clicked, its value becomes the building object so that when the draw function is called it only draws the hud of the selected building.
The problem is, I'm trying to create an instance of my "Text" class in the hud, but I'm getting the AttributeError: 'NoneType' object has no attribute 'name' because self.current_hud isn't an object yet, so self.current_hud.name isn't an attribute yet. How do I reference an attribute that doesn't exist yet? is waiting to instantiate the hud class until after the building is clicked on really the only option?
class Hud:
current_hud = None
def __init__(self,x,y):
self.x = x
self.y = y
self.name_text = Text(x,y,str(self.current_hud.name), (0,0,0), 36)
def draw(self):
if Hud.current_hud == self:
self.square = pygame.Rect((self.x,self.y),(440,400))
pygame.draw.rect(screen,(255,255,255),self.square)
self.name_text.x = self.x + 10
self.name_text.y = self.y + 20
sorry if this is convoluted, but it's a little difficult to explain. The full code is here if you want to run it and see how it all works: https://github.com/hailfire006/economy_game/blob/master/economy_game.py
You can take the name as an option to the Hud class and set it prior to instantiating the Text class.
class Hud:
current_hud = None
def __init__(self,x,y,name):
self.x = x
self.y = y
self.current_hud.name = name
self.name_text = Text(x,y,str(self.current_hud.name), (0,0,0), 36)
def draw(self):
if Hud.current_hud == self:
self.square = pygame.Rect((self.x,self.y),(440,400))
pygame.draw.rect(screen,(255,255,255),self.square)
self.name_text.x = self.x + 10
self.name_text.y = self.y + 20
In your full code example it looks like when you instantiate a building you have its name and can then pass that along to the Hud on instantiation.
class Building:
def __init__(self,posX,posY,color,name):
self.hud = Hud(0,0,name)

Printing from within properties

I'm trying to make a robotics kit. Its designed to be simple so I'm using properties so when the users change a parameter the property method sends the serial command which controls motors/ servos/whatever.
This is the code at the moment, directly from a previous question I asked on here.
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
def get_angle(self):
return self._angle
def set_angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo, notice that this method knows the servo number AND the desired value"
def del_angle(self):
del self._angle
angle = property(get_angle, set_angle, del_angle, "I'm the 'angle' property.
this is then initialized as such:
class robot(object):
def __init___(self):
self.servos = [Servo(0), Servo(1), Servo(2), Servo(3)]
Now, this works in the respect that it does change the variable through the getter and setter functions, however the prints in the getter and setter never is printed, thus if I replace it with a serial command I assume it won't do anything either, can anyone shed any light on this?
Thanks
Update: Thanks for the help using the servo file this is whats happened, there are three scenarios the first works and by extension I would have assumed the next two preferable scenarios would work but they don't any ideas?
This works
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0), servo.Servo(1,0), servo.Servo(2,0)]
R = Robot()
R.servos[1].angle = 25
This does not:
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0), servo.Servo(1,0), servo.Servo(2,0)]
R = Robot()
left_servo = R.servos[1].angle
left_servo = 25
Neither does this
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0).angle, servo.Servo(1,0).angle, servo.Servo(2,0).angle]
R = Robot()
R.servo[1] = 25
Using the preferred decorator syntax for properties, this works fine. It'll also help you avoid issues like this in the future
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
#property
def angle(self):
return self._angle
#angle.setter
def angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo"
#angle.deleter
def angle(self):
del self._angle
Seeing as your indentation is off here, I believe this is likely an issue of indentation in your source. This should work as well if you really want to use the old property function:
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
def get_angle(self):
return self._angle
def set_angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo"
def del_angle(self):
del self._angle
angle = property(get_angle, set_angle, del_angle,"I'm the 'angle' property.")
Both of these work successfully for me (inside a file called servo.py)
>>> import servo
>>> s = servo.Servo(1, 2)
>>> s.angle
2
>>> s.angle = 3
replace this print statement with the code to set servo
EDIT
To address your new issues. When you assign R.servos[1].angle to left_servo, its not creating a reference to the servos angle, it's just setting left_servo to whatever the angle is. When you reassign 25 to it, you're not assigning to the angle you're assigning to the left_servo.
On the second one, I'm assuming you meant R.servos and not R.servo which should be raising an AttributeError. But the real problem as I see it, is you should be saying R.servos[1].angle = 25 and you're omitting the .angle.
To (attempt to) put it simply: When you use the = operator, you are changing where a name refers to, not what it refers to.
>>> x = 1
>>> x = 2
the second assignment does not overwrite the 1 in memory with a 2, it just changes where x refers to. So if I did something like
>>> x = 1
>>> y = x
>>> y = 2
>>> print x
1
the output is 1 because your are telling y to refer to the same place that x refers. Changing y to 2 changes where y refers to, it does not change the 1 already in memory.

Animating a custom QGraphicsItem with QPropretyAnimation

I want to make a car follow a path, so I tried animating a custom QGraphicsItem (describing a 'car') using QPropreties, starting by an example given on PySide documentation :
self.anim = QtCore.QPropertyAnimation(self.car, "geometry")
self.anim.setDuration(4000);
self.anim.setStartValue(QtCore.QRect(0, 0, 100, 30));
self.anim.setEndValue(QtCore.QRect(250, 250, 100, 30));
self.anim.start();
self.car here is an instance of Car, a class that inherits from QGraphicsItem and QObject ( EDIT Changed this, see EDIT 2):
class Car(QtGui.QGraphicsItem, QtCore.QObject):
def __init__(self, map = None, ....):
super(Car, self).__init__()
self.map = map
....
I always get the same error code when executing this :
QPropertyAnimation::updateState (geometry): Changing state of an animation without target
This is weird as the target is really set ! I tried putting setTargetObject ( see the documentation on PySide ) but it didn't change anything.
Any idea about where that could come from ?
EDIT : Something that could help -> I tried putting those three lines and the result shows that the object is not taken into account :
print self.car
self.anim.setTargetObject(self.car)
print self.anim.targetObject()
Result
<engine.Car(this = 0x43f9200 , parent = 0x0 , pos = QPointF(0, 0) , z = 0 , flags = ( ItemIsMovable | ItemIsSelectable ) ) at 0x1de0368>
None
EDIT 2 : Changing the class inheritance to QGraphicsObject seems to have solved the 'no target' problem ! But I have a different error now (using a custom defined property 'pos'):
QPropertyAnimation::updateState (pos, Car, ): starting an animation without end value
I defined my property that way :
def setPos(self, pos):
self.x = pos[0]
self.y = pos[1]
self.update()
def readPos(self):
return (self.x, self.y)
pp = QtCore.Property('tuple', readPos, setPos)
If you just need to animate position, you can animate GraphicsItem.pos rather than defining your own position functions (unless you want the car to have a position within the QGraphicsItem itself.
As for 'starting an animation without end value', make sure you:
Call setEndValue on the animation.
Pass in the correct type to setEndValue (e.g. your current implementation would require a tuple, using GraphicsItem.pos would require a QPoint).
The solution was to first change the inheritance from QGraphicsItem and QObject to QGraphicsObject. Then, the second error I did is I didn't define my property (x and y) correctly.
I ended up re-implementing my class to use QGraphicsObject's "pos" property and give it the correct start and end value (tuples).

Categories

Resources