Python random.sample not working properly? - python

I'm a complete nab with python.
But now I need a simple storage containing MyObject-objects for some project.
Each object contains a few StringProperties nothing fancy.
Now I want to get from my list of MyObjects, 10 random objects and store them in some other array.
So I went searching and found random.sample and started implemending it.
def get10RandomMyObjects():
# waarders maken
dict = {}
myObjectsList = []
# Lijst vullen
myObjects = MyObject.all()
randomMyObjects = random.sample(myObjects, 10)
for o in randomMyObjects:
dict_myObject = { }
#some random property setting
myObjectsList.append(dict_myObject)
dict['myObjects'] = myObjectsList
return dict
This is the error I get back:
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/random.py", line 314, in sample
n = len(population)
TypeError: object of type 'Query' has no len()
So obviously something is wrong with the random.sample but my noobness can't decypher what it is.
Anyone care to explain me why I can't obtain those 10 random MyObjects I so desire?

random.sample() works on lists. Obviously, MyObject.all() does not return a list but a Query object. If Query is at least iterable then you can write:
myObjects = list(MyObject.all())
Otherwise, you have to create a list from MyObject.all() manually.

Looks like the Query object is a generator. random.sample likes to know how many items there are in order to create the sample. So the simplest thing to do is put the items to be sampled in a list:
randomMyObjects = random.sample(list(myObjects), 10)

There is nothing wrong with random.sample(). What is happening is that myObjects is not a collection.
Most likely, myObjects is an iterator. You'll have to turn it into a list before using it in random.sample():
randomMyObjects = random.sample(list(myObjects),10)

You may also use:
randomMyObjects = MyObject.all().order_by('?')[:10]
Which is faster because it will let the database do the random ordering and only load the 10 first objects into memory.

Related

Access list from a function

I have created a function which returns a list
def GetAddressContainer(obj,obj1):
mylist = list()
for i in test['adresss']:
addresscotainer = i[id]
return mylist(addresscontainer)
When i call the function -
UkContainer = GetAddressContainer(Postcode,Country)
i get the following error message:
TypeError: 'list' object is not callable in python
Any ideas why i am getting this error and what i would have to update?
The problems seem to be in
return mylist(addresscontainer)
You using parentheses on the list and therefore calling it as a function, that's why you get the error. Without any more code I not entirely sure what to replace it with though.
Issues
The line mylist = list() basically creates an empty list which you can use to store any values. In the code mylist is being called (using (...)) which does not make sense in python since mylist is not a function.
Another issue with the code is that the value of addresscontainer is never being inserted into mylist.
Possible Solutions
So, as per your problem, either of the following solutions can be used:
Append addresscontainer into mylist iteratively within the for loop:
for i in test['adress']:
addresscontainer = i[id]
mylist.append(addresscontainer) # Inserts the value at the end of list
return mylist # Returns the list
[RECOMMENDED] Use list comprehension:
def GetAddressContainer(...):
return [i[id] for i in test['adress']] # Build list using "List Comprehension"
Replace mylist(addresscontainer) with list(addresscontainer) code.
Only list word could be a callable function because it defines a class of any list. And mylist = list() will be an instance of an abstract list, then, not callable.
change mylist = list() to mylist = []
it will create an empty list instead of a list object.
and you are not appending anything to the list.

Return multiple instances from an object in python

This question has no doubt been asked before, but I am not entirely sure how to search for it (since I do not know what it is called). So apologies in advance.
Alas, my problem is that I have a huge amount of objects
for i in range(1000):
M = subParts[0].get(parts['thing'][i])
Each M is an object that contains a lot of info about this model, now my job is to call four separate functions on this object, so that those functions can return four simple numbers as so:
for i in range(1000):
M = subParts[0].get(parts['thing'][i])
M.getItem1()
M.getItem2()
M.getItem3()
M.getItem4()
each of which returns a number, e.g.
4.5
5.7
3.7
2.9
My question is thus, what is an efficient way to do this? The above is very ugly but works, but there must be more efficient methods. Upon which I would just like to store the whole lot in a dictionary as so
myDict = { 0 : [4.5,5.7,3.7,2.9], ... , 999 : [2.5,3.7,5.7,2.9] }
Thanks.
def getdata(m):
return [m.getItem1(), m.getItem2(), m.getItem3(), m.getItem4()]
myDict = {i: getdata(subParts[0].get(parts['thing'][i])) for i in range(1000)}
Assuming that parts['thing'] is an ordered sequence that can be iterated over, you can use map to call subParts[0].get on each element of parts['thing'] so iterating over each M object could be done like this:
for M in map(subParts[0].get, parts['thing']):
...
Note that this will return a list in python 2 so using itertools.imap would be preferable.
To put it into dict comprehension you would just do:
stuff = {i:[M.getItem1(),
M.getItem2(),
M.getItem3(),
M.getItem4()]
for i,M in enumerate(map(subParts[0].get, parts['thing']))}

Python: Iterating through tuples which are related as subclassed tuples

I have the following tuples:
ReadElement = namedtuple('ReadElement', 'address value size')
LookupElement = namedtuple('LookupElement', ReadElement._fields[0:2] + ('lookups', ReadElement._fields[2]))
and I want to iterate through them as follows:
mytuples = [ReadElement(1,2,3), LookupElement(1,2,3,4)]
for address, value, lookups?, size in mytuples
if lookups is not None:
addLookups(lookups)
print address, value, lookups?, size
def addLookups(*items):
return sum(items)
How could I iterate through similar tuples using the same piece of code?
I think what I am looking for is a Union type of the two named tuples, so that that union type preserves the order of the tuples in the loop.
From laike9m post I can see how I can use the isinstance operator without having to unpack the tuples in the loop however I would like to avoid special casing the data and just go straight through without any if statements.
If these were objects I could do something like mytuples[0].execute() without having to worry about what type they were as long as they were were subclassed from the same parent and had that method implemented.
It seems that my question maybe a variant of the following Why are Super-class and Sub-class reversed? . In the case above I only have two items one subclass and one superclass where they are very similar to each other and therefore could also be made into a single class.
First, your namedtuple definition is wrong, should be:
LookupElement = namedtuple('LookupElement', ReadElement._fields[0:2] + ('lookups', ReadElement._fields[2]))
Second, you don't need to do worry about all that:
>>> for nt in mytuples:
print(nt)
ReadElement(address=1, value=2, size=3)
LookupElement(address=1, value=2, lookups=3, size=4)
I'm going to sleep so maybe I can't answer your futher question. I think the best way is to check whether the field you want exists before using it.
I don't know exactly what you want, here's what I'll do:
mytuples = [ReadElement(1,2,3), LookupElement(1,2,3,4)]
for nt in mytuples
if 'lookups' in nt._fields:
print nt.address, nt.value, nt.lookups, nt.size
else:
print nt.address, nt.value, nt.size

Syntax for adding sequential objects to a list

Very beginner question but it is driving me mad. sample1, sample2 etc. are Pygame.mixer.sound objects.
sample_list = []
sample_list.append(sample1)
sample_list.append(sample2)
sample_list.append(sample3)
Is fine, but I want to do that using a for style loop, e.g.
for j in range(1, 3, 1):
sample_list.append(sample + j)
But that is trying to add a number to a sound object so isn't right. I can add the equivalent string by;
for j in range(1, 3, 1):
sample_list.append("sample" + str(j))
But that doesn't refer to the objects I want, just adds those strings.
I've tried must permutations of syntax I can think of but it is still alluding me!
Thanks.
Don't store the objects in variables in the first place; store them directly into a list, and then you will be able to index them by integer.
If the integer identifiers are sparse, use a dict indexed by integer.
I would recommend storing these in a dict to begin with. It is almost the same effect for you to reference by a name, but without the explicit object symbol for each:
samples = {
"sample1": Sample(),
"sample2": Sample()
}
samples['sample3'] = Sample()
This is the preferred approach when you have a dynamic number of objects you are creating and want to be able to grab them by a name later. You can store 100's of these in your dict without cluttering up your namespace.
And later if you are trying to apply this to your loop, you can reference the string names:
for i in xrange(1,4):
sample_list.append(samples["sample" + str(i)])
As a side note another way to get attributes by name when they live on some object is to use getattr. Assume you have this:
class Sampler(object):
pass
sampler = Sampler()
sampler.sample1 = Sample()
sampler.sample2 = Sample()
sampler.sample3 = Sample()
You can then reference by name via: getattr(sampler, "sample1")
Note: As mentioned in comments by #Marcin, if you don't care about having a string identifier to be able to look up your items, and they are just purely sequential by number, you can use this same approach but with a list. It depends on your needs.
It is possible you might want to end up doing something like:
samples = {
"bang1": Sample(),
"bang2": Sample(),
"bang3": Sample(),
"shot1": Sample(),
"shot2": Sample(),
...
}
... Which would then allow you to look up sequential subsets of those sounds.
You can dynamically load variables from the locals() mapping:
for j in range(1, 4):
sample_list.append(locals()["sample" + str(j)])
Generally, you want to avoid such tricks; find other ways to store your sample variables, in a mapping or a list for example.
Looks like the wrong approach, but nevertheless.
sample_list = [eval('sample' + str(i)) for i in range(1, 4)]

How to compare an element of a tuple (int) to determine if it exists in a list

I have the two following lists:
# List of tuples representing the index of resources and their unique properties
# Format of (ID,Name,Prefix)
resource_types=[('0','Group','0'),('1','User','1'),('2','Filter','2'),('3','Agent','3'),('4','Asset','4'),('5','Rule','5'),('6','KBase','6'),('7','Case','7'),('8','Note','8'),('9','Report','9'),('10','ArchivedReport',':'),('11','Scheduled Task',';'),('12','Profile','<'),('13','User Shared Accessible Group','='),('14','User Accessible Group','>'),('15','Database Table Schema','?'),('16','Unassigned Resources Group','#'),('17','File','A'),('18','Snapshot','B'),('19','Data Monitor','C'),('20','Viewer Configuration','D'),('21','Instrument','E'),('22','Dashboard','F'),('23','Destination','G'),('24','Active List','H'),('25','Virtual Root','I'),('26','Vulnerability','J'),('27','Search Group','K'),('28','Pattern','L'),('29','Zone','M'),('30','Asset Range','N'),('31','Asset Category','O'),('32','Partition','P'),('33','Active Channel','Q'),('34','Stage','R'),('35','Customer','S'),('36','Field','T'),('37','Field Set','U'),('38','Scanned Report','V'),('39','Location','W'),('40','Network','X'),('41','Focused Report','Y'),('42','Escalation Level','Z'),('43','Query','['),('44','Report Template ','\\'),('45','Session List',']'),('46','Trend','^'),('47','Package','_'),('48','RESERVED','`'),('49','PROJECT_TEMPLATE','a'),('50','Attachments','b'),('51','Query Viewer','c'),('52','Use Case','d'),('53','Integration Configuration','e'),('54','Integration Command f'),('55','Integration Target','g'),('56','Actor','h'),('57','Category Model','i'),('58','Permission','j')]
# This is a list of resource ID's that we do not want to reference directly, ever.
unwanted_resource_types=[0,1,3,10,11,12,13,14,15,16,18,20,21,23,25,27,28,32,35,38,41,47,48,49,50,57,58]
I'm attempting to compare the two in order to build a third list containing the 'Name' of each unique resource type that currently exists in unwanted_resource_types. e.g. The final result list should be:
result = ['Group','User','Agent','ArchivedReport','ScheduledTask','...','...']
I've tried the following that (I thought) should work:
result = []
for res in resource_types:
if res[0] in unwanted_resource_types:
result.append(res[1])
and when that failed to populate result I also tried:
result = []
for res in resource_types:
for type in unwanted_resource_types:
if res[0] == type:
result.append(res[1])
also to no avail. Is there something i'm missing? I believe this would be the right place to perform list comprehension, but that's still in my grey basket of understanding fully (The Python docs are a bit too succinct for me in this case).
I'm also open to completely rethinking this problem, but I do need to retain the list of tuples as it's used elsewhere in the script. Thank you for any assistance you may provide.
Your resource types are using strings, and your unwanted resources are using ints, so you'll need to do some conversion to make it work.
Try this:
result = []
for res in resource_types:
if int(res[0]) in unwanted_resource_types:
result.append(res[1])
or using a list comprehension:
result = [item[1] for item in resource_types if int(item[0]) in unwanted_resource_types]
The numbers in resource_types are numbers contained within strings, whereas the numbers in unwanted_resource_types are plain numbers, so your comparison is failing. This should work:
result = []
for res in resource_types:
if int( res[0] ) in unwanted_resource_types:
result.append(res[1])
The problem is that your triples contain strings and your unwanted resources contain numbers, change the data to
resource_types=[(0,'Group','0'), ...
or use int() to convert the strings to ints before comparison, and it should work. Your result can be computed with a list comprehension as in
result=[rt[1] for rt in resource_types if int(rt[0]) in unwanted_resource_types]
If you change ('0', ...) into (0, ... you can leave out the int() call.
Additionally, you may change the unwanted_resource_types variable into a set, like
unwanted_resource_types=set([0,1,3, ... ])
to improve speed (if speed is an issue, else it's unimportant).
The one-liner:
result = map(lambda x: dict(map(lambda a: (int(a[0]), a[1]), resource_types))[x], unwanted_resource_types)
without any explicit loop does the job.
Ok - you don't want to use this in production code - but it's fun. ;-)
Comment:
The inner dict(map(lambda a: (int(a[0]), a[1]), resource_types)) creates a dictionary from the input data:
{0: 'Group', 1: 'User', 2: 'Filter', 3: 'Agent', ...
The outer map chooses the names from the dictionary.

Categories