从帧中检测方法与 class 相关联
Detect, from a frame, which class a method is associated with
我正在 Python 中编写一段非常骇人听闻的非生产代码,我需要一些方法来检测 _XYZ__foo
属性访问是否从定义于一个叫 /_*XYZ/
的 class。不过,这并不那么容易,因为我需要检测 原始 方法访问,以防任何内容被覆盖 __getattribute__
并调用 super()
.
我不擅长解释,所以...规则类似于Java的private
,除了我想防止作弊。 (是的,我知道这与 Python 理念背道而驰;请耐心等待。)
我目前的攻击计划是:
- 使用
re.compile('_(?P<class>.*?)__(?P<name>.*)')
检测 class 的名称(删除前面的 _
)。
- 使用
sys._getframe(n)
攀登 super
链,找出属性访问的位置。
- 检测class它在...不知何故。我被困在这里了。
我可以通过模拟 super
的 MRO 运行来做到这一点,但我更愿意依赖检测,因为检查 super
调用了什么以及调用了什么通过用户功能很难。
所以,对于我的实际问题。给定一个框架,我如何检测方法与哪个 class 相关联?如果我可以访问函数对象,我可以 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 中编写一段非常骇人听闻的非生产代码,我需要一些方法来检测 _XYZ__foo
属性访问是否从定义于一个叫 /_*XYZ/
的 class。不过,这并不那么容易,因为我需要检测 原始 方法访问,以防任何内容被覆盖 __getattribute__
并调用 super()
.
我不擅长解释,所以...规则类似于Java的private
,除了我想防止作弊。 (是的,我知道这与 Python 理念背道而驰;请耐心等待。)
我目前的攻击计划是:
- 使用
re.compile('_(?P<class>.*?)__(?P<name>.*)')
检测 class 的名称(删除前面的_
)。 - 使用
sys._getframe(n)
攀登super
链,找出属性访问的位置。 - 检测class它在...不知何故。我被困在这里了。
我可以通过模拟 super
的 MRO 运行来做到这一点,但我更愿意依赖检测,因为检查 super
调用了什么以及调用了什么通过用户功能很难。
所以,对于我的实际问题。给定一个框架,我如何检测方法与哪个 class 相关联?如果我可以访问函数对象,我可以 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