Question: I need some help with descriptors in python. I wrote an automatic translator from perl to python (Pythonizer) and I'm trying to implement tied scalars, which is basically an object that acts as a scalar, but has FETCH and STORE operations that are called appropriately. I'm using a dynamic class namespace 'main' to store the variable values. I'm attempting to define __get__ and __set__ operations for the object, but they are not working. Any help will be appreciated! main = type('main', tuple(), dict()) class TiedScalar(dict): # Generated code - can't be changed FETCH_CALLED_v = 0 STORE_CALLED_v = 0 def STORE(*_args): _args = list(_args) self = _args.pop(0) if _args else None TiedScalar.STORE_CALLED_v = TiedScalar.STORE_CALLED_v + 1 self["value"] = _args.pop(0) if _args else None return self.get("value") #TiedScalar.STORE = lambda *_args, **_kwargs: perllib.tie_call(STORE, _args, _kwargs) def FETCH(*_args): _args = list(_args) self = _args.pop(0) if _args else None TiedScalar.FETCH_CALLED_v = TiedScalar.FETCH_CALLED_v + 1 return self.get("value") #TiedScalar.FETCH = lambda *_args, **_kwargs: perllib.tie_call(FETCH, _args, _kwargs) @classmethod def TIESCALAR(*_args): _args = list(_args) class_ = _args.pop(0) if _args else None self = {"value": (_args.pop(0) if _args else None)} #self = perllib.bless(self, class_) #return perllib.add_tie_methods(self) return add_tie_methods(class_(self)) def __init__(self, d): for k, v in d.items(): self[k] = v #setattr(self, k, v) def add_tie_methods(obj): # This code is part of perllib and can be changed cls = obj.__class__ classname = cls.__name__ result = type(classname, (cls,), dict()) cls.__TIE_subclass__ = result def __get__(self, obj, objtype=None): return self.FETCH() result.__get__ = __get__ def __set__(self, obj, value): return self.STORE(value) result.__set__ = __set__ obj.__class__ = result return obj main.tied_scalar_v = TiedScalar.TIESCALAR(42) # Generated code assert main.tied_scalar_v == 42 main.tied_scalar_v = 100 assert main.tied_scalar_v == 100 print(TiedScalar.FETCH_CALLED_v) print(TiedScalar.STORE_CALLED_v)  Here the 2 print statements print 1 and 0, so esp STORE is not being called, and fetch is not being called enough times based on the code. Note that 'main' stores all of the user's variables, also the TiedScalar class is (mostly) generated from the user’s perl code.

Answer: Ok - with your help, I was able to figure out how to do it. Basically I have to create a metaclass for my main, then use that class to store the initial object for tied scalars. Here is my updated code with changes marked # new: meta = type('mainmeta', (type,), { '__init__': lambda cls, name, bases, attrs: type.__init__(cls, name, bases, attrs) }) # new #main = type('main', tuple(), dict()) main = meta('main', tuple(), dict()) # new class TiedScalar(dict): # Generated code - can't be changed FETCH_CALLED_v = 0 STORE_CALLED_v = 0 def STORE(*_args): _args = list(_args) self = _args.pop(0) if _args else None TiedScalar.STORE_CALLED_v = TiedScalar.STORE_CALLED_v + 1 self["value"] = _args.pop(0) if _args else None return self.get("value") #TiedScalar.STORE = lambda *_args, **_kwargs: perllib.tie_call(STORE, _args, _kwargs) def FETCH(*_args): _args = list(_args) self = _args.pop(0) if _args else None TiedScalar.FETCH_CALLED_v = TiedScalar.FETCH_CALLED_v + 1 return self.get("value") #TiedScalar.FETCH = lambda *_args, **_kwargs: perllib.tie_call(FETCH, _args, _kwargs) @classmethod def TIESCALAR(*_args): _args = list(_args) class_ = _args.pop(0) if _args else None self = {"value": (_args.pop(0) if _args else None)} #self = perllib.bless(self, class_) #return perllib.add_tie_methods(self) return add_tie_methods(class_(self)) def __init__(self, d): for k, v in d.items(): self[k] = v #setattr(self, k, v) def add_tie_methods(obj): # This code is part of perllib and can be changed cls = obj.__class__ classname = cls.__name__ result = type(classname, (cls,), dict()) cls.__TIE_subclass__ = result def __get__(self, obj, objtype=None): #print(f'__get__({self}, {obj}, {objtype})') return self.FETCH() result.__get__ = __get__ def __set__(self, obj, value): #print(f'__set__({self}, {obj}, {value})') return self.STORE(value) result.__set__ = __set__ obj.__class__ = result return obj def assign_meta(cls, var, value): # new meta = cls.__class__ setattr(meta, var, value) return value # main.tied_scalar_v = TiedScalar.TIESCALAR(42) assign_meta(main, 'tied_scalar_v', TiedScalar.TIESCALAR(42)) # new assert main.tied_scalar_v == 42 main.tied_scalar_v = 100 assert main.tied_scalar_v == 100 print(TiedScalar.FETCH_CALLED_v) print(TiedScalar.STORE_CALLED_v)