python中用于实现perl的tie标量操作的描述符

sno*_*yjc 5 python python-descriptors

我需要一些有关 python 描述符的帮助。我编写了一个从 perl 到 python (Pythonizer) 的自动翻译器,并且我正在尝试实现绑定标量,它基本上是一个充当标量的对象,但具有适当调用的 FETCH 和 STORE 操作。我使用动态类命名空间“main”来存储变量值。我试图为该对象定义__get____set__操作,但它们不起作用。任何帮助将不胜感激!

\n
main = type('main', tuple(), dict())\n\nclass TiedScalar(dict):    # Generated code - can't be changed\n    FETCH_CALLED_v = 0\n    STORE_CALLED_v = 0\n\n    def STORE(*_args):\n        _args = list(_args)\n        self = _args.pop(0) if _args else None\n        TiedScalar.STORE_CALLED_v = TiedScalar.STORE_CALLED_v + 1\n        self["value"] = _args.pop(0) if _args else None\n        return self.get("value")\n    \n    \n    #TiedScalar.STORE = lambda *_args, **_kwargs: perllib.tie_call(STORE, _args, _kwargs)\n    \n    \n    def FETCH(*_args):\n        _args = list(_args)\n        self = _args.pop(0) if _args else None\n        TiedScalar.FETCH_CALLED_v = TiedScalar.FETCH_CALLED_v + 1\n        return self.get("value")\n    \n    \n    #TiedScalar.FETCH = lambda *_args, **_kwargs: perllib.tie_call(FETCH, _args, _kwargs)\n    \n    \n    @classmethod\n    def TIESCALAR(*_args):\n        _args = list(_args)\n        class_ = _args.pop(0) if _args else None\n        self = {"value": (_args.pop(0) if _args else None)}\n        #self = perllib.bless(self, class_)\n        #return perllib.add_tie_methods(self)\n        return add_tie_methods(class_(self))\n\n    def __init__(self, d):\n        for k, v in d.items():\n            self[k] = v\n            #setattr(self, k, v)\n\ndef add_tie_methods(obj):    # This code is part of perllib and can be changed\n    cls = obj.__class__\n    classname = cls.__name__\n    result = type(classname, (cls,), dict())\n    cls.__TIE_subclass__ = result\n\n    def __get__(self, obj, objtype=None):\n        return self.FETCH()\n    result.__get__ =  __get__\n\n    def __set__(self, obj, value):\n        return self.STORE(value)\n    result.__set__ = __set__\n\n    obj.__class__ = result\n    return obj\n\nmain.tied_scalar_v = TiedScalar.TIESCALAR(42)  # Generated code\nassert main.tied_scalar_v == 42\nmain.tied_scalar_v = 100\nassert main.tied_scalar_v == 100\nprint(TiedScalar.FETCH_CALLED_v)\nprint(TiedScalar.STORE_CALLED_v)\n
Run Code Online (Sandbox Code Playgroud)\n

这里 2 个打印语句打印 1 和 0,因此 esp STORE 没有被调用,并且 fetch 没有根据代码被调用足够的次数。请注意,“main”存储了所有用户的变量,TiedScalar 类(大部分)也是从 user\xe2\x80\x99s perl 代码生成的。

\n

sno*_*yjc 1

好的 - 在你的帮助下,我能够弄清楚该怎么做。基本上,我必须为 my 创建一个元类main,然后使用该类来存储绑定标量的初始对象。这是我更新的代码,标记了更改# 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)
Run Code Online (Sandbox Code Playgroud)