【问题标题】:Is is possible to determine if a method was called via a property in Python3?是否可以确定是否通过 Python3 中的属性调用了方法?
【发布时间】:2015-08-03 20:54:28
【问题描述】:

总结

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

详情

我正在对一些代码进行一些 API 更改:旧 API 使用 Getters 和 Setters(GetAttrSetAttr),而新的公共 API 将分别使用 x.Attrx.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

【问题讨论】:

  • 是的,我就是这么想的。呃,好吧。我有一个备用计划,我只是不想这样做,因为我很懒 :-P

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


【解决方案1】:

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

【讨论】:

  • 是的,那是备用计划。
【解决方案2】:

另一种解决方案是包装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__ 以生成带有警告的 g​​etter 和 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 类似。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    • 2011-03-06
    • 1970-01-01
    • 2010-09-25
    • 1970-01-01
    相关资源
    最近更新 更多