Reputation: 3921
Here's what I'm trying to do. I'm trying to make a note app that creates a Note
that consists of NoteBlock
s. People would usually create Note
from the first block to the last so I want to somehow sort class instances by their order of creation.
Is there any way to somehow get the number of the instance's creation? The first instance I created would have 1 and the second 2 and so on.
Alternatively, I've thought of the other way to do this. If I can somehow make the newly created NoteBlock
to point to the previous block already created, I would be able to sort them like a simple linked list.
The worst way I can think of is to give each instance a physical self.created_at
attribute to order them by the time of creation but I think it is a dumb way to do it and hopefully there is another way.
Given my scenario, what do you suggest I do?
from datetime import datetime
Class NoteBlock():
def __init__(self):
self.contents = None
self.previous = None
self.created_at = datetime.now()
return
a = Foo()
b = Foo()
c = Foo()
d = Foo()
Upvotes: 0
Views: 739
Reputation: 48509
I would like to expand the class variable solution provided by Hkoof, by adding direct reference to the instancies, which can also help keeping a class-consistent instance list, allowing access to the previous/next created instance.
The only problem (which, actually, isn't covered by other solutions either) is that the removal of an instance requires an explicit method call, as del
won't suffice: __del__
is only called as soon as there's no reference left to the object. Since there's obviously no way to know if the user/programmer is keeping any reference to it, we need an explicit way to do that; it won't ensure that the instance will be garbage collected, as that will only happen as soon as there's no reference left to it.
class NoteBlock(object):
instancies = []
def __init__(self, id):
self.id = id
def __new__(cls, *args, **kwargs):
instancy = object.__new__(cls)
cls.instancies.append(instancy)
return instancy
def delete(self):
self.instancies.remove(self)
# the following property methods are only useful for "browsing" between the
# instance list
@property
def previous(self):
try:
# "-1" index returns the last object in the instancies list, we
# don't want that...
previous_index = self.instancies.index(self) - 1
assert previous_index >= 0
return self.instancies[previous_index]
except:
return
@property
def next(self):
try:
return self.instancies[self.instancies.index(self) + 1]
except:
return
# create some random objects
from random import randrange
scope_instance_list = []
print('Creating instancies:')
for i in range(8):
index = randrange(100)
block = NoteBlock(index)
scope_instance_list.append(block)
print('\t{} - Block {} created'.format(i + 1, index))
# remove a single instance
toRemoveIndex = randrange(8)
toRemove = scope_instance_list.pop(toRemoveIndex)
print('\nRemoving instance n. {} ({})...'.format(toRemoveIndex + 1, format(toRemove.id)))
# we can't use "del", as the __del__ magic method only works as soon as there is
# *no* reference left for the object: since we're keeping the "instancies" list
# it will never be called, then we need to use an "internal" way to do that;
# keep in mind that if you have *any* reference to that object, it will never be
# garbage collected until it's "released".
toRemove.delete()
print('Done!\n')
# show the current instance list, including previous and next instancies,
# according to the existing objects
print('Remaining instance list (class instance based):')
for i, inst in enumerate(block.instancies):
print('\t{} - Block {}: previous: {}, next: {}'.format(
i + 1,
inst.id,
inst.previous.id if inst.previous else None,
inst.next.id if inst.next else None))
Example output:
Creating instancies:
1 - Block 10 created
2 - Block 23 created
3 - Block 4 created
4 - Block 28 created
5 - Block 9 created
6 - Block 67 created
7 - Block 70 created
8 - Block 73 created
Removing instance n. 5 (9)...
Done!
Remaining instance list (class instance based):
1 - Block 10: previous: None, next: 23
2 - Block 23: previous: 10, next: 4
3 - Block 4: previous: 23, next: 28
4 - Block 28: previous: 4, next: 67
5 - Block 67: previous: 28, next: 70
6 - Block 70: previous: 67, next: 73
7 - Block 73: previous: 70, next: None
Upvotes: 0
Reputation: 796
You can use a class variable to keep track of the number of instances created:
class NoteBlock:
instance_count = 0 # <== Note strange placement:
# it's a class variable (also
# called "class attribute")
def __init__(self):
NoteBlock.instance_count += 1 # <== Note class namespace (NoteBlock)
self.instance_number = NoteBlock.instance_count
def __str__(self):
return str(self.instance_number)
note1 = NoteBlock()
note2 = NoteBlock()
note3 = NoteBlock()
note4 = NoteBlock()
# ...and for good measure, assign note2 another instance
#
note2 = NoteBlock()
print(note1)
print(note2)
print(note3)
print(note4)
Output:
1
5
3
4
Upvotes: 2
Reputation: 224
An object doesn't save the time of instantiation automatically; to do so you have to add an attribute and save at __init__
the time (as you showed).
But if you don't like to create an attribute of the object itself you can as well have a data structure outside containing the object in order, for example a simple list:
foos = []
foos.append(Foo())
...
foos.append(Foo())
...
foos.append(Foo())
...
foos[0] #the first created
foos[1] #the second
foos[2] #the third
Upvotes: 1