简体   繁体   English

Python 如何从父元类调用子 class 方法

[英]Python How to call child class method from Parent metaclass

I am trying to write my own implementation of test runner, what I struggle with is some kind of setUp and TearDown methods and how to override/invoke them.我正在尝试编写自己的测试运行器实现,我遇到的是某种 setUp 和 TearDown 方法以及如何覆盖/调用它们。

class MetaTestCase(type):

    def __call__(self, *args, **kwds):
        return super().__call__(*args, **kwds)

    def __new__(self, name, bases, attrs):
        def replaced_fnc(fn):
            def new_test(*args, **kwargs):
                self.before(self)
                result = fn(*args, **kwargs)
                self.after(self)
                return result

            return new_test

        for i in attrs:
            if callable(attrs[i]):
                attrs[i] = replaced_fnc(attrs[i])

        return (super(MetaTestCase, self).__new__(self, name, bases, attrs))

    def before(self):
        print('Before')

    def after(self):
        print('After')


class TestCase(metaclass=MetaTestCase):
    pass


class TestSuite(TestCase):

    def before(self):
        print('New Before')

    def after(self):
        print('New After')

    def test(self):
        print("Test")


if __name__ == "__main__":
    TS = TestSuite()
    TS.test()

The current output of that is:当前的 output 是:

Before
Test
After

But the expected output would be to override those functions from metaclass with those from Child Class like that:但是预期的 output 将使用来自子类 Class 的函数覆盖元类中的这些函数,如下所示:

New Before
Test
New After

But I don't really know metaclasses very good and how to pass Child methods to the Parent class.但我真的不太了解元类以及如何将子方法传递给父 class。

Like chepner suggest u don't need a metaclass for this.就像 chepner 建议你不需要一个元类。 Define a test runner that takes the suite TS as an argument, and it just calls TS.before, TS.test, and TS.after explicitly and in sequence.定义一个将套件 TS 作为参数的测试运行器,它只是显式地依次调用 TS.before、TS.test 和 TS.after。

I just answer to question, how to call extra method from metaclass我只是回答问题,如何从元类中调用额外的方法

Here u can read more aboute metaclasses . 在这里你可以阅读更多关于元类的信息。 But quick answer will be, just use polymorphism.但快速的答案是,只需使用多态性。

So first of all u need to move your before and after method to parent class(not metaclass).所以首先你需要将你的前后方法移动到父类(而不是元类)。 In python when we work with objects, first argument is always self so we can use that like: args[0].before()在 python 中,当我们使用对象时,第一个参数始终是 self 所以我们可以像这样使用:args[0].before()

Next problem is infinite loop.下一个问题是无限循环。 We need to decied which function we need to overwrite in meta class, in my answaer I simple check if method name contain 'test', but u can create smth more sophisticated我们需要确定我们需要在元 class 中覆盖哪个 function,在我的回答中,我简单检查方法名称是否包含“测试”,但您可以创建更复杂的

class MetaTestCase(type):

    def __call__(self, *args, **kwds):
        return super().__call__(*args, **kwds)

    def __new__(self, name, bases, attrs):
        def replaced_fnc(fn):
            def new_test(*args, **kwargs):
                args[0].before()
                result = fn(*args, **kwargs)
                args[0].after()
                return result

            return new_test

        for i in attrs:
            if callable(attrs[i]) and 'test' in attrs[i].__name__:
                attrs[i] = replaced_fnc(attrs[i])

        return (super(MetaTestCase, self).__new__(self, name, bases, attrs))


class TestCase(metaclass=MetaTestCase):
    def before(self):
        print('Before')

    def after(self):
        print('After')


class TestSuite(TestCase):

    def before(self):
        print('New Before')

    def after(self):
        print('New After')

    def test(self):
        print("Test")


if __name__ == "__main__":
    TS = TestSuite()
    TS.test()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM