是否可以确定是否通过Python3中的属性调用了方法?

时间:2015-08-03 20:54:29

标签: python python-3.x properties deprecation-warning

摘要

是否可以确定方法是通过属性调用而不是直接调用?

详细信息

我正在对某些代码进行一些API更改:旧API使用Getters和Setters(GetAttrSetAttr),新的公共API将使用x.Attr和{{1 }} 分别。我想在程序员调用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()

2 个答案:

答案 0 :(得分:2)

您无法区分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

答案 1 :(得分:1)

另一种解决方案是包裹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__以生成带警告的getter和setter,例如:

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类似。