[英]How can I pass an instance binding descriptor as a reference argument to a function?
如果沒有直接的解決方案,這可能有點棘手,但我也會對更復雜的解決方案感到滿意:
我有一個實例綁定數據描述符綁定到一個全局實例,我想將它作為 function 參數傳遞而不被評估(即__get__()
執行)。 在此代碼示例中,它不起作用,並且描述符將int
類型的當前值10
傳遞給 function 參數,而不是其自身:
"""A 'instance binding data descriptor' that sets and returns values
normally and prints a message logging their access.
The `x`-value is stored in the instance dictionary `my_instance.__dict__`.
"""
def __init__(self, init_value=None):
self.init_value = init_value
def __get__(self, instance, owner):
value = getattr(instance, self.__name__ + '_value')
print('I AM A DATA-DESCRIPTOR retrieving `{}` value: {}'.format(self.__name__, value))
return value
def __set__(self, instance, value):
print('I AM A DESCRIPTOR updating `{}` to value: {}'.format(self.__name__, value))
setattr(instance, self.__name__ + '_value', value)
class MyClass(object):
x = RevealAccess(init_value=10)
def __new__(cls):
instance = object.__new__(cls)
for desc_name in [key for key in cls.__dict__.keys() if isinstance(cls.__dict__[key], RevealAccess)]:
cls.__dict__[desc_name].__name__ = desc_name
instance.__dict__[desc_name + '_value'] = cls.__dict__[desc_name].init_value
return instance
my_instance = MyClass()
def func_with_descriptor_as_argument(descriptor_arg):
print('\n\nINSIDE the function `descriptor_arg=my_instance.x`results in: {}'.format(descriptor_arg))
print('`type(descriptor_arg)`: {}'.format(type(descriptor_arg)))
print('Changing `my_instance.x` value results in:')
descriptor_arg = 5
print('INSIDE the function after changing `my_instance.x` = {}\n\n'.format(descriptor_arg))
if __name__ == '__main__':
print('\n\nOUTSIDE the function `my_instance.x`: {}'.format(my_instance.x))
print('Changing `my_instance.x` value results in:')
my_instance.x = 5
print('OUTSIDE the function after changing `my_instance.x` = {}\n\n'.format(my_instance.x))
print('Reset:')
my_instance.x = 10
func_with_descriptor_as_argument(descriptor_arg=my_instance.x)
output 是:
I AM A DATA-DESCRIPTOR retrieving `x` value: 10
OUTSIDE the function `my_instance.x`: 10
Changing `my_instance.x` value results in:
I AM A DESCRIPTOR updating `x` to value: 5
I AM A DATA-DESCRIPTOR retrieving `x` value: 5
OUTSIDE the function after changing `my_instance.x` = 5
Reset:
I AM A DESCRIPTOR updating `x` to value: 10
I AM A DATA-DESCRIPTOR retrieving `x` value: 10
INSIDE the function `descriptor_arg=my_instance.x`results in: 10
`type(descriptor_arg)`: <class 'int'>
Changing `my_instance.x` value results in:
INSIDE the function after changing `my_instance.x` = 5
我明白它不是這樣工作的。 但我想要的是在 function 中操作全局實例字典值my_instance.__dict__['x_value']
。 我必須對許多實例和函數重復這一點,並且實際的描述符也在做其他事情(在這個例子中,它只打印“我是......”但在我的例子中,它是例如類型檢查、觸發其他進程等),所以不希望直接進行字典操作。 它必須由描述符完成。
我可以構建某種描述符來傳遞對 function 參數的引用,該參數的行為等效嗎?
我一直在尋找不同的選擇:
my_instance
和字符串名稱x
或作為元組傳遞,並在 function 中使用getattr()
、 setattr()
。 我不喜歡它,因為它是一個框架,對任何人都不好。inspect
,一些AST
包,然后在重載的__get__()
中構建一個適當的引用並返回它。 我可以管理檢測部分,但我不知道參考的外觀如何? 將其包裝在另一個描述符中? 最后,function 參數應該在 function 中像直接可調用的描述符一樣工作,但獲取/設置全局字典my_instance.__dict__['x_value']
(並執行提到的所有其他內容)。
我很高興有任何想法並期待討論!
我找到了一個很好的解決方案,它是一種類包裝器,如果您嘗試從中獲取不存在的屬性,則描述符所有者實例my_instance
在__getattr__()
中創建並返回。
調整上面的例子,解決方案看起來像這樣:
class RevealAccess(object):
"""A 'instance binding data descriptor' that sets and returns values
normally and prints a message logging their access.
The `x`-value is stored in the instance dictionary `my_instance.__dict__`.
"""
def __init__(self, init_value=None):
self.init_value = init_value
def __get__(self, instance, owner):
value = getattr(instance, self.__name__ + '_value')
print('I AM A DATA-DESCRIPTOR retrieving `{}` value: {}'.format(self.__name__, value))
return value
def __set__(self, instance, value):
print('I AM A DESCRIPTOR updating `{}` to value: {}'.format(self.__name__, value))
setattr(instance, self.__name__ + '_value', value)
class DescriptorReference:
def __init__(self, instance, descriptor_name):
self.__dict__['instance'] = instance
self.__dict__['descriptor_name'] = descriptor_name
def __getattr__(self, name):
return object.__getattribute__(self.instance, self.descriptor_name)
def __setattr__(self, dummy, value):
setattr(self.instance, self.descriptor_name, value)
class MyClass(object):
x = RevealAccess(init_value=10)
def __new__(cls):
instance = object.__new__(cls)
for desc_name in [key for key in cls.__dict__.keys() if isinstance(cls.__dict__[key], RevealAccess)]:
cls.__dict__[desc_name].__name__ = desc_name
instance.__dict__[desc_name + '_value'] = cls.__dict__[desc_name].init_value
return instance
def __getattr__(self, name):
return DescriptorReference(instance=self, descriptor_name=self.__class__.__dict__['x'].__name__)
my_instance = MyClass()
def func_with_descriptor_value_as_argument(descriptor_arg):
print('\n\nINSIDE the function `descriptor_arg=my_instance.x`results in: {}'.format(descriptor_arg))
print('`type(descriptor_arg)`: {}'.format(type(descriptor_arg)))
print('Changeing `my_instance.x` value results in:')
descriptor_arg = 5
print('INSIDE the function after changeing `my_instance.x` = {}\n\n'.format(descriptor_arg))
def func_with_descriptor_as_argument(descriptor):
print('\n\nINSIDE the function `descriptor_arg=my_instance.x`results in: {}'.format(descriptor.x))
print('`type(descriptor_arg)`: {}'.format(type(descriptor.x)))
print('Changeing `my_instance.x` value results in:')
descriptor.x = 5
print('INSIDE the function after changeing `my_instance.x` = {}\n\n'.format(descriptor.x))
if __name__ == '__main__':
x_ref = DescriptorReference(instance=my_instance,
descriptor_name=my_instance.__class__.__dict__['x'].__name__)
print('\n\nOUTSIDE the function `my_instance.x`: {}'.format(my_instance.x))
print('Changeing `my_instance.x` value results in:')
my_instance.x = 5
print('OUTSIDE the function after changeing `my_instance.x` = {}\n\n'.format(my_instance.x))
print('Reset:')
my_instance.x = 10
func_with_descriptor_as_argument(descriptor=my_instance.x_ref)
print('OUTSIDE the function after changeing INSIDE the function `my_instance.x` = {}\n\n'.format(my_instance.x))
現在通常您調用my_instance.x
來運行描述符並獲取/設置它的全局字典條目my_instance.__dict__['x']
的值並執行所有其他描述符的工作/工作。 通過將帶有不存在屬性調用的my_instance
作為參數傳遞給 function,例如func_...(descriptor=my_instance.x_ref)
, my_instance
在其__dict__
中未找到x_ref
后調用__getattr_()
。 然后__getattr__()
生成DecriptorReference()
並將其返回給 function 中的descriptor
參數。 在 function 中,您現在擁有完整的描述符功能,可以操作my_instance
的全局字典。 所以 function 內部的調用descriptor.x
與my_instance.x
外部的 my_instance.x 完全相同。
注意:在此實現中,您可以調用descriptor
上的任何屬性,它將與my_instance.x
相同,例如descriptor.made_my_day
。 如果不希望這樣做,可以使用if name == 'x':
在DescriptorReference.__getattr__()
中return
之前輕松更改
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.