Changing variable for all objects of one class - python

I am new to Python and I run into a problem.
To keep it simple instead of sending you all my code I will generalize it a bit.
I want to create a class "object" with an x and y coordinate.
class Object():
def __init__(self, x, y):
self.x = x
self.y = y
object_1 = Object(0,0)
object_2 = Object(20, 20)
object_3 = Object(100, 100)
I created three objects of class Object(), each with an individual x and y coordinate. Now I want to add e.g. 5 to all three x coordinate without typing it manually. Is there a smarter way to add 5 to all members of this class?
i am sorry in case my question was answered in another post but I could find anything that helps me. Thank you in advance

To avoid doing it individually, do it in group, you could build a static method in the class that adds a value to the x of all given objects
#staticmethod
def addX(value, *items):
for item in items:
item.x += value
# call
Object.addX(5, object_1, object_2, object_3)
Code Demo

Save all of your obstacles in a list when you create them, something like a group.
You can save them in a list or save them inside another class that they are related to.
Then in each desired move execute a loop over that list, something like this:
for obstacle in obstacles:
obstacle.x += 5

Related

A class for spin up and down particles?

So I have a bunch of particles which can be of two kinds let's say "up" and "down". I am new to python but I know that this segregation can be done with the help of a class.
Let's say I have a list:
T=np.linspace(0,1,1000)
I want each element of this list to be either one of the two particles but I am not sure if I should create two classes with one "kind" each or a single class with two "instances" and assign each element an instance.
In the end, what I want to do is randomly distribute this property of being "up" and "down" over the list T.
There is not enough info. You most likely don't want 2 instances when dealing with 1000 items - each item should be probably represented by separate instance of a class. But that doesn't mean that having 2 classes is a way to go.
Are the particles relatively similiar and besides the difference of a single property they have the same behaviour? If so, I'd go for single class, 1000 instances and storing the up/down property in some instance attribute.
EDIT:
This is how I would personally implement this with for the current requirements in question:
class Particle:
def __init__(self, posInit, momInit, spin):
self.posInit = posInit
self.momInit = momInit
self.spin = spin
def momOfT(self, t):
return self.momInit*(math.cos(t))+self.posInit*(math.sin(t))
def posOfT(self, t):
return self.posInit*(math.cos(t))-self.momInit*(math.sin(t))
T = [Particle(posInit = i, momInit = 1-i, spin = random.choice(["up", "down"])) for i in np.linspace(0, 1, 1001)]
print([T[0].posOfT(i) for i in np.linspace(0, 3.1415*2, 1000)])

How to convert a function based data pipeline to OOP?

I am doing some data processing and have built several pipelines, each consisting of multiple functions that broadly modify dictionaries at each step. As the different pipelines operate on the same data and have similar functions I've been trying to convert it into a more OOP orientated structure. However, before I get started I've been tying myself up in knots slightly.
Take the following simplified example:
for f in foos:
y = extract_y_info(f)
z = extract_z_info(f)
*some code that does something with y and z*
def extract_y_info(f):
return *some code that extracts y info from f*
def extract_z_info(f):
return *some code that extracts z info from f*
To me there seems to be a couple of ways I could approach moving this to an OOP structure. The first is quite similar to the function by function approach.
class foo():
def __init__(self, x):
self.x = x
def extract_y_info(self):
return *some code that extracts y info from self.x*
def extract_z_info(self):
return *some code that extracts z info from self.x*
for f in foo_instances:
y = b.extract_y_info()
z = b.extract_z_info()
*some code that does something with y and z*
The other option is modifying the instances of the class:
class foo():
def __init__(self, x):
self.x = x
def extract_y_info(self):
self.y = *some code that extracts y info from self.x*
def extract_z_info(self):
self.z = *some code that extracts z info from self.x*
for f in foo_instances:
f.extract_y_info()
f.extract_z_info()
*some code that does something with f.y and f.z*
Is either of these options better practice than the other? Is there a better third way?
It really depends on what your overall design is and what state do you expect your instances to be at any given time and what you do with it (in other words, is existence of y attribute itself meanigul, but... former seems generally safer to me. You call and you get a value, you don't have to keep track, have I called the method and what state is this or that attribute in? Note though, you should really define instance attributes in the constructor, otherwise the access could be not just surprising, but fatal (AttributeError).
Now a neat solution addressing some of the above point and possibly fitting to what you seem to be doing here to access the values could be a property, which essentially allows you to access value returned by a method as if it was a instance attribute:
class foo():
def __init__(self, x):
self.x = x
def extract_y_info(self):
return #some code that extracts y info from self.x
y = property(extract_y_info)
for f in foo_instances:
print(f"value of f.y = {f.y}")
Or you can do the same using property as method decorator:
#property
def y(self):
return #some code that extracts y info from self.x
If getting y was expensive and its value does not change across the life of instance, starting Python 3.8 you can also use cached_property.

Python: Modifying an object by assigning it to another object

I'm new to Python (coming from C++), and understand that roughly speaking, all variables (names) are references to Python objects. Some of these objects are mutable (lists), while others aren't (tuples, although you can change its elements if they themselves are mutable).
For mutable objects, I can modify them by accessing their modifier functions (such as .append()) through the name(s) they're bound to. For example:
myList = [1,2,3,4]
myList.append(5)
However, I know that simply assigning myList to a second list just instantiates this second list and reassigns myList to it; The original list [1,2,3,4] still exists, until garbage collection cleans it up (or not if another name is assigned to it).
MY QUESTION:
Lets say I have a Point class:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p1 = Point(1,1)
p1.x = 2
p1.y = 2
How can I replace p1.x = 2 and p1.y = 2 with a single command that just assigns my Point(1,1) object to a Point(2,2) object? Clearly, p1 = Point(2,2) doesn't work as this just reassigns the p1 name to a new and different Point(2,2) object (which is not what I need!).
Is there a built-in way to do this or do I need to define an additional modifier function in Point:
def changePoint(self, newPoint):
self.x = newPoint.x
self.y = newPoint.y
in order to do this in a single command (i.e. via p1.changePoint(Point(2,2)))? In C++ you can often just use a class' implicitly defined overloaded assignment operator (operator=) and accomplish this in a single command:
SimpleNameClass* objectPtr = new SimpleNameClass("Bob");
//Dereferencing objectPtr and assigning new object:
*objectPtr = SimpleNameClass("Jim");
//Now objectPtr still points to (references) the same address in memory,
//but the underlying object is completely different.
Overall, it seems tedious to have to change every attribute individually when I want to transform my object into a new one, especially if my object contains many attributes!
EDIT:
Adding to Jainil's answer, it turns out I don't even need to change the definition of init at all, I can just use the above version. Then, you can transform a Point object to another one with a single command, like so:
p1.__init__(2,2) #Replaces p1.x = 2, p1.y = 2
It works since the original init takes to 2 args. So a standard, vanilla init method basically already enables changing the underlying object, in addition to instantiating it (at least in this case). Yipee.
one way would be to assign using tuple unpacking:
p1.x, p1.y = 2, 2
or you could implement a setter method in your class:
def set_xy(self, x, y):
self.x, self.y = x, y
but creating a new instance (for a class this simple) may make more sense:
p1 = Point(2, 2)
in python you can not override the assignment operator =.
class Point:
def __init__(self, *args):
if(len(args)==2):
self.x = args[0]
self.y = args[1]
elif(len(args)==1):
self.x=args[0].x
self.y=args[0].y
p1 = Point(1,1)
p1.x = 2
p1.y = 2
p1.__init__(Point(3,3))
print(p1.x," ",p1.y)
it is just what you want , but in python way.
in python = can't be overloaded and it is not an operator in python, it is delimeter in python. see https://docs.python.org/3/reference/lexical_analysis.html#delimiters
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def change_point(self, new_x, new_y):
self.x = new_x
self.y = new_y
I'm not sure this is necessarily encouraged, but you can directly modify the __dict__ attribute of the object to modify it. That leads to a solution like:
def assign_to(obj_one, obj_two) -> None:
fields = obj_one.__dict__ # Grab the field/value dictionary of the object
for field_name, field_value in fields.items():
obj_two.__dict__[field_name] = field_value # Loop over obj_one's fields and assign them to obj_two
Then its use:
p1 = Point(1, 2)
p2 = Point(8, 9)
assign_to(p1, p2)
p2.x, p2.y # To show that they were modified
# Prints (1, 2)
id(p1), id(p2) # To show that they're both still distinct objects
# Prints (69029648, 69029296)
This may have drawbacks though, as honestly I've never played around with __dict__ before. You may want to do further research into it before relying on it too heavily.
I'd honestly just write a custom assigning function as the other answers show. Writing an extra line per field shouldn't be too big of a deal; especially given most classes likely won't need such functionality anyways. You're likely just going to be copying PODs like this.

Creating and declaring list in class

I am trying to create a list within a class and then declaring elements in that list.
I don't even know if this is the right way for python. I have some java background.
I didn't add 10 elements in the list manually because I feel creating a dynamic list will be more useful.
class Levels:
def __init__(self):
self.type = "A"
self.size = [] # trying to create a list for 10 elements.
self.makespace(self.size) # running this method to create 10 spaces and then declare them.
def makespace(self, size):
for i in range(0,10):
if(size[i] == None):
size[i] = "free"
print(i)
else:
print("Didn't work")
print(i)
test = Levels()
Your problem lies in here.
if(size[i] == None):
size[i] = "free"
print(i)
At this moment, size is empty, it doesn't contain any elements so why are you
checking size[i] == None?
You probably think that a python list behaves like an array in Java where it initializes everything with null? Even though here you are not declaring the size of the list inside the init constructor, so I'm curious how you thought of that.
Your code should look like this:
class Levels:
def __init__(self):
self.type = "A"
self.size = [] # trying to create a list for 10 elements.
self.makespace(self.size) # running this method to create 10 spaces and then declare them.
def makespace(self, size):
#This will fill the emty list with 10 None(null) values
for i in range(0,10):
size.append(None)
test = Levels()
Also a bonus:
class Levels:
def __init__(self):
self.type = "A"
self.size = []
#Notice that I'm not passing self as an argument when I call makespace()
self.makespace()
def makespace(self):
#This will fill the emty list with 10 None(null) values
for i in range(0,10):
self.size.append(None)
test = Levels()
Self is the this keyword in python, the difference is that in Python you need to pass it as an argument only when declaring methods, not when you call them and also you can name it whatever you want!
Hope this helps!
This code won't work because size[i] does not exist. Instead use size.append(...). Also you should pass a number to makespace so that you can make space for an arbitrary number of items.
class Levels:
def __init__(self, kind='A', size=10):
self.kind = kind
self.size = [ 0 for _ in range(10) ]
These slight changes make your code more robust and more pythonic.
First but the least important is that type is a builtin-method (also a class and also a type) so kind is often substituted.
Second You can pass default arguments to the constructor (or any function) as you should generally avoid having constants inside functions like that. Here you can arbitrarily set a Level's kind, as well as the initial space required.
Third Using list-comprehension you can create a list of arbitrary size (or elements). The syntax is
[ expression for args in iterable ]
which allows for any expression to be generated based on arguments passed from an iterable. Read more about list comprehension and other datastructure here.
As for your makespace you shouldnt really need it, however you could change the implementation so you can allocate more space (using self.size.append(...)) or overwriting currently used space.
Best of luck!
If you want to have 10 free spaces in the list upon initializing, change
self.size = []
to
self.size = [“free”] * 10
If you want to start with an empty list and add 10 free spaces in your makespace loop, simply use
self.size.append(“free”)
Also, you really don’t need to pass size to makespace. Since you’re already passing self, I would just reference self.size from inside the makespace function.

Python: how to automatically create instance object?

I want to create instance objects automatically as I explained in the following:
Class MyClass:
def __init__(self,x):
self.x = x
list = ["A","B"]
I want to create the following but automatically, means to loop through the list and create identical object for each element:
A = MyClass(text)
B = MyClass(text)
e.g. like the following which doesn't work:
# this doesn't work but explains more what I need
for i in list:
i = MyClass(text)
Thanks to all of your help!
In general, you can't and shouldn't shove things into your namespace like that. It's better to store those instances in a dict or a list
Class MyClass:
def __init__(self,x):
self.x = x
lst = ["A","B"] # don't use list as an identifier
myclasses = {k: MyClass(text) for k in lst}
Now your instances are
myclasses['A'], myclasses['B'] etc.
If you really want to create a handful of variables in your namespace:
A, B = (MyClass(text) for x in range(2))
note that this means you need to be explicit. You can't get the A,B from a file or user input etc.
Don't be tempted to use exec to pull this off. It's probably the wrong way to go about solving your problem. Tell us why you think you need to do it instead.

Categories

Resources