Is it possible to create a class of integer where an instance of a certain class (say AutomaticCounter
) will increase itself by some number (say 1) each time it is called?
>>> n = AutomaticCounter(start=0)
>>> print(n)
1
>>> print(n)
2
This is what I have tried so far:
class AutomaticCounter(int):
def __init__(self):
self = 0
def __str__(self):
self = self + 1
return self
If you really, really, really need to mangle an immutable and built-in type, then you can create a kind-of "pointer" to it:
This, however, doesn't make the type immutable per se. If you do
print(f"{self=}")
at the beginning of__str__()
you'll see the instance is unchanged, so you effectively have a size of 2xint()
(+ some trash) for your object and you access the real instance viaself.ptr
.It wouldn't work with
self
alone asself
is merely a read-only reference (created via__new__()
) passed to instance's methods as the first argument, so something like this:and you doing the assignment would, as mentioned by Daniel, simply assign a new value to the local variable named
instance
(self
is just a quasi-standard name for the reference) which doesn't really change the instance. Therefore the next solution which looks similar would be a pointer and as you'd like to manipulate it the way you described, I "hid" it to a custom member calledptr
.As pointed out by user2357112, there is a desynchronization caused by the instance being immutable, therefore if you choose the
self.ptr
hack, you'll need to update the magic methods (__*__()
), for example this is updating the__add__()
. Notice theint()
calls, it converts it toint()
to prevent recursions.However, anything that attempts to pull the raw value or tries to access it with C API will most likely fail, namely reverse operations e.g. with immutable built-ins should be the case as for those you can't edit the magic methods reliably so it's corrected in all modules and all scopes.
Example:
with exception of
list.__mul__()
for some reason. When I find the code line in CPython, I'll add it here.Or, a more sane solution would be to create a custom and mutable object, create a member in it and manipulate that. Then return it, stringified, in
__str__
: