- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想记录一个请求在请求末尾访问过一次的所有方法,以进行调试。
我可以先从一个课程开始:
这是我想要的输出示例:
logging full trace once
'__init__': ->
'init_method_1' ->
'init_method_1_1'
'init_method_2'
'main_function': ->
'first_main_function': ->
'condition_method_3'
'condition_method_5'
import types
class DecoMeta(type):
def __new__(cls, name, bases, attrs):
for attr_name, attr_value in attrs.items():
if isinstance(attr_value, types.FunctionType):
attrs[attr_name] = cls.deco(attr_value)
return super(DecoMeta, cls).__new__(cls, name, bases, attrs)
@classmethod
def deco(cls, func):
def wrapper(*args, **kwargs):
name = func.__name__
stacktrace_full.setdefault(name, [])
sorted_functions = stacktrace_full[name]
if len(sorted_functions) > 0:
stacktrace_full[name].append(name)
result = func(*args, **kwargs)
print("after",func.__name__)
return result
return wrapper
class MyKlass(metaclass=DecoMeta):
最佳答案
方法
我认为有两种不同的方法值得考虑这个问题:
“简单”日志记录元类,或者
Beefier元类可存储调用堆栈
如果您只需要在进行方法调用时就将它们打印出来,并且不关心保存方法调用堆栈的实际记录,那么第一种方法应该可以解决问题。
我不确定您要寻找哪种方法(如果您有什么特定的想法),但是如果您知道需要存储方法调用堆栈,除了打印调用之外,您可能还想跳到第二种方法方法。
注意:此后所有代码均假定存在以下导入:
from types import FunctionType
DecoMeta.__new__
的更改
DecoMeta.__new__
方法基本上保持不变。以下代码中最显着的更改是在
namespace
中添加了“ _in_progress_calls”列表。
DecoMeta.deco
的
wrapper
函数将使用此属性来跟踪已调用但未结束的方法数量。利用该信息,它可以适当缩进打印的方法名称。
staticmethod
装饰的
namespace
属性中包含
DecoMeta.deco
。但是,您可能不需要此功能。另一方面,您可能还想考虑进一步考虑
classmethod
和其他因素。
cls
变量,该变量将在返回之前直接进行修改。但是,您现有的遍历命名空间的循环,以及随后创建和返回类对象的操作,仍然可以解决问题。
DecoMeta.deco
的更改
in_progress_calls
设置为当前实例的
_in_progress_calls
,以便稍后在
wrapper
中使用
staticmethod
的方法进行了一些小的修改-如前所述,您可能想要或不想要的东西
pad
,在此行中打印被调用方法的
name
。打印后,我们将当前方法
name
添加到
in_progress_calls
,通知其他方法进行中的方法
staticmethod
。
self
调用中添加
func
参数来进行了一个很小但重要的更改。没有这个,使用
DecoMeta
的类的常规方法将开始抱怨没有给出位置
self
参数,这很重要,因为
func.__call__
是
method-wrapper
且需要实例我们的方法是绑定的。
in_progress_calls
值,因为我们已经正式调用了该方法并返回了
result
class DecoMeta(type):
def __new__(mcs, name, bases, namespace):
namespace["_in_progress_calls"] = []
cls = super().__new__(mcs, name, bases, namespace)
for attr_name, attr_value in namespace.items():
if isinstance(attr_value, (FunctionType, staticmethod)):
setattr(cls, attr_name, mcs.deco(attr_value))
return cls
@classmethod
def deco(mcs, func):
def wrapper(self, *args, **kwargs):
in_progress_calls = getattr(self, "_in_progress_calls")
try:
name = func.__name__
except AttributeError: # Resolve `staticmethod` names
name = func.__func__.__name__
#################### Log ####################
pad = " " * (len(in_progress_calls) * 3)
print(f"{pad}`{name}`")
in_progress_calls.append(name)
#################### Invoke Method ####################
try:
result = func(self, *args, **kwargs)
except TypeError: # Properly invoke `staticmethod`-typed `func`
result = func.__func__(*args, **kwargs)
in_progress_calls.pop(-1)
return result
return wrapper
class MyKlass(metaclass=DecoMeta):
def __init__(self):
self.i_1()
self.i_2()
#################### Init Methods ####################
def i_1(self):
self.i_1_1()
def i_1_1(self): ...
def i_2(self): ...
#################### Main Methods ####################
def main(self, x):
self.m_1(x)
def m_1(self, x):
if x == 0:
self.c_1()
self.c_2()
self.c_4()
elif x == 1:
self.c_3()
self.c_5()
#################### Condition Methods ####################
def c_1(self): ...
def c_2(self): ...
def c_3(self): ...
def c_4(self): ...
def c_5(self): ...
my_k = MyKlass()
my_k.main(1)
my_k.main(0)
`__init__`
`i_1`
`i_1_1`
`i_2`
`main`
`m_1`
`c_3`
`c_5`
`main`
`m_1`
`c_1`
`c_2`
`c_4`
_in_progress_calls
属性的范围。因此,我们可以在
DecoMeta.__new__
的顶部添加以下未注释的行:
namespace["full_stack"] = dict()
# namespace["_in_progress_calls"] = []
# cls = super().__new__(mcs, name, bases, namespace)
# ...
full_stack
属性的持久性,因为我们在
DecoMeta.__new__
中基于类进行了声明。如果我们不这样做,那么
MyKlass
的所有实例将共享同一个
full_stack
,从而迅速破坏了其用途。
full_stack
,我们可以添加一个新的
DecoMeta.__call__
方法,只要我们创建
MyKlass
的实例(或使用
DecoMeta
作为元类的任何实例),就会调用该方法。只需将以下内容放入
DecoMeta
:
def __call__(cls, *args, **kwargs):
setattr(cls, "full_stack", dict())
return super().__call__(*args, **kwargs)
full_stack
并添加代码以将其更新为
DecoMeta.deco.wrapper
函数。
full_stack
和值
Tuple[str]
来使
List[str]
为字典。请注意,在上述两个问题条件下,此操作都会自动失败;但是,它的确说明了如果您决定更进一步的话,
DecoMeta.deco.wrapper
必需进行的更新。
DecoMeta.deco.wrapper
签名的正下方,添加以下未注释的行:
full_stack = getattr(self, "full_stack")
# in_progress_calls = getattr(self, "_in_progress_calls")
# ...
print
调用之后的“日志”部分中,添加以下未注释的行:
# print(f"{pad}`{name}`")
full_stack.setdefault(tuple(in_progress_calls), []).append(name)
# in_progress_calls.append(name)
# ...
关于python - python-记录请求的旅程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55902280/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!