我需要此其中一個解決方案:
- 作品與兩個Python 2的(> = 2.7)和Python 3(> = 3.2)。
- 讓我們在動態地導入一個依賴關係後改變類的基礎。
- 讓我們從單元測試代碼改變類的基礎。
- 適用於具有自定義元類的類型。
- 仍然允許
unittest.mock.patch
按預期運行。
這就是我想出了:
def ensure_class_bases_begin_with(namespace, class_name, base_class):
""" Ensure the named class's bases start with the base class.
:param namespace: The namespace containing the class name.
:param class_name: The name of the class to alter.
:param base_class: The type to be the first base class for the
newly created type.
:return: ``None``.
Call this function after ensuring `base_class` is
available, before using the class named by `class_name`.
"""
existing_class = namespace[class_name]
assert isinstance(existing_class, type)
bases = list(existing_class.__bases__)
if base_class is bases[0]:
# Already bound to a type with the right bases.
return
bases.insert(0, base_class)
new_class_namespace = existing_class.__dict__.copy()
# Type creation will assign the correct ‘__dict__’ attribute.
del new_class_namespace['__dict__']
metaclass = existing_class.__metaclass__
new_class = metaclass(class_name, tuple(bases), new_class_namespace)
namespace[class_name] = new_class
像這樣來使用該應用程序中:
# foo.py
# Type `Bar` is not available at first, so can't inherit from it yet.
class Foo(object):
__metaclass__ = type
def __init__(self):
self.frob = "spam"
def __unicode__(self): return "Foo"
# … later …
import bar
ensure_class_bases_begin_with(
namespace=globals(),
class_name=str('Foo'), # `str` type differs on Python 2 vs. 3.
base_class=bar.Bar)
使用這樣從內部單元測試代碼:
# test_foo.py
""" Unit test for `foo` module. """
import unittest
import mock
import foo
import bar
ensure_class_bases_begin_with(
namespace=foo.__dict__,
class_name=str('Foo'), # `str` type differs on Python 2 vs. 3.
base_class=bar.Bar)
class Foo_TestCase(unittest.TestCase):
""" Test cases for `Foo` class. """
def setUp(self):
patcher_unicode = mock.patch.object(
foo.Foo, '__unicode__')
patcher_unicode.start()
self.addCleanup(patcher_unicode.stop)
self.test_instance = foo.Foo()
patcher_frob = mock.patch.object(
self.test_instance, 'frob')
patcher_frob.start()
self.addCleanup(patcher_frob.stop)
def test_instantiate(self):
""" Should create an instance of `Foo`. """
instance = foo.Foo()
如果學習者不熟悉metaclass,type(),...:這對學習者來說也是很好的:http://www.slideshare.net/gwiener/metaclasses-in-python :) – loolooyyyy 2014-01-30 11:30:20
這是我的用法案件。我正在導入一個類B繼承自A類的庫。 – FutureNerd 2014-06-25 02:39:47
這是我的實際使用案例。我正在導入一個擁有從類A繼承的類B的庫。我想用new_A_method()創建從A繼承的New_A。現在我想創建New_B繼承自... B,就像B繼承自New_A一樣,以便B的方法,A的方法和new_A_method()都可用於New_B的實例。如何在不修補現有A類的情況下做到這一點? – FutureNerd 2014-06-25 02:49:46