python - 分析所有类方法
问题描述
我正在阅读Practical Python Design Patterns并且正在尝试学习装饰器的概念。我停留在最后一个示例中,我无法获得编写适用于类的所有方法的分析器的逻辑。
这是书中的示例。由于文案限制,我没有在这里重写它,但我希望 Google Book 的链接足够。
问题是,当我实现代码并将其应用到我的DoMathStuff
班级时,我得到TypeError: 'NoneType' object is not callable
. 对我来说,这部try/except/else
分不清楚,我认为某处有错字,但我可以知道在哪里。
@profile_all_class_methods
class DoMathStuff(object):
"""docstring for DoMathStuff"""
def __init__(self, n):
self.n = n
def fib(self):
fPrev, f = 1, 1
for num in xrange(2, self.n):
fPrev, f = f, f + fPrev
return f
@profiling_decorator
def fact(self):
fct = 1
for num in xrange(1, self.n):
fct *= num
return fct
if __name__ == '__main__':
m = DoMathStuff(10)
print("Fib = {}, Fact = {}".format(m.fib(), m.fact()))
编辑:这是我得到的错误
Traceback (most recent call last):
File "class_profiler.py", line 62, in <module>
print("Fib = {}, Fact = {}".format(m.fib(), m.fact()))
TypeError: 'NoneType' object is not callable
解决方案
这段代码确实充满了错误。想想该__getattribute__
方法的流程:给定一个属性名称,我们在包装类上查找该属性(通过调用超类实现)。如果在那里找不到该属性 - 在“fib”的情况下不是这样,因为它在包装的类上,而不是包装器上 - Python 将引发 AttributeError。好的,我们抓住了这一点,大概是这样我们就可以继续在包装类上查找它。但是我们在 except 子句中做了什么?没有什么。由于某种原因,该代码位于 else 子句中,该子句仅在未引发异常时调用。
因此,如果我们通过从块中删除pass
和移动代码来解决这个问题,那会怎样呢?else
好吧,这现在想要得到self.inst
,即被包装类的实例。但是你猜怎么着,获取属性会调用__getattribute__
方法。所以我们递归。现在,获取inst
属性的原始调用将成功。我们将其分配给x
。怎么办?呃,没什么。我们退出而不返回 x。所以原始调用的值为 None self.inst
,并尝试调用__getattribute__
它 - 所以我们会得到另一个 AttributeError。
坦率地说,这段代码看起来像是由不太了解 Python 的人编写的。除了上面的更改之外,还可以通过返回超类调用的值而不是分配它来修复它:
def __getattribute__(self, s):
try:
return super(ProfiledClass, self).__getattribute__(s)
except AttributeError:
x = self.inst.__getattribute__(s)
if type(x) == type(self.__init__):
return profiling_decorator(x)
else:
return x
但这仍然是非常糟糕的代码。首先,你不应该直接调用双下划线方法,所以 except 之后的行应该是x = getattr(self.inst, s)
. 但问题远不止于此。__getattribute__
首先是完全错误的覆盖方法。所有属性查找都调用该方法,因此复杂的 try/super/except 东西。但是 Python 为您提供了一个方法,该方法仅在未直接找到属性时才调用,即__getattr__
. 相反,定义它可以让您完全删除大部分代码:
def __getattr__(self, s):
x = getattr(self.inst, s)
if type(x) == type(self.__init__):
return profiling_decorator(x)
else:
return x
(如果我真的很挑剔,我会用 . 替换那些type(x) == type(self.__init__)
东西if callable(x)
。)
这段代码中的最后一个错误是它们已经factorial
显式地装饰了,而代码的重点是方法将被自动装饰。
推荐阅读
- ios - 是否可以将 Brightcove 集成到 iOS 应用程序中?
- javascript - 如何在 javascript 或 typescript 字符串中插入变量值?
- react-native - 生产模式下的 babel-plugin-transform-remove-console React Native
- c# - 将 RichTextBox 中的彩色文本保存为 pdf
- php - 如果密钥已被使用,则显示“密钥已被使用”
- java - 当小时和分钟变量低于零时, moveForward(lostTime) 应该如何给出正确的输出?
- mysql - MySQL 说:#1064 - 你的 SQL 语法有错误;
- spring-boot - Heroku 上的 Keycloak 服务器
- node.js - 如何对使用 filestream 和 pngjs 创建的文件进行处理?
- c# - ASP。Net 应用程序在指定的路由 url 下工作正常,但在 http://locahost 上不工作