sno*_*yjc 5 python python-descriptors
我需要一些有关 python 描述符的帮助。我编写了一个从 perl 到 python (Pythonizer) 的自动翻译器,并且我正在尝试实现绑定标量,它基本上是一个充当标量的对象,但具有适当调用的 FETCH 和 STORE 操作。我使用动态类命名空间“main”来存储变量值。我试图为该对象定义__get__和__set__操作,但它们不起作用。任何帮助将不胜感激!
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)\nRun Code Online (Sandbox Code Playgroud)\n这里 2 个打印语句打印 1 和 0,因此 esp STORE 没有被调用,并且 fetch 没有根据代码被调用足够的次数。请注意,“main”存储了所有用户的变量,TiedScalar 类(大部分)也是从 user\xe2\x80\x99s perl 代码生成的。
\n好的 - 在你的帮助下,我能够弄清楚该怎么做。基本上,我必须为 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)