Add attribute to an Instance of an existing Class in Python 2 - python

In my data, I am getting two dictionaries at two different parts. I created a Class object to combine the dictionaries into a single object.
In this example, x and y attributes are the Class dictionaries that are being assigned to D_A_x and D_A_y respectively.
How can I add an attribute to a class instance that has already been created?
class Class_Example:
def __init__(self,x="NaN",y="NaN"):
self.x = x; self.y = y
def get_x(self,var): return(self.x[var])
def get_y(self,var): return(self.y[var])
D_A = {}
D_A_x = {"a":1}
D_A["instance_1"] = Class_Example(x = D_A_x)
#D_A["instance_1"].get_x("a")
D_A_y = {"b":2}
D_A["instance_1"].__init__(y = D_A_y)
print D_A["instance_1"].get_x("a") #Doesn't work because it has been replaced.
I don't have access to D_A_x and D_A_y at the same time create the Class in one go.
I checked out this, but it didn't help in my situation: Adding base class to existing object in python

Yes, its as you have already noticed, when you call __init__() for your Class_Example class , it overwrites the x and y values with the value passed in , and in the second time, since you do not send in anything for x, it uses the default "NaN" string .
You should not call __init__() again, you can simply set the y attribute. Example -
D_A["instance_1"].y = D_A_y

Why not simply do: D_A['instance_1'].y = D_A_y?

Related

TypeError: __init__() missing 1 required positional argument: 'lists'

I created a class, something like below -
class child:
def __init__(self,lists):
self.myList = lists
def find_mean(self):
mean=np.mean(self.myList)
return mean
and when I create an onject something like below -
obj=child()
it gives the error -
TypeError: __init__() missing 1 required positional argument: 'lists'
if I create object like below then it works well -
obj=child([44,22,55)
or If I create the class like below -
class child:
def find_mean(self,myList):
mean=np.mean(myList)
return mean
and then I create the object like below -
obj=child()
then also it works well, however I need to make it in the way I explained in the very begining. Can you please help me understand this context?
In the first example, the __init__ method expects two parameters:
self is automatically filled in by Python.
lists is a parameter which you must give it. It will try to assign this value to a new variable called self.myList, and it won't know what value it is supposed to use if you don't give it one.
In the second example, you have not written an __init__ method. This means that Python creates its own default __init__ function which will not require any parameters. However, the find_mean method now requires you to give it a parameter instead.
When you say you want to create it in the way you explained at the beginning, this is actually impossible: the class requires a value, and you are not giving it one.
Therefore, it is hard for me to tell what you really want to do. However, one option might be that you want to create the class earlier, and then add a list to it later on. In this case, the code would look like this:
import numpy as np
class Child:
def __init__(self, lists=None):
self.myList = lists
def find_mean(self):
if self.myList is None:
return np.nan
mean = np.mean(self.myList)
return mean
This code allows you to create the object earlier, and add a list to it later. If you try to call find_mean without giving it a list, it will simply return nan:
child = Child()
print(child.find_mean()) # Returns `nan`
child.myList = [1, 2, 3]
print(child.find_mean()) # Returns `2`
the code you have at the top of your question defines a class called child, which has one attribute, lists, which is assigned at the time of instance creation in the __init__ method. This means that you must supply a list when creating an instance of child.
class child:
def __init__(self, lists):
self.myList = lists
def find_mean(self):
mean=np.mean(self.myList)
return mean
# works because a list is provided
obj = child([44,22,55])
# does not work because no list is given
obj = child() # TypeError
If you create the class like in your second example, __init__ is no longer being explicitly specified, and as such, the object has no attributes that must be assigned at instance creation:
class child:
def find_mean(self, myList):
mean=np.mean(myList)
return mean
# does not work because `child()` does not take any arguments
obj = child([44,22,55]) # TypeError
# works because no list is needed
obj = child()
The only way to both have the myList attribute, and not need to specify it at creation would be to assign a default value to it:
class child:
def find_mean(self,myList=None):
mean=np.mean(myList)
return mean
# now this will work
obj = child()
# as will this
obj = child([24, 35, 27])

How are duplicate class names resolved in data classes?

While working with data classes I declared duplicate data class and realized that on creating objects with them, the code worked perfectly fine, as long as I was using the format mentioned on the most recent line from the bottom.
Is duplicate naming really allowed? Can I do some kind of overloading with duplicate data class names? What about inheriting from the data class of the same name?
Just like you can reassign a new value to a name with an assignment statement
x = 1
x = 2
assert x == 2
you can assign a new class object to a name with a class statement.
class X:
pass
old_X = X
class X:
pass
assert old_X is not X
A class statement itself, is a declarative syntax that does three things:
Evaluates its body to define some names
Pass a dict constructed from the names and their values to the metaclass to create a new class
Assigns the return value of the call to the metaclass to the name given by the class statement.
You are just observing the 3rd step.

How to import global variables in python from a class module in another file?

I have a file that contains the class definitions and functions I need to use in my main file to make the text cleaner. However, I'm having a problem with imported global variables.
There is plenty of information at SO and other resources regarding how to make function variables global within the same code or how to use the global variables from an imported file. However, there is no information on how to access a variable from an imported file if the variable belongs to a function belonging to a class.
I would appreciate any help on how to do it or why it cannot be done. Please skip the lecture on the dangers of using global variables like this as my situation requires such use.
Edit: Sorry for not having an example in the original post. It's my first one. Below is an example of what I'm trying to accomplish.
Let's say I have a file classes.py that contains:
class HelixTools():
def calc_angle(v1, v2):
v1_mag = np.linalg.norm(v1)
v2_mag = np.linalg.norm(v2)
global v1_v2_dot
v1_v2_dot = np.dot(v1,v2)
return v1_v2_dot
Then in my main text file I do:
from classes import HelixTools
ht = HelixTools()
v1 = some vector
v2 = some other vector
ht.calc_angle(v1,v2)
print(v1_v2_dot)
The result is "v1_v2_dot" not defined. I need v1_v2_dot to use it as the input of another function.
Here's an example of how you can access class attributes (if I understand what it is you want to do correctly). Lets imagine you have a python file called "Test_class.py" that contains the following code:
class Foo(object):
def __init__(self, x, y):
self.x = x
self.y = y
def bar(self):
self.z = self.x + self.y
Now lets imagine you want to import this class into another python file in the same directory, and access attributes of that class. You would do this:
from Test_class import Foo
# Initialize two Foo objects
test1 = Foo(5, 6)
test2 = Foo(2, 3)
# Access the x and y attributes from the first Foo object
print(test1.x) # This will print 5
print(test1.y) # This will print 6
# Access the x and y attributes from the second Foo object
print(test2.x) # This will print 2
print(test2.y) # This will print 3
# Access the z attribute from the first Foo object
test1.bar()
print(test1.z) # This will print 11
# Access the z attribute from the second Foo object
test2.bar()
print(test2.z) # This will print 5
This works because variables defined in the __init__ magic method are initialized as soon as the Foo object is first called, so the attributes defined here can be access immediately after. The bar() method has to be called before you can access the z attribute. I made 2 Foo objects just to show the importance of including "self." in front of your variables, in that each attribute is specific to that particular class instance.
I hope that answers your question, but it would be very helpful if you provided some example code to show exactly what it is you want to do.
You should likely use a class attribute to store this value. Note that the implementation will depend on what your class HelixTools really does.
But for the example, you could use something like this:
import numpy as np
class HelixTools():
def __init__(self):
# Initialize the attribute so you'll never get an error calling it
self.v1_v2_dot = None
def calc_angle(self, v1, v2): # Pass self as first argument to this method
v1_mag = np.linalg.norm(v1)
v2_mag = np.linalg.norm(v2)
# Store the value in the attribute
self.v1_v2_dot = np.dot(v1,v2)
And then:
from classes import HelixTools
ht = HelixTools()
v1 = some vector
v2 = some other vector
ht.calc_angle(v1,v2) # This will not return anything
print(ht.v1_v2_dot) # Access the calculated value

Reading binary file to a list of structs, but deepcopy overwrites first structs

I am reading a binary file into a list of class instances. I have a loop that reads data from the file into an instance. When the instance is filled, I append the instance to a list and start reading again.
This works fine except that one of the elements of the instance is a Rect (i.e. rectangle), which is a user-defined type. Even with deepcopy, the attributes are overwritten.
There are work-arounds, like not having Rect be a user-defined type. However, I can see that this is a situation that I will encounter a lot and was hoping there was a straightforward solution that allows me to read nested types in a loop.
Here is some code:
class Rect:
def __init__(self):
self.L = 0
class groundtruthfile:
def __init__(self):
self.rect = Rect
self.ht = int
self.wt = int
self.text = ''
...
data = []
g = groundtruthfile()
f = open("datafile.dtf", "rb")
length = unpack('i', f.read(4))
for i in range(1,length[0]+1): #length is a tuple
g.rect.L = unpack('i',f.read(4))[0]
...
data.append(copy.deepcopy(g))
The results of this are exactly what I want, except that all of the data(i).rect.L are the value of the last data read.
You have two problems here:
The rect attribute of a groundtruthfile instance (I'll just put this here...) is the Rect class itself, not an instance of that class - you should be doing:
self.rect = Rect() # note parentheses
to create an instance, instead (similarly e.g. self.ht = int sets that attribute to the integer class, not an instance); and
The line:
g.rect.L = unpack('i',f.read(4))[0]
explicitly modifies the attribute of the same groundtruthfile instance you've been using all along. You should move the line:
g = groundtruthfile()
inside the loop, so that you create a separate instance each time, rather than trying to create copies.
This is just a minimal fix - it would make sense to actually provide arguments to the various __init__ methods, for example, such that you can create instances in a more intuitive way.
Also, if you're not actually using i in the loop:
for _ in range(length[0]):
is neater than:
for i in range(1,length[0]+1):

Creating classes in dictionaries - values being duplicated between classes?

So I'm trying to store some lists into a list that belongs to a "person". I tried to do this with some classes:
class data():
# Contains list of x, y, z, time lists
x = []
y = []
z = []
time = []
class data_main():
# Contains data for each Pi
data_plot = data()
data_overflow = data()
piList = ["Lui", "Wing"]
rpi_data = {}
for pi in piList:
rpi_data[pi] = data_main()
rpi_data["Lui"].data_plot.x = 10
rpi_data["Wing"].data_plot.x = 99
print(rpi_data["Lui"].data_plot.x)
print(rpi_data["Wing"].data_plot.x)
Problem is, I won't actually know how many people there will be. Therefore I want to create a dictionary of the class "data_main" belonging to different people.
When I try to do this, the console results are:
99
99
When I'd rather it do: 10 and 99 respectively. I'm worried that in the for loop:
for pi in piList:
rpi_data[pi] = data_main()
I'm really just designating the same instance of data_main() to the dictionary entries, when really I'd prefer unique ones, so that they can each have their own values.
How do I achieve this?
EDIT: I did more digging and it turns out data_plot for both instances of data_main() is pointing to the same address. How do I avoid this (ie, every time I init a new data_main() class, that I create new data_plot() and data_overflow() classes too?)
Your data_plot and data_overflow are class attributes not instance attributes ,so they are initialized when the class gets defined , not when the instance is created, and they get shared between all the instances of the class . You should create them as instance attributes in __init__() method. Example -
class data_main:
def __init__(self):
# Contains data for each Pi
self.data_plot = data()
self.data_overflow = data()
Also in your data class , the attributes in it are also class attributes, you should make them instance attributes as well. Example -
class data:
def __init__(self):
# Contains list of x, y, z, time lists
self.x = []
self.y = []
self.z = []
self.time = []
Finally, first in data class you are defining x as a list, and then you are changing the x for rpi_data["Lui"].data_plot.x to a number , when you do -
rpi_data["Lui"].data_plot.x = 10 #or the 99 one.
If you intended to append the number to the x list , you should use -
rpi_data["Lui"].data_plot.x.append(10)

Categories