I have a class named Robot, which creates a number of instances of the classes Segment and Pointmass. All these instances have a variable mass. How can I obtain the total mass of all the objects within the object with the same variable name mass?
What I do right now:
class Robot:
def __init__(self, massJoint1, massJoint2, massJoint3, massSlide, reachSlide, massArm, lengthArm):
self.joint1 = Pointmass(massJoint1)
self.joint2 = Pointmass(massJoint2)
self.joint3 = Pointmass(massJoint3)
self.slide = Slide(massSlide, reachSlide)
self.arm = Arm(massArm, lengthArm)
self.totalmass = self.joint1.mass + self.joint2.mass + self.joint3.mass + self.slide.mass + self.arm.mass
def printVars(self):
attrs = vars(self)
print(', \n'.join("%s: \t%s" % item for item in attrs.items()))
print()
class Pointmass:
def __init__(self, mass):
self.mass = mass
self.location = None
class Segment:
def __init__(self, mass):
self.mass = mass
self.start = None
self.end = None
In which
self.totalmass = self.joint1.mass + self.joint2.mass + self.joint3.mass + self.slide.mass + self.arm.mass
is a very long line, and is really inconvenient when the Robot gains more arms and joints... Is there a better way to obtain the total mass?
You shouldn't be storing the joints in separate attributes. Rather, store a simple joints list; then you can simply use sum with a generator expression.
self.totalmass = sum(j.mass for j in self.joints)
Related
I am obviously missing something fundamental here. Hopefully someone can put me right! TIA
I have an array of objects whose class contains instances of another object. But when I set a property for one of these then they all change.
class direction():
dest = -1
lock = ''
class room():
roomname = ''
desc = ''
n = direction()
s = direction()
w = direction()
e = direction()
item = ''
rooms = []
rooms.append( room() )
rooms.append( room() )
rooms.append( room() )
rooms.append( room() )
rooms.append( room() )
rooms[0].roomname = 'outside'
rooms[0].desc = ''
rooms[0].n.dest = 4
rooms[0].item = ''
rooms[1].roomname = 'hall'
rooms[1].desc = 'The hallway has doors to the east and south'
rooms[1].n.dest = 2
rooms[1].item = ''
if I iterate through the n.dest properties in the rooms list then all are returned as 2
It is as if the direction objects in each object in the rooms list are all a single instance and setting one value in one of them sets it for all of them.
Your attributes are all declared at class level, not instance level, meaning that every instance of the class will share the same values. I think you want:
class Room():
def __init__(self):
self.roomname = ''
self.desc = ''
self.n = direction()
self.s = direction()
self.w = direction()
self.e = direction()
self.item = ''
You're missing constructors, and therefore missing instance variables
You're defining class variables, so each variable is the same between all instances
In each class, you have declared a bunch of class attributes. An assignment like rooms[0].roomname = 'outside' creates an instance attribute that shadows room.roomname. However, you never actually make any such assignment to rooms[0].n, so each assignment to something like rooms[0].n.dest is adding an instance attribute dest to the same instance of direction shared by each instance of room.
In your attempt to "simplify" your code, you've made it more complicated. Define __init__ to set your instance attributes; class attributes are not used as often.
class Direction:
def __init__(self, dest, lock=''):
self.dest = dest
self.lock = lock
class Room:
def __init__(self, roomname, desc, item=''):
self.roomname = roomname
self.desc = desc
self.n = direction()
self.s = direction()
self.w = direction()
self.e = direction()
self.item = item
rooms = []
r = Room('outside', '')
r.n.dest = 4
rooms.append(r)
r = Room('hall', 'The hallway has doors to the east and south')
r.n.dest = 2
rooms.append(r)
I am creating a "pet game" in order to train my computing skills in python (that is just an excuse: it is because it is fun).
I decided to do a simple RPG game. For that, I defined the class hero:
class hero:
#Common class for the main character
def __init__(self, name, lvl, str, agi, vit, int, luk, prof):
self.name = name
self.lvl = lvl
self.str = str
self.agi = agi
self.vit = vit
self.int = int
self.luk = luk
self.prof = prof
self.exp = 0
if prof==1:
self.dmg=3*(self.str)+1*(self.agi)
self.skillList=['heavySlash01']
self.strUp=3
self.agiUp=1
self.vitUp=2
self.intUp=1
self.lukUp=1
if prof==2:
self.dmg=1*(self.str)+3*(self.agi)
self.skillList=['doubleAttack02']
self.strUp=1
self.agiUp=3
self.vitUp=1
self.intUp=1
self.lukUp=2
if prof==3:
self.dmg=4*(self.int)
self.skillList=['fireBall03']
self.strUp=1
self.agiUp=1.5
self.vitUp=0.5
self.intUp=3.5
self.lukUp=1.5
self.hp=19*vit
However, I noticed that whenever the hero leveled up, I needed to update all of its status separately. For instance, I needed to manually update the hero.dmg. Changing the agi, str and int did not automatically change the dmg as I would expect.
My question is then: Is there a way to make the dmg automatically update itself, based on its formula?
Make dmg a property instead of setting in the __init__ function. The __init__ only runs when the instance is initialized, which is why things aren't updating. However, making it a property runs the method whenever the property is accessed.
#property
def dmg(self):
if prof==1:
return 3*(self.str)+1*(self.agi)
if prof==2:
...
It's better to use inheritance in your case:
class Hero(object):
def __init__(self, name, lvl, _str, agi, vit, _int, luk):
self.name = name
self.lvl = lvl
self._str = _str # Should not use "str" because of reserved keyword of the same name
self.agi = agi
self.vit = vit
self._int = _int # Should not use "int" because of reserved keyword of the same name
self.luk = luk
self.exp = 0
#property
def hp(self):
return 19 * self.vit
class HeroProf_1(Hero):
skillList = ['heavySlash01']
strUp = 3
agiUp = 1
vitUp = 2
intUp = 1
lukUp = 1
#property
def dmg(self):
return 3 * self._str + 1 * self.agi
class HeroProf_2(Hero):
skillList = ['doubleAttack02']
strUp = 1
agiUp = 3
vitUp = 1
intUp = 1
lukUp = 2
#property
def dmg(self):
return 1 * self._str + 3 * self.agi
class HeroProf_3(Hero):
skillList = ['fireBall03']
strUp = 1
agiUp = 1.5
vitUp = 0.5
intUp = 3.5
lukUp = 1.5
#property
def dmg(self):
return 4 * self._int
I'm trying to rewrite a script and I'm stuck on making it easy to use. Basically it's an assembly script (like the reverse of destruction), where you input a load of variables such as location, whether the location is absolute or relative, scale, rotation, visibility, random offset, etc, to create an animation. The first version was very non user friendly, so I'm trying to get it working nicely from the start this time.
I've thought of how I'd like it to work, and I've managed to keep it clean, but there is a flaw. As you can see below, it'd be possible to use anything like SetGroup.frame[i].save(), which I don't want (and I don't want to put checks on if name is None throughout the class).
Here is the code I have:
class SetGroup(object):
def __init__(self, name=None, _frame_only=False):
if name is None and not _frame_only:
raise TypeError('name of group must be provided')
self.selection = None
self.origin = None
self.start = None
self.end = None
self.offset = 0
self.distance = None
self.random = 0
self.location = None
self.rotation = None
self.scale = None
self.visibility = None
if not _frame_only:
self.frame = defaultdict(lambda: SetGroup(_frame_only=True))
def save(self):
self.load()
#do a bit of error checking here
self.data[self.name] = {'ObjectSelection': self.selection,
'ObjectOrigin': self.origin,
'FrameStart': self.start,
'FrameEnd': self.end,
'FrameOffset': self.offset,
'FrameDistance': self.distance,
'FrameRandom': self.random,
'StartLocation': self.location,
'StartRotation': self.rotation,
'StartScale': self.scale,
'StartVisibility': self.visibility,
'ExtraFrames': self.frame}
pm.fileInfo['AssemblyScript'] = StoreData().save(self.data)
def load(self):
try:
self.data = StoreData().load(pm.fileInfo['AssemblyScript'])
except KeyError:
pm.fileInfo['AssemblyScript'] = StoreData().save({})
The way I'd like it to work is like this:
a = SetGroup('test')
a.location = ((0, 0, 0), True)
a.start = 0
a.end = 10
a.frame[5].location = ((10, 10, 10), False)
a.frame[5].scale = ((2, 1, 1), True)
a.save()
Unless anyone can think of a way which would make it more friendly to use, how would I separate location, rotation, scale, and visibility into another class and link them up again, so that they still work at the core level of the class, but also work for the frame dictionary too?
Edit - Got it working to a basic level:
class _MovementInfo(object):
def __init__(self, location=None, rotation=None, scale=None, visibility=None):
self.location = location
self.rotation = rotation
self.scale = scale
self.visibility = visibility
def __repr__(self):
return '_MovementInfo(location={x.location}, rotation={x.rotation}, scale={x.scale}, visibility={x.visibility}'.format(x=self)
Then I used this in the main class to merge the dictionaries:
self.__dict__.update({k: v for k, v in _MovementInfo().__dict__.iteritems() if '__' not in k})
self.frame = defaultdict(_MovementInfo)
I would change the code like this:
class SetGroup(_Movement):
def __init__(self, name=None):
if name is None:
# ...
super().__init__()
# ...
self.random = 0 # __init__ should end here
# ...
But you should check that all _MovementInfo's in all frames are _MovementInfo's or have inherited from them (to check this: isinstance(x, _MovementInfo)), but are not SetGroup's (to check this: not isinstance(x, SetGroup)).
super() is short for super(SetGroup, self) (you have to use the last option for python2), and is basicly an object that holds all things that the base class has, and allows you to call methods that modify the class calling it.
Or in code:
class A(object):
def __init__(self, y):
self.x = 2
self.y = y
class B(A):
def __init__(self, y, z):
super().__init__(y) # equivalent to: A.__init__(self, y)
self.z = z
b = B(3, 4)
# b's x is 2, b's y is 3 (both set by A.__init__, the last one was passed by B), and b's z is 4 (set by B.__init__)
I hope this helped,
CodenameLambda
I have two Python classes: Agent and Group...
Each Group has a centerGroup property, plus a static list of groups, i.e. GroupList
Here is a brief overview of the Group class:
import Agent
class Group(object):
"""description of class"""
GroupIdentifier = 1
GroupThreshold = 10
GroupList = []
def __init__(self, agentList = None ,groupCenter = None, gruopIdentifier = None):
global GroupIdentifier
global GroupList
self.groupIdentifier = GroupIdentifier
Group.GroupIdentifier += 1
Group.GroupList.append(self)
self.groupCenter = groupCenter
self.agentList = agentList
Furthermore, within the Agent class, I am going to find the minimum euclidean distance of a typical agent from all centerGroup properties corresponding to the groups in the groupList... (There is an offset, is which GAMMA_TRESHOLD)...
One can depict the related part of Agent class, as below snippet:
import Group
class Agent(object):
"""description of class"""
GAMMA_TRESHOLD = 20
def __init__(self, point = None, groupId = None):
self.locationX = point.x
self.locationY = point.y
self.groupId = 0
def get_agent_distance_from_groupCenter(self, object):
return math.sqrt(math.pow(self.locationX - point.x, 2) +
math.pow(self.locationY - point.y, 2))
def gamma_condition(self):
#I KNOW THIS IMPLEMENTATION IS WRONG... JUST GOTTA SHOW THE TARGET!
return Group.Group.GroupList[Group.Group.GroupList.index(min(get_agent_distance_from_groupCenter(agent, group.groupCenter) - GAMMA_TRESHOLD))]
From a mathematical manner perspective, the problem is minimizing the below norm and introducing the group, which its centerGroup is nearest to the agent:
min \norm{centerGroup_{i} - agent - TRESHOLD}
Would you please helping me to write such query (valid processing for gamma_condition method) by list comprehension of Python?!
All in all, with due attention to lack of any better idea from the other people, my investigations lead to below solution for this problem:
def gamma_condition(self):
temp = []
maxValue = 0
temp = [[item.groupIdentifier, JOIN_TRESHOLD - self.get_agent_distance_from_groupCenter(item.groupCenter)] for item in Group.Group.GroupList]
for item in temp:
maxValue = max(float(i) for i in item[1])
if maxValue > 0:
index = temp.index(maxValue)
NearestGroupIdToJoin = temp[index][0]
return NearestGroupIdToJoin
else:
return None
NB Noob alert ... !
I am trying to use recursion in a Python class method, but with limited results.
I'm trying to build a car class, with very basic attributes: id, position in a one lane road (represented by an integer), and velocity. One of the functions I have is used to return which car id is in front on this one -- i.e. if we have class:
class Car:
def __init__(self, position, id, velocity):
self.position = position
self.id = id
self.velocity = velocity
Now, I've come up with the following class method (additional details below the code):
def findSuccessorCar(self, cars):
successorCar = ""
smallestGapFound = 20000000
for car in cars:
if car.id == self.id: continue
currentGap = self.calculateGap(car)
if (currentGap > -1) and (currentGap < smallestGapFound):
smallestGapFound = currentGap
successorCar = car
if successorCar == "":
return 1 # calling code checks for 1 as an error code
else:
return successorCar
The plan is to create car objects, then store them in a list. Each time the findSuccessorMethod is called, this global list of cars is passed to it, e.g.
c1 = testCar.Car(4, 5, 1) # position, pos_y, Vel, ID
c2 = testCar.Car(7, 9, 2)
c3 = testCar.Car(9, 1, 2)
cars = [c1, c2, c3]
c1_succ = c1.findSuccessorCar(cars)
This works fine: the find successor car function will say that car c2 is in front of car c1 (position 7 ahead of position 4).
However, I want car c1 to work out what car is in front of its immediate successor -- that is, which car is in front of the car in front, which in this case is car c3. My thinking was that if I did c1_succ.findSuccessorCars(cars) then this should work fine: doing type(c1_succ) shows it is an instance and hasattr shows that it has the anticipated object attributes.
However, when I do try to execute c1_succ.findSuccessorCars(cars), an integer is returned. Hence, I am confused -- why doesn't this work? Why can you not recursively execute a class method in this fashion? Where does this integer come from?
NB Gut feel says that this has something to do with the self declaration, and that I'll need to modify my code so that as well as a global list of cars, there'll need to be a global list of their current positions, or another class method, e.g.
findSuccessorsSuccessor (yes, fully aware of crummy naming!). However, I am interested to understand why this recursive approach does not work.
UPDATE
Here is the requested code for calculating a gap between 2 cars -- I appreciate it is very basic, so not too much laughter at the back please.
def calculateGap(self, car):
''' Calculate the gap between two cars
'''
thisCar = self
otherCar = car
gap = otherCar.position_x - thisCar.position_x
return gap
What you're calling a class method is actually an instance method. Class methods operate on the class, and instance methods operate on the instance. Here, we're dealing with Car instances, not the Car class itself.
class Car(object):
def __init__(self, position, id, velocity):
self.position = position
self.id = id
self.velocity = velocity
def __eq__(self, other):
return self.id == other.id
def __str__(self):
return 'Car(%d, %d, %d)' % (self.position, self.id, self.velocity)
def calculateGap(self, other):
return other.position - self.position
def findSuccessor(self, cars):
ret = smallestGap = None
for car in cars:
if car == self:
continue
gap = self.calculateGap(car)
if gap < 0:
continue
if smallestGap is None or gap < smallestGap:
ret, smallestGap = car, gap
return ret
def findNthSuccessor(self, n, cars):
cur = self
for x in xrange(n):
cur = cur.findSuccessor(cars)
if cur is None:
return None
return cur
c1 = Car(4, 5, 1)
c2 = Car(7, 9, 2)
c3 = Car(9, 1, 2)
cars = [c1, c2, c3]
print c1.findSuccessor(cars)
print c1.findSuccessor(cars).findSuccessor(cars)
print c1.findNthSuccessor(2, cars)
Output:
Car(7, 9, 2)
Car(9, 1, 2)
Car(9, 1, 2)
Your method does work in theory; this is an implementation bug. That said, it is not the right way to do things; specifically, findSuccessorCar should not be a class method of Car. This is because the list of Car instances is a separate construct; the class Car doesn't and shouldn't know anything about it. If you wanted to make a class for it you should make a Road which is a list of Cars, and put findSuccessorCar on that.
That said, I don't see why you can't do
import operator
cars.sort( key = operator.attrgetter( "position" ) )
to sort the list of cars in position order. I think you're implementing your own sorting algorithm to find the successor car?
Other points of note: you should use exceptions (raise BadCarMojoError) to indicate failure, not magic return codes; classmethods traditionally use cls instead of self as the first argument; and Car should inherit from object.
import bisect
class Car( object) :
def __init__( self, position, id, velocity ):
self.position = position
self.id = id
self.velocity = velocity
def __lt__( self, other ):
return self.position < other.position
class Road( object ):
def __init__( self ):
self.cars = [ ]
def driveOn( self, car ):
bisect.insort( self.cars, car )
def successor( self, car ):
i = bisect.bisect_left( self.cars, car )
if i == len( self.cars ):
raise ValueError( 'No item found with key at or above: %r' % ( car, ) )
return self.cars[ i + 1 ]
c1 = Car( 4, 5, 1 )
c2 = Car( 7, 9, 2 )
c3 = Car( 9, 1, 2 )
c1 < c2
road = Road( )
for car in ( c1, c2, c3 ):
road.driveOn( car )
c1_succ = road.successor( c1 )