动态查找和 "replace" 方法时发生冲突
Conflicts when find and "replace" a method dynamically
我有一个 class 由静态方法“列表”组成,A
。我想用 class-装饰器 Meta
改变它的行为,它作用于特定的静态方法,在这个例子中 content
,通过执行方法 m
.
我最初的尝试 CASE=2
没有达到预期效果,所以我开始了案例研究。我引入了一个新的 class B
,它与其他方法 info
的实现略有不同,但引发了一个有趣的错误,而新的 class 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 不工作,如果它是语言的限制那么是哪种?
附加问题:classB
案例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>
我有一个 class 由静态方法“列表”组成,A
。我想用 class-装饰器 Meta
改变它的行为,它作用于特定的静态方法,在这个例子中 content
,通过执行方法 m
.
我最初的尝试 CASE=2
没有达到预期效果,所以我开始了案例研究。我引入了一个新的 class B
,它与其他方法 info
的实现略有不同,但引发了一个有趣的错误,而新的 class 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 不工作,如果它是语言的限制那么是哪种?
附加问题:classB
案例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>