def track_attributes(cls):
class TrackedWrapper:
def __init__(self, value, count):
self.__dict__['_value'] = value
self.count = count
def __getattr__(self, name):
return getattr(self._value, name)
# Basic "Classical" representation
def __str__(self): return str(self._value)
def __repr__(self): return repr(self._value)
# Delegation for math/logic
def __bool__(self): return bool(self._value)
def __int__(self): return int(self._value)
def __add__(self, other): return self._value + other
def __radd__(self, other): return other + self._value
def __setattr__(self, name, value):
# 1. Use object.__getattribute__ to safely check for internal dicts
try:
counts = object.__getattribute__(self, '_attr_counts')
values = object.__getattribute__(self, '_attr_values')
except AttributeError:
# Initialize storage if it doesn't exist yet
object.__setattr__(self, '_attr_counts', {})
object.__setattr__(self, '_attr_values', {})
counts = object.__getattribute__(self, '_attr_counts')
values = object.__getattribute__(self, '_attr_values')
if name in ('_attr_counts', '_attr_values'):
object.__setattr__(self, name, value)
return
counts[name] = counts.get(name, 0) + 1
values[name] = value
def __getattribute__(self, name):
# 2. Immediate bypass for internal storage and dunder methods
if name in ('_attr_counts', '_attr_values', '__dict__') or name.startswith('__'):
return object.__getattribute__(self, name)
try:
counts = object.__getattribute__(self, '_attr_counts')
values = object.__getattribute__(self, '_attr_values')
except AttributeError:
return object.__getattribute__(self, name)
# 3. Handle specific logic for tracked attributes
if name in counts:
return TrackedWrapper(values.get(name), counts[name])
# 4. Unknown attribute logic
class Unknown:
def __getattr__(self, attr):
if attr == "count": return -1
raise AttributeError(f"'{cls.__name__}' object has no attribute '{name}'")
# If we reach here, the attribute isn't in our tracker.
# We return the Unknown proxy only if the user is about to ask for .count
return Unknown()
def __delattr__(self, name):
counts = object.__getattribute__(self, '_attr_counts')
values = object.__getattribute__(self, '_attr_values')
if name in values:
counts[name] = -2
values[name] = -2
cls.__setattr__ = __setattr__
cls.__getattribute__ = __getattribute__
cls.__delattr__ = __delattr__
return cls
@track_attributes
class A:
def __init__(self, x):
self.x = x
a = A(4.2)
a.x = 5.5
a.x= -2
print(a.x, a.x.count)
a.y = -1
print(a.y.count)
a.y = 2
print(a.y.count)
del a.x
print(a.x.count)
To embed this program on your website, copy the following code and paste it into your website's HTML: