How to Keep Track of Class Instances

How to keep track of class instances?

One way to keep track of instances is with a class variable:

class A(object):
instances = []

def __init__(self, foo):
self.foo = foo
A.instances.append(self)

At the end of the program, you can create your dict like this:

foo_vars = {id(instance): instance.foo for instance in A.instances}

There is only one list:

>>> a = A(1)
>>> b = A(2)
>>> A.instances
[<__main__.A object at 0x1004d44d0>, <__main__.A object at 0x1004d4510>]
>>> id(A.instances)
4299683456
>>> id(a.instances)
4299683456
>>> id(b.instances)
4299683456

What's a good way to keep track of class instance variables in Python?

First of all: class attributes, or instance attributes? Or both? =)

Usually you just add instance attributes in __init__, and class attributes in the class definition, often before method definitions... which should probably cover 90% of use cases.

If code adds attributes on the fly, it probably (hopefully :-) has good reasons for doing so... leveraging dynamic features, introspection, etc. Other than that, adding attributes this way is probably less common than you think.

Is is possible to keep track of the current number of instances of a class?

You can achieve the gist of this as below, but this seems like a bad idea IMO; in particular:

  1. finalizers aren't free (and neither is IDisposable.Dispose())
  2. you can create objects without ever running a constructor (if you try hard enough)

Anyway, code:

public class CountableInstance
{
static int s_Total, s_Alive;
public CountableInstance() {
// need a separate total vs alive so we don't give duplicate
// InstanceIndex, at least for the first 4 billion objects
InstanceIndex = Interlocked.Increment(ref s_Total);
Interlocked.Increment(ref s_Alive);
}
~CountableInstance() {
Interlocked.Decrement(ref s_Alive);
}
public int InstanceIndex { get; }
public static int Alive => Volatile.Read(ref s_Alive);
public static int Total => Volatile.Read(ref s_Total);
}

Using metaclass to keep track of instances in python

The method on the metaclass that is called when each new instance of its "afiliated" classes is __call__. If you put the code to record the instances in there, that is all the work you need:


from weakref import WeakSet

# A convenient class-level descriptor to retrieve the instances:

class Instances:
def __get__(self, instance, cls):
return [x for x in cls._instances]

class Parallelizable(type):
def __init__(cls, name, bases, attrs, **kw):
super().__init__(name, bases, attrs, **kw)
cls._instances = WeakSet()
cls.instances = Instances()

def __call__(cls, *args, **kw):
instance = super().__call__(*args, **kw)
cls._instances.add(instance)
return instance

The same code will work without the descriptor at all - it is just a nice way to have a class attribute that would report the instances. But if the WeakSet is enough, this code suffices:


from weakref import WeakSet
class Parallelizable(type):
def __init__(cls, name, bases, attrs, **kw):
super().__init__(name, bases, attrs, **kw)
cls.instances = WeakSet()

def __call__(cls, *args, **kw):
instance = super().__call__(*args, **kw)
cls.instances.add(instance)
return instance

Keep track of state in class instance

You can create a type that can handle three cases:

  • Success: the value was fetched and it's now available
  • Loading: we are fetching the value
  • Failure: wasn't able to fetch the value (error)
type AsyncValue<T> = Success<T> | Loading<T> | Failure<T>;

Then you can define all those types with their custom guards:

class Success<T> {
readonly value: T;

constructor(value: T) {
this.value = value;
}

isSuccess(this: AsyncValue<T>): this is Success<T> {
return true;
}

isLoading(this: AsyncValue<T>): this is Loading<T> {
return false;
}

isError(this: AsyncValue<T>): this is Failure<T> {
return false;
}
}

class Loading<T> {
readonly loading = true;

isSuccess(this: AsyncValue<T>): this is Success<T> {
return false;
}

isLoading(this: AsyncValue<T>): this is Loading<T> {
return true;
}

isError(this: AsyncValue<T>): this is Failure<T> {
return false;
}
}

class Failure<T> {
readonly error: Error;

constructor(error: Error) {
this.error = error;
}

isSuccess(this: AsyncValue<T>): this is Success<T> {
return false;
}

isLoading(this: AsyncValue<T>): this is Loading<T> {
return false;
}

isError(this: AsyncValue<T>): this is Failure<T> {
return true;
}
}

Now you are ready to use the AsyncValue in your code:

function doSomething(val: AsyncValue<number>) {
if(val.isLoading()) {
// can only be loading
} else if (val.isError()) {
// can only be error
val.error
} else {
// can only be the success type
val.value // this is a number
}
}

which can be invoked with one of those:

doSomething(new Success<number>(123))
doSomething(new Loading())
doSomething(new Failure(new Error('not found')))

Concept to keep track of class instantiations in C++

Your problem is that the static map is filled inside the constructor, but outside of the constructor, the entry is gone. It seems like there are two different instances of the static map. You see one instance inside the constructor, and another instance outside of the constructor.

It looks like, you define your static map in a header file. Each .cpp file that includes the header file will "see" its own instance of the static map. Solution: Make a class which keeps the map as a static member. If this does not solve your problem, make also sure that you define the static member inside a .cpp file, like:

map<int, Dummy> TypeRegistry::Type_Map;



Related Topics



Leave a reply



Submit