How to use dictionary in Python correctly - python

Python dictionaries have always confused me.
I have 3 dictionaries:
left_dict = {"N":"W", "W":"S", "S":"E", "E":"N"}
right_dict = {"N":"E", "E":"S", "S":"W", "W":"N"}
turn_dict = {"N":"S", "E":"W", "S":"N", "W":"E"}
I have a class Robot which is initialized as such:
class Robot:
def __init__(self, team, x, y, direction):
self.team = team
self.health = 50
self.x = x
self.y = y
self.direction = direction
In this class I have a method that changes the direction.
def left90(self):
self.direction = left_dict <---- **is this how I would change the direction**

I believe what you are looking for is:
def left90(self):
self.direction = left_dict[self.direction]

Related

How to create a method that can be called by any instance that uses information from the instances?

Suppose I want to create a class called "Point". Suppose I only ever plan on making two points because that's important. I want to create a method that can be called by either instance or "point" that gives the distance between the two points. How would I go about doing that?
This is what my code looks like.
import math
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self): # Just filler code
return math.sqrt((self_2.x - self_1.x)**2+(self_2.y - self_1.y)**2) # Just filler code
point_1 = Point(0,0)
point_2 = Point(3,4)
print(point_1.distance()) # Should return 5.0
print(point_2.distance()) # Should return 5.0
Obviously I know what I made here doesn't work, but I'm just trying to give an idea of what the print statement should do. How would I go about doing this?
import math
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self,other):
return math.sqrt((self.x - other.x)**2+(self.y - other.y)**2)
point_1 = Point(0,0)
point_2 = Point(3,4)
print(point_1.distance(point_2)) # Should return 5.0
print(point_2.distance(point_1)) # Should return 5.0
You should use a second class that specifically represents two points.
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def distance_to(self, other):
return abs(complex(self.x, self.y) - complex(other.x, other.y))
class PointPair:
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
def distance(self):
return self.p1.distnace_to(self.ps2)
point_1 = Point(0,0)
point_2 = Point(3,4)
pair = PointPair(point_1, point_2)
print(pair.distance()
or a regular function
def distance(p1, p2):
return abs(complex(p1.x, p1.y) - complex(p2.x, p2.y))
print(distance(point_1, point_2))

newList = list - self

I have an list of objects called character like that:
characters=[character(0,0,20,20,keys1),character(50,50,50,50,keys2),character(200,200,100,20,keys1)]
where character class is defined as:
class character():
def __init__(self,x,y,w,h,keys=keys1):
self.x = x
self.y = y
self.w = w
self.h = h
self.keys = keys
self.vel = 200 /math.sqrt(self.w*self.h)
self.crashed=False
# I need an list to use here in a function of my "character" class
# my list must have all the elements in my initial list but self
what I mean is like
characters[0].myFunction() must have a list of [characters[1],characters[2]]
which is characters =[character(50,50,50,50,keys2),character(200,200,100,20,keys1)]
you have to pass as an argument to your .myFunction the full list to know from which list to exclude/filter self:
class character():
def __init__(self,x,y,w,h,keys=keys1):
self.x = x
self.y = y
self.w = w
self.h = h
self.keys = keys
self.vel = 200 /math.sqrt(self.w*self.h)
self.crashed = False
def __repr__(self):
return 'charcter({}, {}, {}, {}, {})'.format(
self.x, self.y, self.w, self.h, self.keys)
def myFunction(self, characters):
return [e for e in characters if e != self]
print(characters[0].myFunction(characters))
output:
[charcter(50, 50, 50, 50, keys2), charcter(200, 200, 100, 20, keys1)]
I Understand what you want but there are a few issues with your code that I decided to fix for you i guess. The first is to remember just for your sake that when making classes make the first letter upper case. Next your key creation does not make any sense because keys1 doesnt exsist. I assumed it to be a string in my example. Next I created an str function for your class so it can output the characters somehow so its not only the memory address. Next I created the function you want but it will be in the format
x = myFunc(characters[0], characters)
and on top of that if you print x it will give you a list of memory addresses and therefore you must loop through and print each character specifically to see which one it is. Here is the final code.
import math
class Character():
def __init__(self,x,y,w,h,keys="keys1"):
self.x = x
self.y = y
self.w = w
self.h = h
self.keys = keys
self.vel = 200 /math.sqrt(self.w*self.h)
self.crashed=False
# I need an list to use here in a function of my "character" class
# my list must have all the elements in my initial list but self
def __str__(self):
return "Character x:{}, y:{}, w:{}, h:{}, key:{}".format(self.x, self.y, self.w, self.h, self.keys)
def myFunc(chars, characters):
characters_copy = characters[:]
if chars in characters_copy:
ind = characters_copy.index(chars)
characters_copy.pop(ind)
return characters_copy
characters = [Character(0,0,20,20), Character(50,50,50,50), Character(200,200,100,20)]
x = myFunc(characters[0], characters)
for i in x:
print(i)
I believe this is somewhat what you wanted, I added the changes so its easier for me and you. But you should be able to work with this.

Having difficulty understanding Python OOP

I'm fairly green to OOP and I was just playing around with it in Python and came across something I can't explain so hopefully you guys will be able to help.
I was playing with the code below:
class Car():
def __init__(self, brand, model, speed):
self.brand = brand
self.model = model
self.speed = speed
def increase_speed(self):
return self.speed + 1
def decrease_speed(self, decrease_by):
return self.speed - decrease_by
car1 = Car("tesla","x",30)
print(car1.brand)
print(car1.speed)
print(car1.increase_speed())
print(car1.speed)
print(car1.decrease_speed(10))
My question is, I am expecting after increasing the speed, car1's speed will be 31 but instead it prints out 30. Why is it that way and how should the code be written for the speed to be 31 instead?
def increase_speed(self):
self.speed += 1
return self.speed
Previously you did not increase your speed, rather you just return a value that is equal to the speed plus 1. Similarly, change your decrease_speed function.
Instead of returning the values, set them on the attributes:
class Car():
def __init__(self, brand, model, speed):
self.brand = brand
self.model = model
self.speed = speed
def increase_speed(self):
self.speed = self.speed + 1
def decrease_speed(self, decrease_by):
self.speed = self.speed - decrease_by
I deliberately don't return the changed speed anymore, as it's good style (at least with methods mainly setting attributes) to either return something or change state:
car1 = Car("tesla","x",30)
print(car1.brand)
print(car1.speed)
car1.increase_speed()
print(car1.speed)
car1.decrease_speed(10)
print(car1.speed)
The method increase_speed is just returning self.speed + 1, if you wish to update the speed you need to self.speed = self.speed + 1 into the method increase speed.

Creating Classes with multiple mutable vector attributes in python

Are the classmethods being used correctly?
I am working on a program to create data input for an 3-D N-body problem. The goal is to create a uniform density sphere with 50000 particles. Each particle class instance must have a mass, position and velocity. The position vector must be in spherical so when the instance of a particle is created it is within a sphere of radius 1. The velocity must be randomized in 3-directions. This will be changed later by adding an orbital velocity. All the data will later be exported into 3 lists masses, position and velocity all in Cartesian coordinates.
I am having trouble creating the particles with such attributes.
The first run of code was:
import math
import numpy as np
class Particle:
def__init__(self,mass,position,velocity):
self.mass = 1/50000
self.position = position
self.velocity=velocity
def position(self):
self.position = (self.r, self.theta, self.phi)
#classmethod
def set_r(cls, r):
cls.r = np.rand.uniform(0,1)
#classmethod
def set_theta(cls, theta):
cls.theta = np.rand.uniform(-(math.pi)/2 ,(math.pi)/2)
#classmethod
def set_phi(cls, phi):
cls.phi = np.rand.uniform(0,2*math.pi)
def velocity(self):
self.velocity = (self.Vx, self.Vy, self.Vz)
#classmethod
def set_Vx(cls, Vx):
cls.Vx = np.rand.uniform(0,0.001)
#classmethod
def set_Vy(cls, Vy):
cls.Vy = np.rand.uniform(0,0.001)
#classmethod
def set_Vz(cls, Vz):
cls.Vz = np.rand.uniform(0,0.001)
After talking to a friend in the CS department the code was edited to:
import math
import numpy as np
class Particle():
def __init__(self,mass,position,velocity):
self.mass = 1/50000
self.position = position[]
self.velocity = velocity[]
#classmethod
def getPosition(cls):
return [cls.r, cls.theta, cls.phi]
#classmethod
def set_r(cls, r):
cls.position[0] = np.rand.uniform(0,1)
#classmethod
def set_theta(cls, theta):
cls.position[1] = np.rand.uniform(-(math.pi)/2 ,(math.pi)/2)
#classmethod
def set_phi(cls, phi):
cls.position[2] = np.rand.uniform(0,2*math.pi)
def getVelocity(cls):
return [cls.Vx, cls.Vy, cls.Vz]
#classmethod
def set_Vx(cls, Vx):
cls.velocity[0] = np.rand.uniform(0,0.001)
#classmethod
def set_Vy(cls, Vy):
cls.velocity[1] = np.rand.uniform(0,0.001)
#classmethod
def set_Vz(cls, Vz):
cls.velocity[2] = np.rand.uniform(0,0.001)
Do I need to define the parts of the vectors in the init and then use a classmethod to create the arrays to be used and changed later?
EDIT 1: The class will be ran trough a for loop to create 50000 particles each with the same mass (normalized to 1/50000), a position vector, and a velocity vector. So exported to a .dat file in a list
If I'm understanding correctly, I don't believe you need classmethods here, rather you want to deal with each Particle individually. If I'm correct, I believe you're looking for a class that each instance knows it's own mass, position and velocity. I made a class that resembles yours but I used namedtuples to represent a position, and velocity.
import math
import numpy as np
from collections import namedtuple
Position = namedtuple('Position', ('r', 'theta', 'phi'))
Velocity = namedtuple('Velocity', ('Vx', 'Vy', 'Vz'))
class Particle():
#With 50,000 instances being created, I suggest using __slots__ if possible.
#This will cut down some on memory consumption.
__slots__ = ('mass', 'position', 'velocity')
def __init__(self, *args, **kwargs):
self.mass = kwargs.get('mass', None)
self.position = kwargs.get('position', None)
self.velocity = kwargs.get('velocity', None)
#Note! This will automatically set random values if any
#of mass, position, velocity are None when initialized
#so this may need to be altered if this is undesired
#this is just a skeleton example and if it works for you it works
if not any((self.mass, self.position, self.velocity)):
self.setup_random()
def setup_random(self):
self.mass = 1/1500
self.position = Position(
r = np.random.uniform(0,1),
theta = np.random.uniform(-(math.pi)/2 ,(math.pi)/2),
phi = np.random.uniform(0,2*math.pi)
)
self.velocity = Velocity(
Vx = np.random.uniform(0,0.001),
Vy = np.random.uniform(0,0.001),
Vz = np.random.uniform(0,0.001)
)
def set_r(self, r):
self.position = self.position.replace(r = r)
def set_theta(self, theta):
self.position = self.position.replace(theta = theta)
def set_phi(self, phi):
self.position = self.position.replace(phi = phi)
def set_Vx(self, Vx):
self.velocity = self.velocity.replace(Vx = Vx)
def set_Vy(self, Vy):
self.velocity = self.velocity.replace(Vy = Vy)
def set_Vz(self, Vz):
self.velocity = self.velocity.replace(Vz = Vz)
def __str__(self):
return('Mass: {}\nPosition: {}\nVelocity: {}'.format(
self.mass,
self.position,
self.velocity))
def __repr__(self):
return('Mass: {}\nPosition: {}\nVelocity: {}'.format(
self.mass,
self.position,
self.velocity))
From here you can make as many particles as needed just using Particle()
p = Particle()
print(p)
And this prints:
Mass: 0.0006666666666666666
Position: Position(r=0.8122849235862195, theta=-0.060787026289457646, phi=3.415049614503205)
Velocity: Velocity(Vx=0.0006988289817776562, Vy=0.00040214068163074246, Vz=0.0003347218438727625)
You can get a value very easily thanks to the namedtuples as well:
print(p.position.r)
#0.8122849235862195
And you can make a particle using pre-defined values like the following:
p = Particle(
mass = 2/5000,
position = Position(r=1, theta = 2, phi = 3),
velocity = Velocity(Vx = 4, Vy = 5, Vz = 6))
print(p)
Results:
Mass: 0.0004
Position: Position(r=1, theta=2, phi=3)
Velocity: Velocity(Vx=4, Vy=5, Vz=6)
You will still need the setter methods to set individual values such as r, theta... as tuples are immutable, although you can set a completely new position easily as well Ex:
#to set an individual value
p.set_r(1)
#setting a whole new position/velocity
p.position = Position(r = 1, theta = 2, phi = 3)
#or
p.position = Position(r = p.position.r, theta = 2, phi = 3)
#as an example
If you want to use a different collection type or anything feel free to do so I just figured namedtuples fit well here.
Edit
To allow for loading and unloading from a data file; you can make to_json and from_json methods.
Let's say your data for one Particle looks like:
d = {'mass': 0.0006666666666666666,
'r': 0.8122849235862195,
'theta': -0.060787026289457646,
'phi': 3.415049614503205,
'Vx': 0.0006988289817776562,
'Vy': 0.00040214068163074246,
'Vz': 0.0003347218438727625
}
Your methods would look like this:
def to_json(self):
json_particle = {'mass': self.mass}
json_particle.update(dict(self.position._asdict()))
json_particle.update(dict(self.velocity._asdict()))
return json_particle
#here we finally use #classmethod
#as we are creating a new instance of the class
#classmethod
def from_json(cls, data):
pos = Position(r = data['r'], theta = data['theta'], phi = data['phi'])
vel = Velocity(Vx = data['Vx'], Vy = data['Vy'], Vz = data['Vz'])
return cls(data['mass'], pos, vel)

How to retrieve a variable name given its value

class type_name:
def __init__(self, *field_names):
self.x = field_names[0]
self.y = field_names[1]
self._fields = [x for x in field_names]
def get_y(self):
return self.y
def __getitem__(self, ind):
fstr = 'self.get_' + str(self._fields[ind]) #this would give me 5 i want self.y so I construct a string such as 'self.get_y()'
#and then return eval on that string to return the value
Using this code above,
Point = pnamedtuple('Point', ['x','y'], mutable = False)
origin = Point(0,5)
print(origin[1])
It should also work with origin['y']

Categories