是否可以确定是否通过 Python3 中的 属性 调用了方法?
Is is possible to determine if a method was called via a property in Python3?
总结
是否可以确定方法是通过 属性 调用而不是直接调用?
详情
我正在对某些代码进行一些 API 更改:旧的 API 使用 Getters 和 Setters(GetAttr
和 SetAttr
)以及新的 public API 将分别使用 x.Attr
和 x.Attr = val
。我想在程序员调用 GetAttr()
时添加弃用警告
有效,我要找的是这个神奇的_was called_via_property
函数:
import warnings
class MyClass(object):
def __init__(self):
self._attr = None
def GetAttr(self):
if not _was_called_via_property():
warnings.warn("`GetAttr()` is deprecated. Use `x.attr` property instead.", DeprecationWarning)
return self._attr
def SetAttr(self, value):
if not _was_called_via_property():
warnings.warn("deprecated", DeprecationWarning)
self._attr = value
Attr = property(GetAttr, SetAttr)
理想情况下,如果除了 property()
函数之外还通过装饰器定义事物,该解决方案也可以工作,但这不是必需的。
像这样:
@property
def attr(self):
if not _was_called_via_property():
warnings.warn("deprecated", DeprecationWarning)
return self._attr
@attr.setter
def attr(self, value):
if not _was_called_via_property():
warnings.warn("deprecated", DeprecationWarning)
self._attr = value
你无法区分 property
描述符访问和直接访问,不。
创建一个合适的 属性,并为其代理旧方法:
@property
def attr(self):
return self._attr
@property.setter
def attr(self, value):
self._attr = value
# legacy access to the attr property
def GetAttr(self):
warnings.warn("deprecated", DeprecationWarning)
return self.attr
def SetAttr(self, value):
warnings.warn("deprecated", DeprecationWarning)
self.attr = value
另一个解决方案是包装 property
:
def myprop(getter, setter):
return property(lambda self : getter(self, True),
lambda self, x : setter(self, x, True))
class MyClass(object):
def __init__(self):
self._attr = None
def GetAttr(self, called_via_property=False):
if not called_via_property:
warnings.warn("`GetAttr()` is deprecated. Use `x.attr` property instead.", DeprecationWarning)
return self._attr
def SetAttr(self, value, called_via_property=False):
if not called_via_property:
warnings.warn("deprecated", DeprecationWarning)
self._attr = value
Attr = myprop(GetAttr, SetAttr)
另一种解决方案可能是覆盖 __getattr__
和 __setattr__
以生成带有警告的吸气剂和 setters,例如:
class MyBase(object):
def __getattr__(self, key):
if key.startswith("Get"):
tail = key[3:]
if hasattr(self, tail):
def getter(self):
res = getattr(self, tail)
issue_warning()
return res
return lambda : getter(self)
raise AttributeError
与 setter 类似。
总结
是否可以确定方法是通过 属性 调用而不是直接调用?
详情
我正在对某些代码进行一些 API 更改:旧的 API 使用 Getters 和 Setters(GetAttr
和 SetAttr
)以及新的 public API 将分别使用 x.Attr
和 x.Attr = val
。我想在程序员调用 GetAttr()
有效,我要找的是这个神奇的_was called_via_property
函数:
import warnings
class MyClass(object):
def __init__(self):
self._attr = None
def GetAttr(self):
if not _was_called_via_property():
warnings.warn("`GetAttr()` is deprecated. Use `x.attr` property instead.", DeprecationWarning)
return self._attr
def SetAttr(self, value):
if not _was_called_via_property():
warnings.warn("deprecated", DeprecationWarning)
self._attr = value
Attr = property(GetAttr, SetAttr)
理想情况下,如果除了 property()
函数之外还通过装饰器定义事物,该解决方案也可以工作,但这不是必需的。
像这样:
@property
def attr(self):
if not _was_called_via_property():
warnings.warn("deprecated", DeprecationWarning)
return self._attr
@attr.setter
def attr(self, value):
if not _was_called_via_property():
warnings.warn("deprecated", DeprecationWarning)
self._attr = value
你无法区分 property
描述符访问和直接访问,不。
创建一个合适的 属性,并为其代理旧方法:
@property
def attr(self):
return self._attr
@property.setter
def attr(self, value):
self._attr = value
# legacy access to the attr property
def GetAttr(self):
warnings.warn("deprecated", DeprecationWarning)
return self.attr
def SetAttr(self, value):
warnings.warn("deprecated", DeprecationWarning)
self.attr = value
另一个解决方案是包装 property
:
def myprop(getter, setter):
return property(lambda self : getter(self, True),
lambda self, x : setter(self, x, True))
class MyClass(object):
def __init__(self):
self._attr = None
def GetAttr(self, called_via_property=False):
if not called_via_property:
warnings.warn("`GetAttr()` is deprecated. Use `x.attr` property instead.", DeprecationWarning)
return self._attr
def SetAttr(self, value, called_via_property=False):
if not called_via_property:
warnings.warn("deprecated", DeprecationWarning)
self._attr = value
Attr = myprop(GetAttr, SetAttr)
另一种解决方案可能是覆盖 __getattr__
和 __setattr__
以生成带有警告的吸气剂和 setters,例如:
class MyBase(object):
def __getattr__(self, key):
if key.startswith("Get"):
tail = key[3:]
if hasattr(self, tail):
def getter(self):
res = getattr(self, tail)
issue_warning()
return res
return lambda : getter(self)
raise AttributeError
与 setter 类似。