Python 多重继承只适用于一个父类的方法,但从两个父类调用方法
Python multiple inheritance only working for one parent's method but calling method from both parents
我有一个 Python
/OOP
问题。
你们都熟悉 C++
中的菱形问题吧?这是类似的东西。
我有以下 classes
class BaseAuth(TestCase):
def setUp(self):
# create dummy user and client, removing code of that for simplicity.
self.user.save()
self.client.save()
def _get_authenticated_api_client(self):
pass
class TokenAuthTests(BaseAuth):
def _get_authenticated_api_client(self):
super()._get_authenticated_api_client()
print("I AM IN TOKEN AUTH")
api_client = APIClient()
# do stuff with api_client
return api_client
class BasicAuthTests(BaseAuth):
def _get_authenticated_api_client(self):
super()._get_authenticated_api_client()
print("I AM IN BASIC AUTH")
api_client = APIClient()
# do stuff with api client
return api_client
class ClientTestCase(BasicAuthTests, TokenAuthTests):
def test_get_login_response(self):
api_client = self._get_authenticated_api_client()
# login test code
def test_get_clients(self):
api_client = self._get_authenticated_api_client()
# get client test code
def test_get_client_by_id(self):
api_client = self._get_authenticated_api_client()
# get client by id test code
def test_update_client_by_id(self):
api_client = self._get_authenticated_api_client()
# update client test code
def test_add_client(self):
api_client = self._get_authenticated_api_client()
# add client test code
def test_delete_client_by_id(self):
api_client = self._get_authenticated_api_client()
# delete client test code
现在,当我 运行 代码时,我可以看到打印出来的是:
I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
但是,如果我从功能的角度来看,测试 运行 仅适用于 BasicAuthTests
。我怎么知道的?
1.测试运行s个数是6
,本来应该是12
,6
每个父class.
2. 如果我将 BasicAuthTests
中的 _get_authenticated_api_client()
函数更改为错误的 return
类型,代码会崩溃,但如果我在 TokenAuthTests
中更改它,则什么也不会发生,这意味着 TokenAuthTests
没有做任何事情,但它的打印语句在工作,这意味着函数被调用。
这太令人困惑了,有人可以帮忙吗?
我的最终目标是 运行 为每个父 class 返回的 api_client
.
这 6 个测试
HERE IS MUST MENTION THAT, THE CODE RUNS FINE. AND THE TEST WORK ALRIGHT IF I RUN THEM SEPARATELY. I AM TRYING TO SIMPLIFY THE CODE AND REMOVE ALL THE REPETITION, THAT'S WHY I AM KIND TO TRYING TO MERGE THEM INTO ONE FILE.
您被我们的 MRO 困住了。
虽然 Python 支持 Diamond Inheritance,但在变量赋值时你会卡住。
多亏了 Diamond Inheritance,我们现在 _get_authenticated_api_client
都将被调用。在分配时,_get_authenticated_api_client
returns 取决于您通过 classes 的顺序。
在你的例子中,只有 6 个测试 运行 因为你只有一个 class,具有 6 个测试功能。
您打算 运行 使用不同的 auth
方法进行完全相同的测试。
一种简单的方法是:
class ClientMixinCase: #Do not Inherit from "TestCase"
#... Declare you tests here
class ClientWithTokenAuthTestCase(ClientMixinCase,TokenAuthTests):
pass
class ClientWithBasicAuthTestCase(ClientMixinCase,BasicAuthTests):
pass
所以我用不同的方法解决了这个问题。
我们可以做的是,我们可以在父 class 中声明所有测试,并在子 classes.
中声明函数 _get_authenticated_api_client
但是我们如何在父 class 中使用子 class 的函数呢?
当父 class 继承 TestCase
并且将成为第一个 class 时,测试将从 运行 开始,它将崩溃,因为它没有 _get_authenticated_api_client
功能。
为了避免这种情况,我们所做的是将父 class 包装在另一个 class 中,这样 class 就不会被视为 class 而是父 class.
但是当我们从包装的父 TestCase
继承 class 继承我们的子 classes 时,它将被视为 class 并且它的测试将是 运行 但是在那一点 _get_authenticated_api_client
函数将在 child 中声明。
这是代码
class WrapperTestClass:
class ClientTestCase(TestCase):
# all the tests and setup function
class TokenAuthTests(WrapperTestClass.ClientTestCase):
def get_authenticated_api_client(self):
# function that returns api_client
class BasicAuthTests(WrapperTestClass.ClientTestCase):
def get_authenticated_api_client(self):
# function that returns api_client
我有一个 Python
/OOP
问题。
你们都熟悉 C++
中的菱形问题吧?这是类似的东西。
我有以下 classes
class BaseAuth(TestCase):
def setUp(self):
# create dummy user and client, removing code of that for simplicity.
self.user.save()
self.client.save()
def _get_authenticated_api_client(self):
pass
class TokenAuthTests(BaseAuth):
def _get_authenticated_api_client(self):
super()._get_authenticated_api_client()
print("I AM IN TOKEN AUTH")
api_client = APIClient()
# do stuff with api_client
return api_client
class BasicAuthTests(BaseAuth):
def _get_authenticated_api_client(self):
super()._get_authenticated_api_client()
print("I AM IN BASIC AUTH")
api_client = APIClient()
# do stuff with api client
return api_client
class ClientTestCase(BasicAuthTests, TokenAuthTests):
def test_get_login_response(self):
api_client = self._get_authenticated_api_client()
# login test code
def test_get_clients(self):
api_client = self._get_authenticated_api_client()
# get client test code
def test_get_client_by_id(self):
api_client = self._get_authenticated_api_client()
# get client by id test code
def test_update_client_by_id(self):
api_client = self._get_authenticated_api_client()
# update client test code
def test_add_client(self):
api_client = self._get_authenticated_api_client()
# add client test code
def test_delete_client_by_id(self):
api_client = self._get_authenticated_api_client()
# delete client test code
现在,当我 运行 代码时,我可以看到打印出来的是:
I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
.I AM IN TOKEN AUTH
I AM IN BASIC AUTH
但是,如果我从功能的角度来看,测试 运行 仅适用于 BasicAuthTests
。我怎么知道的?
1.测试运行s个数是6
,本来应该是12
,6
每个父class.
2. 如果我将 BasicAuthTests
中的 _get_authenticated_api_client()
函数更改为错误的 return
类型,代码会崩溃,但如果我在 TokenAuthTests
中更改它,则什么也不会发生,这意味着 TokenAuthTests
没有做任何事情,但它的打印语句在工作,这意味着函数被调用。
这太令人困惑了,有人可以帮忙吗?
我的最终目标是 运行 为每个父 class 返回的 api_client
.
HERE IS MUST MENTION THAT, THE CODE RUNS FINE. AND THE TEST WORK ALRIGHT IF I RUN THEM SEPARATELY. I AM TRYING TO SIMPLIFY THE CODE AND REMOVE ALL THE REPETITION, THAT'S WHY I AM KIND TO TRYING TO MERGE THEM INTO ONE FILE.
您被我们的 MRO 困住了。 虽然 Python 支持 Diamond Inheritance,但在变量赋值时你会卡住。
多亏了 Diamond Inheritance,我们现在 _get_authenticated_api_client
都将被调用。在分配时,_get_authenticated_api_client
returns 取决于您通过 classes 的顺序。
在你的例子中,只有 6 个测试 运行 因为你只有一个 class,具有 6 个测试功能。
您打算 运行 使用不同的 auth
方法进行完全相同的测试。
一种简单的方法是:
class ClientMixinCase: #Do not Inherit from "TestCase"
#... Declare you tests here
class ClientWithTokenAuthTestCase(ClientMixinCase,TokenAuthTests):
pass
class ClientWithBasicAuthTestCase(ClientMixinCase,BasicAuthTests):
pass
所以我用不同的方法解决了这个问题。
我们可以做的是,我们可以在父 class 中声明所有测试,并在子 classes.
中声明函数 _get_authenticated_api_client
但是我们如何在父 class 中使用子 class 的函数呢?
当父 class 继承 TestCase
并且将成为第一个 class 时,测试将从 运行 开始,它将崩溃,因为它没有 _get_authenticated_api_client
功能。
为了避免这种情况,我们所做的是将父 class 包装在另一个 class 中,这样 class 就不会被视为 class 而是父 class.
但是当我们从包装的父 TestCase
继承 class 继承我们的子 classes 时,它将被视为 class 并且它的测试将是 运行 但是在那一点 _get_authenticated_api_client
函数将在 child 中声明。
这是代码
class WrapperTestClass:
class ClientTestCase(TestCase):
# all the tests and setup function
class TokenAuthTests(WrapperTestClass.ClientTestCase):
def get_authenticated_api_client(self):
# function that returns api_client
class BasicAuthTests(WrapperTestClass.ClientTestCase):
def get_authenticated_api_client(self):
# function that returns api_client