Variable identity with Python __init__ function - can anyone explain? - list

I have a query about class init functions in Python. I was messing about trying to create a text adventure game type environment, with each room having an "items" property, stored as a list. I tried the following:
class Room:
def __init__(self,items=[]):
self.items=items
But what I find with this is that every room that does not have an item defined on initiation gets not only an empty list, but the same empty list. Now if I create a bunch of rooms and append an item to one of them, the item appears in every room.
Easy enough to fix (manually assign an empty list to every room) but I don't understand why this happens. I would imagine creating room a would create a.items as an empty list, and room b would create b.items. But can anyone explain why these would be identical? And is there a way to produce the above function with a default value that creates a different list each time?
Cheers,
Billy.

You have to understand default parameters in python.
When you write items=[], you create a global variable [], that you assign to item when a proper parameter is not provided.
This means every time items take the default value, it will be assigned the same [] object.
(Remember, as in Java, variables are just references to objects. All items variables will be references to the same object).
Formal explanation :
http://effbot.org/zone/default-values.htm
What you could do is :
def __init__(self, items=None):
if items is None:
items = []
self.items = items
this way, the default value, None, is never changed. When that is spotted, a new list is created (a real new list this time, not a global one).

Related

Remove similar items on an object list

I am populating a std::list<item*> itemslist from a text file, but there are instances where the name variable is the same, in those instances I want to remove the duplicated item (the item with the same name, other information of the item is irrelevant) but get data from that object to add to the 'original' (the first instance of the item)
Because I want to be able to load multiple information, aka an array of sorts into 'items' and this is what I have so far come up with
I tried to loop through items, then loop again and check the first loop against the second loop, copy the information and add to the array of the first loop item but it just breaks.
Suggestions?
Similar to this: Removing duplicates in a vector of strings
Except I want to use the information found in any duplicate and add it to a std::list that the item object holds
So if I load this:
Set Normal DIfficulty|Sets your save game to normal difficulty|/JKSV/Saves/Fire_Emblem__Awakening/hack/Chapter0|0x0D|0x00
Set Normal DIfficulty|Sets your save game to normal difficulty|/JKSV/Saves/Fire_Emblem__Awakening/hack/Chapter0|0x0F|0x0A
Set Hard DIfficulty|Sets your save game to hard difficulty|/JKSV/Saves/Fire_Emblem__Awakening/hack/Chapter0|0x0D|0x01
Set Lunatic DIfficulty|Sets your save game to lunatic difficulty|/JKSV/Saves/Fire_Emblem__Awakening/hack/Chapter0|0x0D|0x02
Set Lunatic+ DIfficulty|Sets your save game to lunatic+ difficulty|/JKSV/Saves/Fire_Emblem__Awakening/hack/Chapter0|0x0D|0x03
It will only have 1 Set Normal Difficulty item but that item will hold the duplicates last 2 pieces of information (aka 0x0F|0x0A
If you want your std::list<T> to erase duplicate values you have to call unique member function. There are two overloads of it. First take 0 arguments and compares values using operator==. It is not your case cause your list contains pointers and you don't need to compare addresses but name members. So try a second one. It takes a binary predicate where you can compare members
std::list<item*> myList;
// populate your list..
// sort it before calling unique..
myList.sort([](const item *lhs,const item *rhs)->bool{
return lhs->name < rhs->name;
});
myList.unique([](const item *lhs,const item *rhs)->bool{
return lhs->name == rhs->name;
});
// now your list has no duplicates..
More info here.

Ember data store.find() creating empty items when called with an invalid id

I have a list bound to model backed by a DS.RecordArray, as used the Ember data sample js fiddle. When I call this.store.find({id}) with a valid id, everything works as expected. However, when I call this.store.find({id}) with either a non-existing id or an empty string, an empty model is added to the DS.RecordArray, which is reflected in my bound list.
I've created an example of this behavior in a JSFiddle here. My example has two buttons to showcase two cases:
Calling find('post', 14) where 14 represents an id that does not exist. In this case, pressing this button once adds a blank element to the list and subsequent presses do nothing.
Calling find('post', '') where the empty string is passed instead of an id. In this case, every time this button is pressed, a blank element is added to the list.
Is this behavior expected? If so, what would be the best way to avoid these empty elements in my list?
store.find("type", id) will delegate to store.findById(type, id), which calls store.recordForId(type, id). If you check out the function body of recordForId(), you'll see that it checks the typeMap for the id, and if it doesn't exist, calls buildRecord(type, id), which creates a record of that type and adds it to the typeMap.
It's expected behavior in that it's clearly intended to do so, but whether it's a good idea or not can be argued.
It's not a good idea, for my application, so I override the store.findById to Ember.assert() on the id being truthy, since I'm never trying to find a record with 0, null, or undefined id's.

How to give a model object an order (or index), which can be reassigned?

Say you have an ordered list. You order the list based on a model field called "index". So the first item has an index of 0, the second has an index of 1 and so on...
The index is unique to that model object.
How would you implement this?
I want to be able to create more instances of the model object, where the index is assigned to the next available index (add the object to the end of the list). And then be able to reorder the list so that if you change the index of an object, all the following object's indexes increase by one.
If you want an IntegerField that increments itself you can use the id. It's unique for that model and Django generates it automatic. And you can order by this using
inverse:
MyModel.objects.all().order_by('-id')
Normal order:
MyModel.objects.all().order_by('id')
If you just have a field that contains auto-increment-index don't need to create another one only if you can modify it, but if this index is unique you cannot edit it to prevent duplicates. Si I would use the id MyModel.id
Here you have the documentation for .order_by()
There is no field that does that automatically. Have you looked in to using signals for this? You could hook up a signal that detects an index change, and triggers a function that updates the index of every object whose current index is greater than the one being removed/changed.
You may ave to rethink your schema because if you change the index of your first element in the list which has lets say 1 million elements, you are gonna update 1 million objects! You may save for each object its left and right "neighbour" and create a method to get the list.

Dart observable list removed items

I just started to use observable list in dart. It notifies when the list is updated. When it's a removing case, it only gives me the index it removes from and how many items were removed. How am I supposed to know which items were removed since I only have indices and the 'updated' list (the items have already been removed from it.) I want to know if I miss something before I manually put extra code in it.
Thanks,
yi
The List removeAt() method returns the removed object. So, you can simply assign the value of removeAt() to a variable, like this:
var list = [obj0, obj1, obj2];
var first = list.removeAt(0);

Is it possible to improve the process of instance creation/deletion in Django using querysets?

So I have a list of unique pupils (pupil is the primary_key in an LDAP database, each with an associated teacher, which can be the same for several pupils.
There is a box in an edit form for each teacher's pupils, where a user can add/remove an pupil, and then the database is updated according using the below function. My current function is as follows. (teacher is the teacher associated with the edit page form, and updated_list is a list of the pupils' names what has been submitted and passed to this function)
def update_pupils(teacher, updated_list):
old_pupils = Pupil.objects.filter(teacher=teacher)
for pupils in old_pupils:
if pupil.name not in updated_list:
pupil.delete()
else:
updated_list.remove(pupil.name)
for pupil in updated_list:
if not Pupil.objects.filter(name=name):
new_pupil = pupil(name=name, teacher=teacher)
new_pupil.save()
As you can see the function basically finds what was the old pupil list for the teacher, looks at those and if an instance is not in our new updated_list, deletes it from the database. We then remove those deleted from the updated_list (or at least their names)...meaning the ones left are the newly created ones, which we then iterate over and save.
Now ideally, I would like to access the database as infrequently as possible if that makes sense. So can I do any of the following?
In the initial iteration, can I simply mark those pupils up for deletion and potentially do the deleting and saving together, at a later date? I know I can bulk delete items but can I somehow mark those which I want to delete, without having to access the database which I know can be expensive if the number of deletions is going to be high...and then delete a lot at once?
In the second iteration, is it possible to create the various instances and then save them all in one go? Again, I see in Django 1.4 that you can use bulk_create but then how do you save these? Plus, I'm actually using Django 1.3 :(...
I am kinda assuming that the above steps would actually help with the performance of the function?...But please let me know if that's not the case.
I have of course been reading this https://docs.djangoproject.com/en/1.3/ref/models/querysets/ So I have a list of unique items, each with an associated email address, which can be the same for several items.
First, in this line
if not Pupil.objects.filter(name=name):
It looks like the name variable is undefined no ?
Then here is a shortcut for your code I think:
def update_pupils(teacher, updated_list):
# Step 1 : delete
Pupil.objects.filter(teacher=teacher).exclude(name__in=updated_list).delete() # delete all the not updated objects for this teacher
# Step 2 : update
# either
for name in updated_list:
Pupil.objects.update_or_create(name=name, defaults={teacher:teacher}) # for updated objects, if an object of this name exists, update its teacher, else create a new object with the name from updated_list and the input teacher
# or (but I'm not sure this one will work)
Pupil.objects.update_or_create(name__in=updated_list, defaults={teacher:teacher})
Another solution, if your Pupil object only has those 2 attributes and isn't referenced by a foreign key in another relation, is to delete all the "Pupil" instances of this teacher, and then use a bulk_create.. It allows only 2 access to the DB, but it's ugly
EDIT: in first loop, pupil also is undefined