Pulling an object out of a queue based on a data member - python

I need to extend Queue so that I can pluck an object out of the Queue based on the value of one of the object's data members.
I've solved the problem like this and I wonder if I'm being dense. Do I really need to do the list conversion to find the object?
class Datum:
def __init__(self, id):
self.id = id
def __str__(self):
return str(self.id)
class PluckQueue(Queue):
def pluck(self, id):
with self.not_empty:
plucked = None
while plucked is None:
pluck_list = list(self.queue)
try:
plucked = next(xx for xx in pluck_list if xx.id == id )
except StopIteration:
plucked = None
if plucked is None:
self.not_empty.wait()
else:
index = pluck_list.index(plucked)
self.queue.remove(pluck_list[index])
return plucked
def __str__(self):
return str([str(xx) for xx in self.queue])
pq = PluckQueue()
pq.put(Datum('a'))
pq.put(Datum('b'))
pq.put(Datum('c'))
plucked = pq.pluck('b')
print(plucked)
print(pq)
This gives the result:
b
['a', 'c']
Am I missing an easier way to do this?

This approach has worked fine and isn't so kludgy after all. The big difference one might make is to pass a predicate instead of having the test hardcoded into the next statement.

Related

divide classes into sub functions/classes python

First time poster and python newbie here, this question is probably asked before, but I am not able to find any answer.
I have a Class that reads robot status data, this works fine and I am able to dive my data into methods that are working fine when i call them. But I would like to divide my class even more, so the data is structured better. for example
I have some methods the reads and return target_data
def target_joint_positions(self):
t_j_p = self.read_data()[1:7]
return t_j_p
def target_joint_velocities(self):
t_j_v = self.read_data()[7:13]
return t_j_v
def target_joint_currents(self):
t_j_c = self.read_data()[19:25]
return t_j_c
And similar methods returning actual_data:
def actual_joint_positions(self):
a_j_p = self.read_data()[31:37]
return a_j_p
def actual_joint_velocities(self):
a_j_v = self.read_data()[37:43]
return a_j_v
def actual_joint_currents(self):
a_j_c = self.read_data()[43:49]
return a_j_c
So what I would like to accomplish is that when i make a instance of my class, instead of getting all the methods i would like something like this:
inst = Class_Name()
inst.target. (list of target methods)
inst.actual. (list of actual methods)
I have looked into nested classes and inheritance but I have not been successful in achieving my goal. Thanks for any pointers.
Welcome!
You can do the following:
class TargetMetrics:
def __init__(self, data):
self.data = data
def joint_positions(self):
return self.data[1:7]
...
class ActualMetrics:
def __init__(self, data):
self.data = data
def joint_positions(self):
return self.data[31:37]
...
class RobotMetrics:
def __init__(self):
data = read_data()
self.actual = ActualMetrics(data)
self.target = TargetMetrics(data)
...

Call a method on a new object from a variable

I have a class containing a list and some boolean methods.
class Cls:
data = [] // populated in __init__()
def flag1(self):
def flag2(self):
def flag3(self): # these all return booleans, based on the data
I want to create a higher level function, taking a parameter one of the flags, manipulating the data in a number of ways, applying the flag to the new data, and counting the number of results.
Something like:
def hof(self, fn):
count = 0
for i in range(1, 10):
new_obj = Cls(self.data+i)
if new_obj.fn():
count +=1
Is there any way to accomplish this without turning all the flags into static methods ?
===
Edit: Made it work, in a very hackish way:
class Cls:
data = []
def __init__(self):
self.data = value
class flag1(self):
return True
class flag2(self):
return False
# The hackish part
flag_dict = {
1: flag1,
2: flag2,
}
def hof(self, flag):
count = 0
for i in range(1,10):
new_obj = Cls(self.data + [i])
if self.flag_dict[flag](new_obj):
count +=1
return count
But it seems like a hack, and it's not quite understandable. Could someone point to a better way ?
Thanks.
You should be able to just pass the methods into the function like instance.hof(Cls.flag1), and internally, write it as if fn(new_obj):, with no need to make it a staticmethod.

Best way to do many try-except blocks within Python class assignments?

I have a class which is pulling JSON data with keys, but the problem is that per instance of this class, the JSON data may not have keys for everything I am trying to grab. Currently, my class is set up like this:
class Show():
def __init__(self, data):
self.data = data
self.status = self.data['status']
self.rating = self.data['rating']
self.genres = self.data['genres']
self.weight = self.data['weight']
self.updated = self.data['updated']
self.name = self.data['name']
self.language = self.data['language']
self.schedule = self.data['schedule']
self.url = self.data['url']
self.image = self.data['image']
And so on, there are more parameters than that. I'm trying to avoid the messiness of having a try-except block for EACH AND EVERY one of those (27) lines. Is there a better way? Ultimately, I want a parameter to be assigned None if the JSON key doesn't exist.
If you're going to set a default value to the attribute if it's not in the data dictionary, use data.get('key') rather than data['key']. The get method will return None if the key does not exist, rather than raising a KeyError exception. If you want a different default value than None, you can pass a second argument to get and that is what will be returned.
So, your code could become:
class Show():
def __init__(self, data):
self.data = data
self.status = self.data.get('status')
self.rating = self.data.get('rating')
self.genres = self.data.get('genres')
self.weight = self.data.get('weight')
self.updated = self.data.get('updated')
self.name = self.data.get('name')
self.language = self.data.get('language')
self.schedule = self.data.get('schedule')
self.url = self.data.get('url')
self.image = self.data.get('image')
Use dict.get, which provides a default value instead of raising an exception for missing keys.
For example, you can change this:
self.status = self.data['status']
into this:
self.status = self.data.get('status')
You could change your code to something like:
class Show():
def __init__(self, data):
self.data = data
self.__dict__.update(data)
data = {'status': True, 'ratings': [1,2,3], 'foo': "blahblah"}
aShow = Show(data)
"""
>>> aShow.status
True
>>> aShow.ratings
[1,2,3]
>>> aShow.something_not_in_dict
AttributeError: Show instance has no attribute 'something_not_in_dict'
"""
Which does exactly the same, and trying to access something from your Show instance that isn't a key in your data dictionary would raise an AttributeError

"Sub-classes" and self in Python

Note: I see that I need to more clearly work out what it is that I want each property/descriptor/class/method to do before I ask how to do it! I don't think my question can be answered at this time. Thanks all for helping me out.
Thanks to icktoofay and BrenBarn, I'm starting to understand discriptors and properties, but now I have a slightly harder question to ask:
I see now how these work:
class Blub(object):
def __get__(self, instance, owner):
print('Blub gets ' + instance._blub)
return instance._blub
def __set__(self, instance, value):
print('Blub becomes ' + value)
instance._blub = value
class Quish(object):
blub = Blub()
def __init__(self, value):
self.blub = value
And how a = Quish('one') works (produces "Blub becomes one") but take a gander at this code:
import os
import glob
class Index(object):
def __init__(self, dir=os.getcwd()):
self.name = dir #index name is directory of indexes
# index is the list of indexes
self.index = glob.glob(os.path.join(self.name, 'BatchStarted*'))
# which is the pointer to the index (index[which] == BatchStarted_12312013_115959.txt)
self.which = 0
# self.file = self.File(self.index[self.which])
def get(self):
return self.index[self.which]
def next(self):
self.which += 1
if self.which < len(self.index):
return self.get()
else:
# loop back to the first
self.which = 0
return None
def back(self):
if self.which > 0:
self.which -= 1
return self.get()
class File(object):
def __init__(self, file):
# if the file exists, we'll use it.
if os.path.isfile(file):
self.name = file
# otherwise, our name is none and we return.
else:
self.name = None
return None
# 'file' attribute is the actual file object
self.file = open(self.name, 'r')
self.line = Lines(self.file)
class Lines(object):
# pass through the actual file object (not filename)
def __init__(self, file):
self.file = file
# line is the list if this file's lines
self.line = self.file.readlines()
self.which = 0
self.extension = Extension(self.line[self.which])
def __get__(self):
return self.line[self.which]
def __set__(self, value):
self.which = value
def next(self):
self.which += 1
return self.__get__()
def back(self):
self.which -= 1
return self.__get__()
class Extension(object):
def __init__(self, lineStr):
# check to make sure a string is passed
if lineStr:
self.lineStr = lineStr
self.line = self.lineStr.split('|')
self.pathStr = self.line[0]
self.path = self.pathStr.split('\\')
self.fileStr = self.path[-1]
self.file = self.fileStr.split('.')
else:
self.lineStr = None
def __get__(self):
self.line = self.lineStr.split('|')
self.pathStr = self.line[0]
self.path = self.pathStr.split('\\')
self.fileStr = self.path[-1]
self.file = self.fileStr.split('.')
return self.file[-1]
def __set__(self, ext):
self.file[-1] = ext
self.fileStr = '.'.join(self.file)
self.path[-1] = fileStr
self.pathStr = '\\'.join(self.path)
self.line[0] = self.pathStr
self.lineStr = '|'.join(self.line)
Firstly, there may be some typos in here because I've been working on it and leaving it half-arsed. That's not my point. My point is that in icktoofay's example, nothing gets passed to Blub(). Is there any way to do what I'm doing here, that is set some "self" attributes and after doing some processing, taking that and passing it to the next class? Would this be better suited for a property?
I would like to have it so that:
>>> i = Index() # i contains list of index files
>>> f = File(i.get()) # f is now one of those files
>>> f.line
'\\\\server\\share\\folder\\file0.txt|Name|Sean|Date|10-20-2000|Type|1'
>>> f.line.extension
'txt'
>>> f.line.extension = 'rtf'
>>> f.line
'\\\\server\\share\\folder\\file0.rtf|Name|Sean|Date|10-20-2000|Type|1'
You can do that, but the issue there is less about properties/descriptors and more about creating classes that give the behavior you want.
So, when you do f.line, that is some object. When you do f.line.extension, that is doing (f.line).extension --- that is, it first evalautes f.line and then gets the extension attribute of whatever f.line is.
The important thing here is that f.line cannot know whether you are later going to try to access its extension. So you can't have f.line do one thing for "plain" f.line and another thing for f.line.extension. The f.line part has to be the same in both, and the extension part can't change that.
The solution for what you seem to want to do is to make f.line return some kind of object that in some way looks or works like a string, but also allows setting attributes and updating itself accordingly. Exactly how you do this depends on how much you need f.lines to behave like a string and how much you need it to do other stuff. Basically you need f.line to be a "gatekeeper" object that handles some operations by acting like a string (e.g., you apparently want it to display as a string), and handles other objects in custom ways (e.g., you apparently want to be able to set an extension attribute on it and have that update its contents).
Here's a simplistic example:
class Line(object):
def __init__(self, txt):
self.base, self.extension = txt.split('.')
def __str__(self):
return self.base + "." + self.extension
Now you can do:
>>> line = Line('file.txt')
>>> print line
file.txt
>>> line.extension
'txt'
>>> line.extension = 'foo'
>>> print line
file.foo
However, notice that I did print line, not just line. By writing a __str__ method, I defined the behavior that happens when you do print line. But if you evaluate it "raw" without printing it, you'll see it's not really a string:
>>> line
<__main__.Line object at 0x000000000233D278>
You could override this behavior as well (by defining __repr__), but do you want to? That depends on how you want to use line. The point is that you need to decide what you want your line to do in what situations, and then craft a class that does that.

how to select an object from a list of objects by its attribute in python

Apologies if this question has already been asked but I do not think I know the correct terminology to search for an appropriate solution through google.
I would like to select an object from a list of objects by the value of it's attribute, for example:
class Example():
def __init__(self):
self.pList = []
def addPerson(self,name,number):
self.pList.append(Person(self,name,number))
class Person():
def __init__(self,name,number):
self.nom = name
self.num = number
a = Example()
a.addPerson('dave',123)
a.addPerson('mike',345)
a.pList #.... somehow select dave by giving the value 123
in my case the number will always be unique
Thanks for the help
One option is to use the next() built-in:
dave = next(person for person in a.pList if person.num == 123)
This will throw StopIteration if nothing is found. You can use the two-argument form of next() to provide a default value for that case:
dave = next(
(person for person in a.pList if person.num == 123),
None,
)
A slightly more verbose alternative is a for loop:
for person in a.pList:
if person.num == 123:
break
else:
print "Not found."
person = None
dave = person
If those nom's are unique keys, and all you are ever going to do is access your persons using this unique key you should indeed rather use a dictionary.
However if you want to add more attributes over time and if you like to be able to retrieve one or more person by any of those attributes, you might want to go with a more complex solution:
class Example():
def __init__(self):
self.__pList = []
def addPerson(self,name,number):
self.__pList.append(Person(name,number))
def findPerson(self, **kwargs):
return next(self.__iterPerson(**kwargs))
def allPersons(self, **kwargs):
return list(self.__iterPerson(**kwargs))
def __iterPerson(self, **kwargs):
return (person for person in self.__pList if person.match(**kwargs))
class Person():
def __init__(self,name,number):
self.nom = name
self.num = number
def __repr__(self):
return "Person('%s', %d)" % (self.nom, self.num)
def match(self, **kwargs):
return all(getattr(self, key) == val for (key, val) in kwargs.items())
So let's assume we got one Mike and two Dave's
a = Example()
a.addPerson('dave',123)
a.addPerson('mike',345)
a.addPerson('dave',678)
Now you can find persons by number:
>>> a.findPerson(num=345)
Person('mike', 345)
Or by name:
>>> a.allPersons(nom='dave')
[Person('dave', 123), Person('dave', 678)]
Or both:
>>> a.findPerson(nom='dave', num=123)
Person('dave', 123)
The terminology you need is 'map' or 'dictionnary' : this will lead you to the right page in the python doc.
Extremely basic example:
>>> a = {123:'dave', 345:'mike'}
>>> a[123]
'dave'
The missing underscore makes plist a public property. I don't think that's what you want, since it does not encapsulate the functionality and you could call a.plist.append instead of a.addPerson.
class Example():
...
def filter(self, criteria):
for p in self.plist:
if criteria(p):
yield p
def getByNum(self, num):
return self.filter(lambda p: p.num == num)
dave = next(a.getByNum(123))
If the numbers are unique, you may also consider using a dictionary that maps from number to name or person instead of a list. But that's up to your implementation.

Categories

Resources