Skip to main content

How to Create Auto-Incrementing IDs in Python Classes

This guide explains how to create auto-incrementing IDs for instances of a Python class. We'll cover the recommended approach using itertools.count() for thread-safe ID generation, and contrast it with a manual (but less safe) approach using class variables.

How to Use itertools.count() (Recommended and Thread-Safe)

The itertools.count() function creates an iterator that produces consecutive integers. This is ideal for generating unique IDs, and it's thread-safe, which is important if your class might be used in a multi-threaded environment.

import itertools

class Employee():
_id_counter = itertools.count() # Create the counter, shared among all instances

def __init__(self, name, salary):
self.id = next(Employee._id_counter) # Get the next ID
self.name = name
self.salary = salary

alice = Employee('Alice', 100)
bob = Employee('Bob', 100)
carl = Employee('Carl', 100)

print(alice.id) # Output: 0
print(bob.id) # Output: 1
print(carl.id) # Output: 2
  • The code creates an object called _id_counter on the class, which is an iterator that can be called using the next() method to generate a new number every time it is called.

  • _id_counter = itertools.count(): This creates a class-level counter that starts at 0. The leading underscore (_) is a convention indicating that this attribute is intended for internal use within the class.

  • self.id = next(Employee._id_counter): Inside the __init__ method, next() is called on the class-level counter (Employee._id_counter, not self._id_counter). This gets the next integer from the counter and assigns it to the instance's id attribute. Each new instance gets a unique, incrementing ID.

Starting from a Different Value

itertools.count() accepts an optional start argument:

import itertools

class Employee():
_id_counter = itertools.count(start=1) # Start at 1 instead of 0

def __init__(self, name, salary):
self.id = next(Employee._id_counter)
self.name = name
self.salary = salary

alice = Employee('Alice', 100)
bob = Employee('Bob', 100)
carl = Employee('Carl', 100)
print(alice.id) # Output: 1
print(bob.id) # Output: 2
print(carl.id) # Output: 3
  • The start argument can be set to any integer and it will be the first value returned by the iterator.

Manual Incrementing with a Class Variable (Not Thread-Safe)

You can manually increment a class variable, but this approach is not thread-safe and is therefore not recommended for production code where multiple threads might create instances of your class concurrently:

class Employee():
cls_id = 0 # Class variable to store the ID counter

def __init__(self, name, salary):
self.id = Employee.cls_id
self.name = name
self.salary = salary
Employee.cls_id += 1 # Increment the class variable


alice = Employee('Alice', 100)
bob = Employee('Bob', 100)
carl = Employee('Carl', 100)

print(alice.id) # Output: 0
print(bob.id) # Output: 1
print(carl.id) # Output: 2
  • cls_id = 0: This initializes a class variable to store the ID counter.
  • self.id = Employee.cls_id: Assigns the current value of cls_id to the instance's id.
  • Employee.cls_id += 1: Increments the class variable.
warning

Thread Safety Issue: If multiple threads create Employee instances simultaneously, there's a risk of race conditions.

  • Two threads could read the same value of cls_id before either of them increments it, leading to duplicate IDs.
  • itertools.count() is inherently thread-safe.