3

Possible Duplicate:
Auto-incrementing IDs for Class Instances

I want to something like the following Java class in Python:

public class MyObject {
    private static int ID = 0;
    private final int id;
    public MyObject() {
        id = ID++;
    }
}

In this Java code, every myObject will have id and there will be no way that two objects could have the same ID (it's a one-threaded application).

Can I do something like this in Python?

Community
  • 1
  • 1
MAGx2
  • 3,149
  • 7
  • 33
  • 63
  • You really shouldn't call a variable `id` in Python, because that's the name of the built-in function that returns the identity of an object. – abarnert Nov 12 '12 at 22:22

3 Answers3

8

In Python, you can just refer directly to the class attribute:

class MyObject(object):
    ID = 0

    def __init__(self):
       self.id = MyObject.ID = MyObject.ID + 1

Demo:

>>> class MyObject(object):
...     ID = 0
...     def __init__(self):
...        self.id = MyObject.ID = MyObject.ID + 1
... 
>>> MyObject().id
1
>>> MyObject().id
2
>>> MyObject().id
3
>>> MyObject.ID
3
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Why is the `id` changing each time it is accessed? The code above doesn't do that. – Whymarrh Nov 12 '12 at 22:16
  • 1
    He only says each object needs a uid, not that they must be sequential. `id()` may work just as well for him (unless the small risk that the id of a GC'ed object could be reapplied to a new object is a concern). – Silas Ray Nov 12 '12 at 22:17
  • @Whymarrh, it's because each `id` is coming from a different object. Each new object is assigned a unique ID number. – Mark Ransom Nov 12 '12 at 22:17
  • That makes sense, I mistook creating a new object for accessing one. – Whymarrh Nov 12 '12 at 22:18
  • 1
    Note that the Java code assigns the id before incrementing while this code assigns after. – Mark Ransom Nov 12 '12 at 22:20
  • Instead of managing the counter manually, you could just use `idcounter = itertools.count()` in the class, and `self.id = next(MyObject.idcounter)`. (That also starts you off at 0, like the Java code.) – abarnert Nov 12 '12 at 22:34
2

As I mentioned in my comment on @Martjin Pieters' answer, the id() builtin may be good enough for your needs. id(obj) returns an id for any object in the system that is unique at the time of access (essentially, and in some interpreters literally, the memory address of the object). Unless your objects are being destroyed frequently but your id references need to stay valid even after destruction, id() should work for your unique id needs.

From docs:

[The value returned by id()] is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

Silas Ray
  • 25,682
  • 5
  • 48
  • 63
  • 1
    +1. But it's probably worth quoting either the docs ("This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.") or the similar `help(id)` text. – abarnert Nov 12 '12 at 22:25
1

@Martjin Pieters has the right idea, but I would suggest going with itertools.count for this one:

class MyObject(object):
    ID = itertools.count()

    def __init__(self):
       self.id = MyObject.ID.next()

>>> MyObject().id
0
>>> MyObject().id
1
>>> MyObject().id
2
>>> MyObject.ID
count(3)

Hope this helps

inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • What benefit does making an entire iterator object just to increment a single integer give? This use case doesn't really seem complex enough to justify the increased overhead. – Silas Ray Nov 12 '12 at 23:04
  • What happens if you accidentally hit `=` instead of `+`? What happens if you increment in multiple methods before you realize if you want to increment by `n!=1` instead, and so on... – inspectorG4dget Nov 13 '12 at 00:49
  • "What if you typo" is equally applicable to any solution. As to the other what ifs, the OP specifically stated his requirements. Over-engineering to support every hypothetical use case is not valuable. Design for the problem you have and the growth you can predict, not the what-if-this-is-used-to-store-the-nuclear-codes scenario. That is, unless you think you should have one of these in your home kitchen: http://www.foodprocessing-technology.com/contractors/industrial_ovens/sveba/sveba5.html – Silas Ray Nov 13 '12 at 14:36
  • I wasn't supporting "every possible use case". I was making one small change that would allow many other use cases to be supported if necessary. In either case, `c.next()` is cleaner than `MyClass._ID += 1`. It's not like I'm trying to get this to make me breakfast as an extension to its functionality - it's more like I'm getting it to be more flexible for the functionality it is intended – inspectorG4dget Nov 13 '12 at 15:39
  • Anyone that programs can understand `MyClass._ID += 1`. `MyClass._ID = c.next()` is much more arcane, not cleaner. – Silas Ray Nov 13 '12 at 16:46