[英]How to make sure parent method is always called before child overrides it in a decorator?
[英]How do I make sure a super method is called on child classes method on Python?
如何確保在父 class 方法中調用super
覆蓋父方法的子方法? 我在除 Python 以外的其他語言中發現了這個問題。
據我所知,沒有辦法強制子 class 方法在覆蓋它時必須調用父 class 方法。
盡管如此,解決方法可能是使用調用重寫方法的裝飾器。
基於這個答案,
import inspect
def get_class_that_defined_method(meth):
if inspect.ismethod(meth):
for cls in inspect.getmro(meth.__self__.__class__):
if meth.__name__ in cls.__dict__:
return cls
if inspect.isfunction(meth):
return getattr(inspect.getmodule(meth),
meth.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0],
None)
return None
def override(func):
def wrapper(*args, **kwargs):
cls = get_class_that_defined_method(func)
if hasattr(cls.__base__, func.__name__):
getattr(cls.__base__, func.__name__)(*args, **kwargs)
return func(*args, **kwargs)
return wrapper
這可以按如下方式使用。
class A:
def method(self):
print("call A.method")
class B(A):
@override
def method(self):
print("call B.method")
B().method()
# call A.method
# call B.method
這可以通過使用decorator
和metaclass
來實現
import inspect
def my_decorator(func):
def wrapper(self, *args, **kwargs):
has_super = False
for line in inspect.getsource(func).split('\n'):
if line.strip().startswith("super"):
has_super = True
break
if not has_super:
super_method = getattr(super(self.__class__, self), func.__name__, None)
if super_method:
super_method(*args, **kwargs)
func(self, *args, **kwargs)
return wrapper
class MyMeta(type):
def __new__(cls, name, bases, local):
for attr in local:
if callable(local[attr]):
local[attr] = my_decorator(local[attr])
return super().__new__(cls, name, bases, local)
class BaseClass:
def __init__(self):
print("BaseClass __init__")
def method1(self):
print("BaseClass method1")
def method2(self):
print("BaseClass method2")
class Child(BaseClass, metaclass=MyMeta):
def __init__(self):
print("Child __init___")
def method1(self):
print("Child method1")
def method2(self):
print("Child method2")
super().method2()
if __name__=="__main__":
a = Child()
a.method1()
a.method2()
Output
BaseClass __init__
Child __init___
BaseClass method1
Child method1
Child method2
BaseClass method2
雖然您不能強制調用超類,但您可以做的是在覆蓋另一個 function 時強制調用一個:
class Parent:
def other_method(self):
# code that would be in overridden function should be placed here
print("Hello from parent!")
def method(self):
pass
def run_method(self):
self.other_method()
self.method()
class Child(Parent):
def method(self):
print("Hello from child!")
myChild= Child()
# calling method() here will not have the desired effect, one needs to call run_method()
myChild.run_method()
這將產生以下 output:
Hello from parent!
Hello from child!
子方法在不調用super()
) 的情況下覆蓋method()
) 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.