python - 从帧中检测方法与哪个类关联

标签 python super internal sys python-3.7

我正在用 Python 编写一段令人难以置信的 hackish 的不完全生产代码,我需要某种方法来检测 _XYZ__foo 是否存在。属性访问是从名为 /_*XYZ/ 的类上定义的方法调用的。 。不过,这并不那么容易,因为我需要检测原始方法访问,以防任何内容被覆盖 __getattribute__并调用super() .

我不擅长解释,所以...规则类似于Java的private ,除了我想防止作弊。 (是的,我知道这与 Python 哲学背道而驰;请耐心听我说。)

我目前的攻击计划是:

  1. 使用re.compile('_(?P<class>.*?)__(?P<name>.*)')检测类的名称(前面的 _ 被删除)。
  2. 攀爬super链条 sys._getframe(n)找出属性访问的位置。
  3. 以某种方式检测它在哪个类(class)。我被困在这里了。

我也许可以通过模拟 super 来做到这一点正在 MRO 中行走,但我更愿意依赖检测,因为检查 super 所调用的内容而用户函数调用的内容是很难的。

所以,回答我的实际问题。给定一个框架,如何检测方法与哪个类关联?如果我有权访问函数对象,我可以做 f.__qualname__[:-1-len(f.__name__)] ,但我不这样做(或者至少,我不认为我这样做)。事实上,我不知道该怎么做!

这是一个简单的示例,演示了我想要做的事情:

import sys
import re
import itertools
import builtins
from builtins import __build_class__

def build_class(func, name, *bases, metaclass=None, **kwds):
    if bases[-1] is object:
        bases = bases[:-1]
    bases += HackishClass, object
    if metaclass is None:
        return __build_class__(func, name, *bases, **kwds)
    return __build_class__(func, name, *bases, metaclass=metaclass, **kwds)

private_regex = re.compile('_(?P<class>.*?)__(?P<name>.*)')
class HackishClass:
    __slots__ = ()
    def __getattribute__(self, key):
        match = private_regex.match(key)
        if match is not None:
            for depth in itertools.count(1):
                frame = sys._getframe(depth)
                if ...:  # snip
                    # Check for the original attribute access here.
                    break
            class_name = ...  # HERE! MAGIC GOES HERE!
            if class_name != match['class']:
                raise AttributeError("This is private! Keep out.")
        return super().__getattribute__(key)

builtins.__build_class__ = build_class

最佳答案

据我所知,没有办法直接从框架对象中获取发生属性访问的方法。但是,我们可以获得该方法的 code object 。然后我们可以搜索该对象的 MRO,直到找到该代码对象所属的方法。

private_regex = re.compile('_(?P<class>.*?)__(?P<name>.*)')
class HackishClass:
    __slots__ = ()

    def __getattribute__(self, key):
        match = private_regex.match(key)
        if match is None:
            # not a private attribute, no problem
            return super().__getattribute__(key)

        # obtain the code object of the calling function
        calling_codeobj = inspect.currentframe().f_back.f_code

        # iterate the MRO until we find a class with the name from `key`
        classname = match.group('class')
        for cls in type(self).mro():
            if cls.__name__ != classname:
                continue

            # check if the code object belongs to a method defined in this class
            for thing in vars(cls).values():
                if getattr(thing, '__code__', None) is calling_codeobj:
                    # found it! allow the attribute access
                    return super().__getattribute__(key)

        raise AttributeError("This is private! Keep out.")

一个小演示:

class Foo:
    def __init__(self):
        self.__foo = 5
        print(self.__foo)

f = Foo()           # prints 5
print(f._Foo__foo)  # throws AttributeError

关于python - 从帧中检测方法与哪个类关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52060860/

相关文章:

css - 如何在 CakePHP 中创建 CSS 内部样式表

java - java子类的私有(private)final字段可以在 super 构造函数完成之前初始化吗?

java - JLS 8 关于关键字 super 和 protected 成员

python - 如何在 Tkinter 列表框中插入时添加自动滚动?

python - 如何将列表插入 Python 中的 f 字符串?

java - class.super.method 和 class.method 有什么区别?

C# 设置程序集中所有类型都可访问的访问器,并仅获取派生类型的访问器。如何?

python - 你能用内部方法完全替换一个对象吗?

python - 使用python在桌面(windows/ubuntu)上绘图

python - 在 Python 中操作 MIDI 文件