I'm new to python threads and I can't find any answers for that. If it is a duplicate question sorry for that.
I have a thread class like this:
class Ant(Thread):
def __init__(self, start_item, possible_items, backpack_limit, pheromone_map, alpha, beta, eta):
Thread.__init__(self)
self.start_item = start_item
self.item = start_item
self.possible_items = possible_items
self.selected_items = []
self.backpack_limit = backpack_limit
self.weight_sum = 0
self.backpack_value = 0
self.pheromone_map = pheromone_map
self.alpha = alpha
self.beta = beta
self.eta = eta # (weight/value)
# append start location to route, before doing random walk
self.add_backpack(start_item)
self.tour_complete = False
def run(self):
while self.possible_items and self.is_remaining_space_feasible():
next_item = self.pick_item()
self.item = next_item
self.add_backpack(next_item)
self.tour_complete = True
def add_backpack(self, next_item):
self.update_items(next_item)
self.update_backpack(next_item)
def update_items(self, next_item):
self.selected_items.append(next_item)
self.possible_items.remove(next_item)
def update_backpack(self, next_item):
self.weight_sum += next_item.get_weight()
self.backpack_value += next_item.get_value()
and I create bunch of instances in another class like this:
ants = [Ant(self.items[random.randint(0, len(self.items) - 1)], self.items, self.backpack_limit, self.pheromone_matrix, self.alpha, self.beta, self.eta) for _ in range(self.ant_count)]
As you can see when I create an ant instance it's called add_backpack function and at some point this piece of code work self.possible_items.remove(next_item) and the program finished the initialization step and create the next instance. But for the next instance possible_items already removed the item and this caused list.remove(x): x not in list error. I tried deep copying but it's doesn't work.
Related
I'm trying to make a model where nodes connect to one and other using OOP. I'd like each node to store the names of its inputs and connections within lists and have these lists as attributes. The code seems to function perfectly outside of the "connect" function.
It creates desired Connection object, but it creates erroneous attributes for the destination node and origin nodes. The desired attributes are:
A.inputs = [],
A.outputs = [B]
B.inputs = [A]
B.outputs = [0]
But instead of that I get:
A.inputs = [A]
A.outputs = [B}
B.inputs = [A]
B.outputs = [B}
CONNECTIONS = []
NODES = []
class Zone:
def __init__(self, height, width):
self.height = height
self.width = width
class Node:
def __init__(self, name, initial_activation, activation_function = "linear", inputs = [], outputs = [], location = (0,0)):
global NODES
self.name = name
self.activation = initial_activation
self.activation_function = activation_function
self.inputs = inputs
self.outputs = outputs
self.location = location
NODES.append(self)
def __repr__(self):
return(f"Node {self.name}")
class Connection:
def __init__(self, origin, destination):
self.origin = origin.name
self.destination = destination.name
def __repr__(self):
return(f"Connection from {self.origin} to {self.destination}")
def connect(origin, destination):
new_connection = Connection(origin, destination)
origin.outputs.append(destination.name)
destination.inputs.append(origin.name)
global CONNECTIONS
CONNECTIONS.append(new_connection)
A = Node("A",0)
B = Node("B", 0, location = (100,100))
A.__dict__ # verify it is correct before hand
B.__dict__
test_connection = Connection(A,B)
test_connection.__dict__
connect(A,B) # create connection
A.__dict__ # show erroneous result
B.__dict__
CONNECTIONS
CONNECTIONS[0].__dict__ # verify connection object is correct
I have tried to debug using print statements, but to no avail. I believe the problem is found within lines 33 and 34 but I cannot see an error in those lines.
I see that Node class has mutable default arguments values for variables inputs and outputs.
In code, you don't pass values for this argument so A.input refers to same list as B.input.
print(id(A.inputs) == id(B.inputs))
will print True.
You need to get rid off mutable default argument, f.e doing this:
class Node:
def __init__(self, name, initial_activation, activation_function="linear",
inputs=None, outputs=None, location=(0, 0)):
# Some code
self.inputs = inputs or []
self.outputs = outputs or []
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 an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.
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
I am trying to grab the values from a class and use that particular value into another class. However I keep getting this error - AttributeError: 'CustomNodeTranslator' object has no attribute 'start'
Basically I am trying to get/transfer the values of self.start and self.end to be used into the ChanFileExporter class
I am not exactly sure why it is not working but when I applied this similar method in another portion of the code, it is working fine.
Any advises are greatly appreciated!
class CustomNodeTranslator(OpenMayaMPx.MPxFileTranslator):
def __init__(self):
OpenMayaMPx.MPxFileTranslator.__init__(self)
def haveWriteMethod(self):
return True
def haveReadMethod(self):
return True
def filter(self):
return "*.chan"
def defaultExtension(self):
return "chan"
def writer( self, fileObject, optionString, accessMode ):
self.start = []
self.end = []
for opt in filter(None, optionString.split(';')):
optSplit = opt.split('=')
if optSplit[1] == '0':
startAnimation = cmds.findKeyframe(which='first')
endAnimation = cmds.findKeyframe(which='last')
self.start = startAnimation
self.end = endAnimation
class ChanFileExporter():
def __init__(self, transform, startAnimation, endAnimation, cameraObj):
self.fileExport = []
testClass = CustomNodeTranslator()
mayaGlobal = OpenMaya.MGlobal()
mayaGlobal.viewFrame(OpenMaya.MTime(1))
startAnimation = testClass.start
endAnimation = testClass.end
for i in range(int(startAnimation), int(endAnimation + 1)):
...
...
The first time you see start or end in CustomNodeTranslator is in the writer() method.
self.start = []
self.end = []
It is bad practice to add attributes outside of __init__(); and the reason why it fails for you is because you are referring to attributes that do not yet exist since they are created only after you call writer().