I need to iterate over a number of attributes inside an object. Each attribute is initialized as None and over the course of the program each will store a separate object. There are 16 attributes that I need to iterate over and the condition is that the attributes will store objects in a predetermined sequence. For example, if attribute 10 is empty, then attributes 11 to 16 will also be empty, therefore I will not need to iterate past any empty attributes. My initial result was to use 'if' statements for each attribute like this:
Class Object1:
def __init__(self):
self.attribute1=None
self.attribute2=None
self.attribute3=None
self.attribute4=None
...
def repeating_function(self):
if self.attribute1!=None:
self.attribute1.attribute=Callback1
if self.attribute2!=None:
self.attribute2.attribute=Callback2
if self.attribute3!=None:
self.attribute3.attribute=Callback3
...
But, because of the sequence in which the attributes store objects, I ended up with this:
class Object1:
def __init__(self):
self.attribute1=None
self.attribute2=None
self.attribute3=None
self.attribute4=None
self.attribute5=None
def repeating_function(self):
if self.attribute1!=None:
self.attribute1.attribute=Callback1
if self.attribute2!=None:
self.attribute2.attribute=Callback2
if self.attribute3!=None:
self.attribute3.attribute=Callback3
...
Basically, my question is: if the second example is more efficient at iterating over the non-empty attributes. Because I'm adding conditions inside conditions in the second example, I'm not sure which method is more efficient.
You should use a list instead of separate attributes:
class MyClass(object):
def __init__(self):
self.attributes = []
With this,
to add an attribute, use self.attributes.append(...);
to find out how many (non-None) attributes there are, use len(self.attributes);
to refer to the final non-None attribute, use self.attributes[-1];
and so on.
Related
I have created a class and am attempting to create a function that will, in essence, act as a binary operator between two objects of that class. The function I was trying to create is called 'combine'.
I know I could create the function outside of the class, but I want it to be associated with the class.
Background (not really necessary for answering the question) - the class is modelling the S4 mathematical group and is some practice with objects and classes for me. My next function was to be to simplify an element into it's simplest expression in cycles, which I am confident that I could do, but I would rather get this one sorted first.
When I create a function with one argument, it runs fine - as demonstrated in the code below, with the function 'cycletype', which works as expected.
class s4:
# Define an element of s4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(first, second):
for i in second:
first.append(i)
return first
double = s4([[1,2],[3,4]])
triple = s4([[1,2,3]])
print(combine(double,triple))
I was expecting [[1,2],[3,4],[1,2,3]] to be printed, however, it showed a NameError, not recognising combine.
You should be creating a new instance from the lists wrapped by the two arguments:
class S4:
# Define an element of S4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(self, first, second):
return S4(first.element_list + second.element_list)
It also appears that you could simply define __add__ instead of combine,
# Simplified implementation, no error checking
def __add__(self, second):
return S4(self.element_list + second.element_list)
allowing you to write
print(double + triple)
instead of
print(combine(double, triple))
There's two problems with the code
putting the function inside the class means that it's a method. So, you have to access it using the object s4.combine(s1), not just combine(...). Otherwise, it would be a function, not a method.
After you change that: you can't write for i in second, because instances of your class are not iterable. You have to implement __iter__ to be able to use that syntax
This is because the combine function isn't present in the global scope ( I hope that's what its called, I mess up names real bad).
You can only call functions present in the global scope, in the case of classes, you need objects to call these functions as these functions are part of those specific classes and not the global scope in general.
Hope this helped
There's a scope problem, you defined combine within the s4 class, so you should call it from a instance of s4. Anyways, here's is how I would do it.
class s4:
# Define an element of s4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(self, second):
#Here I changed first to self, first would be the s4 class that calls the function, in this example double and second would be the one that you want to combine
first = self.elementlist
for i in second.elementlist:
first.append(i)
return first
double = s4([[1,2],[3,4]])
triple = s4([[1,2,3]])
##As double() is defined within the s4 class, you can only call it from an instance of s4 (in this case you could use doble.combine() or triple.combine())
print(double.combine(triple))
Hope it helps.
I have a class
class MyClass():
def __init__(self):
self.a = 7
self.b = 2
#property
def aAndB(self):
return self.a + self.b
I would like a function that iterates over all properties and returns only class instances having a certain property.
My goal is a function like this:
def findInstances(listOfInstances, instanceVariable, instanceValue):
#return all instances in listOfInstances where instanceVariable==instanceValue
Using instance.__dict__ only gives me a and b, but not aAndB. I would like to have a dict of all properties/methods with their values to loop over, so I can search for instances where a certain property (or method decorated with #property) has a certain value.
Currently, calling the function like this
findInstances(someListOfInstances, 'aAndB', '23')
makes Python complain that aAndB is not in instance.__dict__.
Maybe all of you are right and the answers are there, but I still don't get it. All the answers in the mentioned questions get lists, not dictionaries. I want all the properties (including methods with the #property decorator) and their values. Is there a way to iterate over the values of the keys in dir(myClass)? The dir command only contains the names of the attributes, not their values.
I need something like
for a in dir(myClass):
print a, myClass.(a) # get the value for an attribute stored in a variable
To be even more clear: The following achieves exactly what I want but there is probably a better way that I don't know.
for a in dir(myClass):
print a, eval("myClass.{}".format(a))
There's actually a very simple way to do this, using getattr in place of eval:
myClass = MyClass()
for a in dir(myClass):
if(a[:2] != "__"): #don't print double underscore methods
print a, getattr(myClass, a)
Output:
a 7
aAndB 9
b 2
This has the very big advantage of not needing to hard code in the name of your instance into the string, as is required using eval("myClass.{}".format(a))
I have a python list that contains a set of objects (a class that has it's own
properties and functions and variables). I would like to extract some of the list elements and create a new list.
My question is: Are the new list elments going to remain same or they will be considered new instances of the class when I extract them from list?
For example: List layer = [myclass1, myclass2, myclass3]
I want new list layernew = [myclass1] or any such combination. How can I extract the items. When I print directly layer and new layer (by using newlayer=layer[0:1]) I see that it gives me the same instance reference of the object.
Are the new list elments going to remain same or they will be considered new instances of the class when I extract them from list.
They'll be the same. Demo:
class Widget:
def __init__(self, value):
self.value = value
a = [Widget(4), Widget(8), Widget(15)]
b = a[0:1]
print a[0] is b[0]
The output is True, so a[0] and b[0] are references to the same object.
One way to change this behavior is to use the copy module's deepcopy method. This will attempt to duplicate the object you give it and return a referentially distinct object with identical values.
import copy
class Widget:
def __init__(self, value):
self.value = value
a = [Widget(4), Widget(8), Widget(15)]
b = copy.deepcopy(a[0:1])
print a[0] is b[0]
#result: False
They are exactly the same objects. You can do identity tests with is in python.
layernew[0] is layer[0] # True
I have an object scene which is an instance of class Scene and has a list children which returns:
[<pythreejs.pythreejs.Mesh object at 0x000000002E836A90>, <pythreejs.pythreejs.SurfaceGrid object at 0x000000002DBF9F60>, <pythreejs.pythreejs.Mesh object at 0x000000002E8362E8>, <pythreejs.pythreejs.AmbientLight object at 0x000000002E8366D8>, <pythreejs.pythreejs.DirectionalLight object at 0x000000002E836630>]
If i want to update this list with a point which has type:
<class 'pythreejs.pythreejs.Mesh'>
I need to execute:
scene.children = list(scene.children) + [point]
Usually, I would execute:
scene.children.append(point)
However, while these two approaches both append point, only the first actually updates the list and produce the expected output (that is; voxels on a grid). Why?
The full code can be found here.
I am guessing your issue is due to children being a property (or other descriptor) rather than a simple attribute of the Scene instance you're interacting with. You can get a list of the children, or assign a new list of children to the attribute, but the lists you're dealing with are not really how the class keeps track of its children internally. If you modify the list you get from scene.children, the modifications are not reflected in the class.
One way to test this would be to save the list from scene.children several times in different variables and see if they are all the same list or not. Try:
a = scene.children
b = scene.children
c = scene.children
print(id(a), id(b), id(c))
I suspect you'll get different ids for each list.
Here's a class that demonstrates the same issue you are seeing:
class Test(object):
def __init__(self, values=()):
self._values = list(values)
#property
def values(self):
return list(self._values)
#values.setter
def values(self, new_values):
self._values = list(new_values)
Each time you check the values property, you'll get a new (copied) list.
I don't think there's a fix that is fundamentally different than what you've found to work. You might streamline things a little by by using:
scene.children += [point]
Because of how the += operator in Python works, this extends the list and then reassigns it back to scene.children (a += b is equivalent to a = a.__iadd__(b) if the __iadd__ method exists).
Per this issue, it turns out this is a traitlets issue. Modifying elements of self.children does not trigger an event notification unless a new list is defined.
Using python.....I have a list that contain names. I want to use each item in the list to create instances of a class. I can't use these items in their current condition (they're strings). Does anyone know how to do this in a loop.
class trap(movevariables):
def __init__(self):
movevariables.__init__(self)
if self.X==0:
self.X=input('Move Distance(mm) ')
if self.Vmax==0:
self.Vmax=input('Max Velocity? (mm/s) ')
if self.A==0:
percentg=input('Acceleration as decimal percent of g' )
self.A=percentg*9806.65
self.Xmin=((self.Vmax**2)/(2*self.A))
self.calc()
def calc(self):
if (self.X/2)>self.Xmin:
self.ta=2*((self.Vmax)/self.A) # to reach maximum velocity, the move is a symetrical trapezoid and the (acceleration time*2) is used
self.halfta=self.ta/2. # to calculate the total amount of time consumed by acceleration and deceleration
self.xa=.5*self.A*(self.halfta)**2
else: # If the move is not a trap, MaxV is not reached and the acceleration time is set to zero for subsequent calculations
self.ta=0
if (self.X/2)<self.Xmin:
self.tva=(self.X/self.A)**.5
self.halftva=self.tva/2
self.Vtriang=self.A*self.halftva
else:
self.tva=0
if (self.X/2)>self.Xmin:
self.tvc=(self.X-2*self.Xmin)/(self.Vmax) # calculate the Constant velocity time if you DO get to it
else:
self.tvc=0
self.t=(self.ta+self.tva+self.tvc)
print self
I'm a mechanical engineer. The trap class describes a motion profile that is common throughout the design of our machinery. There are many independent axes (trap classes) in our equipment so I need to distinguish between them by creating unique instances. The trap class inherits from movevariables many getter/setter functions structured as properties. In this way I can edit the variables by using the instance names. I'm thinking that I can initialize many machine axes at once by looping through the list instead of typing each one.
You could use a dict, like:
classes = {"foo" : foo, "bar" : bar}
then you could do:
myvar = classes[somestring]()
this way you'll have to initialize and keep the dict, but will have control on which classes can be created.
The getattr approach seems right, a bit more detail:
def forname(modname, classname):
''' Returns a class of "classname" from module "modname". '''
module = __import__(modname)
classobj = getattr(module, classname)
return classobj
From a blog post by Ben Snider.
If it a list of classes in a string form you can:
classes = ['foo', 'bar']
for class in classes:
obj = eval(class)
and to create an instance you simply do this:
instance = obj(arg1, arg2, arg3)
EDIT
If you want to create several instances of the class trap, here is what to do:
namelist=['lane1', 'lane2']
traps = dict((name, trap()) for name in namelist)
That will create a dictionary that maps each name to the instance.
Then to access each instance by name you do:
traps['lane1'].Vmax
you're probably looking for getattr.