【问题标题】:Determining scope / context of a method call in python在python中确定方法调用的范围/上下文
【发布时间】:2014-03-02 21:58:46
【问题描述】:

我想为 python 类方法编写一个装饰器,它可以确定该方法是从公共上下文还是私有上下文调用的。例如,给定以下代码

def public_check_decorator(f):
    def wrapper(self):
        if self.f is `called publicly`:  # <-- how do I make this line work correctly?
            print 'called publicly'
        else:
            print 'called privately'
        return f(self)
    return wrapper

class C(object):
    @public_check_decorator
    def public_method(self):
        pass

    def calls_public_method(self):
        self.public_method()

运行时执行在理想情况下应该是这样的:

>>> c = C()
>>> c.public_method()
called publicly

>>> c.calls_public_method()
called privately

有没有办法在 python 中做到这一点?也就是改行

if self.f is `called publicly`:  # <-- how do I make this line work correctly?

给出想要的输出?

【问题讨论】:

  • 只是出于好奇,您为什么需要这样做?
  • 你如何定义 public?是不是在任何函数之外调用?在全局函数中调用?别的东西?您是否定义了一个特定的堆栈作为函数的公共入口?
  • c.public_methodcalls_public_method 中的self.public_method 相同。那么您到底要检查什么?
  • @Blender 简短的回答——可能是最有用和最明显的——它可以让你强制执行私有范围(或抛出某种错误或错误)。但是,我的使用要复杂一些。给定一个允许延迟初始化类实例的元类(即延迟调用 init),仅在访问“公共”方法时触发 init 调用。或者,延迟到公开访问方法。是的,是的,我知道这里的 my 用例听起来很危险。而且它很可能永远不会看到任何生产代码。但我认为这仍然是一个有趣的问题。
  • @kalefranz 但它有什么不同?

标签: python python-2.7 metaprogramming decorator metaclass


【解决方案1】:

其中一些似乎是试图逆流而上“蟒蛇”。合适吗?

您知道双重不计分标准吗?它使方法“更加私密”:

>>> class C(object):
...    def __hide_me(self):
...        return 11
...    def public(self):
...        return self.__hide_me()
...
>>> c = C()
>>> c.__hide_me()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__hide_me'
>>> c.public()
11
>>> c._C__hide_me()
11
>>>

这够私密吗?而且使用这种技术是pythonic。

【讨论】:

  • 双下划线和名称修饰不是我想要的。我会争辩说,我正在尝试做的是以 pythonic 为核心的。我想用另一个函数包装一个类方法来影响该方法的行为。这就是装饰器和元类的全部意义所在,也是它们令人难以置信的强大(而且确实是 Pythonic!)的原因。我的主要帖子上的 cmets 可以被解读为我只是想让一个方法只具有私有访问权限;这是一个错误的解读,尽管它是一个潜在的用例。
【解决方案2】:

给定包的名称决定一个函数是从私有上下文还是从公共上下文中调用的:

import inspect
import re


def run():
    package_name = '/my_package/'
    p = re.match(r'^.*' + package_name, inspect.stack()[0].filename).group()
    is_private_call = any(re.match(p, frame.filename) is not None for frame in inspect.stack()[1:])
    print(is_private_call)

尝试从包内运行,然后从包外运行!!! 见inspect.stack()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多