python-3.x - 动态查找和“替换”方法时发生冲突
问题描述
我有一个由静态方法“列表”组成的类,A
. 我想用一个类装饰器来改变它的行为Meta
,它作用于一个特定的静态方法,在这个例子content
中,通过执行方法m
。
我最初的尝试CASE=2
没有按预期工作,所以我开始了我的案例研究。我介绍了一个新类B
,它对另一个方法的实现略有不同,info
但引发了一个有趣的错误,以及一个C
没有该方法的新类info
。
- 案例2:贪心案例
d[i] = classmethod(lambda cls, *args: mcs.m( getattr(target_cls, i)(*args)) )
它不能正常工作,可能是嵌套的动态表达式太多?
- 案例1:本质上是案例2,但表达式分为两行,并且有效
o = getattr(target_cls, i)
d[i] = classmethod(lambda cls, *args: mcs.m(o(*args)))
这里的代码
class Meta:
def __new__(mcs, target_cls):
if CASE == 1:
print('case 1')
d = {}
for i in dir(target_cls):
if i == 'content':
o = getattr(target_cls, i)
d[i] = classmethod(lambda cls, *args: mcs.m(o(*args)))
if CASE == 2:
print('case 2')
d = {}
for i in dir(target_cls):
if i == 'content':
d[i] = classmethod(lambda cls, *args: mcs.m( getattr(target_cls, i)(*args)) )
return type('AAA', (target_cls,), d)
@classmethod
def m(mcs, p):
return '--> ', p
class A:
@staticmethod
def content(response):
return 'static_method', response
@staticmethod
def info(response):
return response
class B:
@staticmethod
def content(response):
return 'static_method', response
@staticmethod
def info(response):
response.sort()
return response
class C:
@staticmethod
def content(response):
return 'static_method', response
# call the "content" class-method of each class for all different cases
for cls in (A, B, C):
print(cls.__name__)
for case in range(1,3):
CASE = case
R = Meta(cls)
try:
print(R.content('ppp'))
except Exception as e: print(e)
print()
输出
A
case 1
('--> ', ('static_method', 'ppp'))
case 2
('--> ', 'ppp') # no decoration
B
case 1
('--> ', ('static_method', 'ppp'))
case 2
'str' object has no attribute 'sort' # <- complained about the other method
C # <- this is ok BUT I removed the other method!
case 1
('--> ', ('static_method', 'ppp'))
case 2
('--> ', ('static_method', 'ppp')) # <- here the decoration took place
问题是为什么案例 2 不起作用,如果它是语言的限制,那么是什么样的?
额外问题:如何解释类B
案例2的错误
解决方案
我猜这个问题是由循环引起的,原因是每个语句都没有自己的范围(在循环中)。通过i
作为lambda
修复问题的关键参数传递。
class Meta:
def __new__(mcs, target_cls):
d = {}
for i in dir(target_cls):
if i == 'content':
d[i] = classmethod(lambda cls, *args, m_name=i: mcs.m( getattr(target_cls, m_name)(*args)) )
return type('AAA', (target_cls,), d)
@classmethod
def m(mcs, p):
return '--> ', p
class A:
@staticmethod
def content(response):
return 'static_method', response
@staticmethod
def info(response):
return response
print(A.content)
print(Meta(A).content)
print(Meta(A).content('a'))
print(Meta(A).info)
输出
<function A.content at 0x7f04500740d0> # original static method
<bound method Meta.__new__.<locals>.<lambda> of <class '__main__.AAA'>> # class method
('--> ', ('static_method', 'a'))
<function A.info at 0x7f0450074040>
推荐阅读
- javascript - 有没有办法解决我在响应式网站上的背景图片的这个小问题?
- excel-formula - 检查在任务上花费的时间的公式,参考允许的最短时间和将延长最小值的变量(如果存在)
- hibernate - Hibernate Criteria 查询没有给出完整的结果
- php - laravel 中的计数函数机制
- pandas - 如何访问 map_paritions 中的 dask 数据帧索引值?
- java - 带有 Docker Image 的 MAVEN 项目的 Gitlab CI
- c++ - C++ 中的 TEXT 到 IMAGE 转换器,无需使用任何库
- php - PHP中的eval()函数内的嵌套变量引用
- android - Flutter 插件无法在 Android 下运行
- swift - Swift - stopAnimating() - 只能在主线程中使用