python - 如何在调用某些方法时使用 getattr 或 getattribute 正确引发 ImportError
问题描述
您好,他们提前感谢您帮助我,
请看下面的代码:
import types
_MSG = ("Failed importing {name}. Please install {name}."
" Using pip install {name}")
class Empty(): # pylint: disable=too-few-public-methods
"""Empty class for beam API."""
def __call__(self, *args, **kwargs):
return None
class DummyBeam(types.ModuleType): # pylint: disable=too-few-public-methods
DoFn = Empty
Pipeline = Empty
def __init__(self, name="apache_beam"):
super(DummyBeam, self).__init__(name)
def __getattribute__(self, _):
if getattr(DummyBeam, _, None) is Empty:
err_msg = _MSG.format(name=self.__name__)
raise ImportError(err_msg)
我要检查的是否apache_beam
未安装它将成功加载所有光束类,如 DoFn 和管道,但调用某些函数会引发错误,请参阅下面的代码以查看上面使用的代码。
try:
import apache_beam as beam
except ImportError:
beam = DummyBeam()
class SomeFn(beam.DoFn):
pass
class SomeOtherFn(beam.Pipeline):
pass
SomeFn()
在上面的代码中,现在访问beam.DoFn
会引发错误,但我希望它在访问时不会引发错误,beam.DoFn
尽管它会在调用SomeFn()
. 还尝试替换getattribute
为getattr
,但它没有像我预期的那样给我结果,尽管它对所有代码都运行良好,但它在调用 SomeFn() 时不会引发错误。
感谢您查看这个。
解决方案
如回溯中所示(您应该已经发布了 FWIW),您的错误不是在调用 中,SomeFn()
而是在访问 类定义中。原因很明显:您通过简单的覆盖非常明确地指示 Python 这样做。beam.DoFn
SomeFn
Beam.__getattribute__
请注意,这object.__getattribute__
是属性查找的官方默认实现(每次 Python 看到obj.name
or getattr(obj, "name") 时都会调用它,除非您完全理解覆盖它的含义并且没有更好的解决方案。
在这种情况下,非常明显的解决方案是改为implempent ,如果无法以任何其他方式解析属性__getattr__
,它只会作为最后的手段调用。__getattribute__
你说:
也用 getattr 替换 getattribute 不起作用
但我只是在您的代码片段上尝试了它,它(当然)产生了我预期的结果。这是否是您的预期是另一个问题,但由于您既没有发布此版本的代码,也没有关心解释它是如何“不工作”的,所以在这一点上你不能指望任何答案(提示:“不工作”是对问题的完全无用的描述)。
最后一点:
它将成功加载所有梁方法,如 DoFn 和管道......在上面的代码中,现在调用 beam.DoFn
看来您对术语有些困惑。DoFn
并且Pipeline
是类,而不是方法,并且(如前所述)在访问 beam.DoFn
时会引发错误,而不是在调用时引发错误。
编辑:
by 不工作我的意思是当我尝试访问 beam.DoFn 或 SomeFn() 时使用 getattr 而不是 getattribute (...) 我想要的是在调用 someFn no access beam.DoFn 时引发错误
好的,看起来您并没有完全了解方法调用表达式的执行顺序。当你这样做
obj.method()
这实际上是一个捷径
method = obj.__getattribute__("method")
method.__call__()
所以覆盖__getattribute__
不是正确的解决方案(参见上面的),__getattr__
在这里定义是无用的——你的DummyBeam
类DoFn
有和Pipeline
属性,所以__getattr__
不会为这些名称调用。
beam.DoFn
现在,您在调用时没有得到任何异常的原因beam.Pipeline
是这些名称绑定到您的Empty
类,而不是该类的实例,因此您实际上从不调用Empty.__call__
. 类__call__
中定义的方法仅在调用该类的实例时使用,而不是在您实例化该类时使用(在这种情况下,__call__
调用的是元类的方法):
>>> class MyCallable:
... def __init__(self):
... print("in MyCallable.__init__")
... def __call__(self):
... print("in MyCallable.__call__")
...
>>>
... c = MyCallable()
in MyCallable.__init__
>>> c()
in MyCallable.__call__
>>>
因此,如果您想要在有人尝试实例化 DoFn
或“管道you either have to make them instances of
空空”时引发异常or keep them as they are and rename
。叫to
空。新which is the first method called by
类型。call(
type` 是所有类的默认元类)。
推荐阅读
- c# - Azure Functions,如何拥有多个 .json 配置文件
- tensorflow - 使用 TensorFlow2 的分布式学习不起作用
- angular - 在我的选择使用函数的地方为 mat-select 设置默认值?
- javascript - 下载文本文件并将文本作为字符串分配给变量 - Angular 7
- chart.js - Chart.js x轴标签在悬停时重复
- bash - 根据字符串中的 ID 删除重复的行
- python - 在熊猫数据框中按组滚动回归
- sql-server-2008 - 如何获取和处理 2 条记录,然后是连续对?
- qt - 文件夹对话框 QML
- java - 为什么我的自定义 JavaFX MapView 请求通过 OSM 获得 403 错误?