如果你想通過調用預定義類A
一個函數來創建B
類,你可以簡單地做B = wrap_class(A)
與功能wrap_class
看起來像這樣:
import copy
def wrap_class(cls):
'Wraps a class so that exceptions in its methods are caught.'
# The copy is necessary so that mutable class attributes are not
# shared between the old class cls and the new class:
new_cls = copy.deepcopy(cls)
# vars() is used instead of dir() so that the attributes of base classes
# are not modified, but one might want to use dir() instead:
for (attr_name, value) in vars(cls).items():
if isinstance(value, types.FunctionType):
setattr(new_cls, attr_name, func_wrapper(value))
return new_cls
B = wrap_class(A)
正如於爾根指出,這將創建一個班級副本;這只是需要的,但是,如果你真的想保持你的原始類A
左右(如原始問題中提出的)。如果你不關心A
,你可以簡單地與不進行任何複製,像這樣的包裝裝飾它:
def wrap_class(cls):
'Wraps a class so that exceptions in its methods are caught.'
# vars() is used instead of dir() so that the attributes of base classes
# are not modified, but one might want to use dir() instead:
for (attr_name, value) in vars(cls).items():
if isinstance(value, types.FunctionType):
setattr(cls, attr_name, func_wrapper(value))
return cls
@wrap_class
class A(object):
… # Original A class, with methods that are not wrapped with exception catching
裝飾類A
捕獲異常。
元類的版本是較重的,但其原理是相似的:
import types
def func_wrapper(f):
'Returns a version of function f that prints an error message if an exception is raised.'
def wrapped_f(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception, ex:
print "Function", f, "raised", ex
return wrapped_f
class ExceptionCatcher(type):
'Metaclass that wraps methods with func_wrapper().'
def __new__(meta, cname, bases, cdict):
# cdict contains the attributes of class cname:
for (attr_name, value) in cdict.items():
if isinstance(value, types.FunctionType): # Various attribute types can be wrapped differently
cdict[attr_name] = func_wrapper(value)
return super(meta, ExceptionCatcher).__new__(meta, cname, bases, cdict)
class B(object):
__metaclass__ = ExceptionCatcher # ExceptionCatcher will be used for creating class A
class_attr = 42 # Will not be wrapped
def __init__(self):
pass
def f0(self, a):
return a*10
def f1(self, a, b):
1/0 # Raises a division by zero exception!
# Test:
b = B()
print b.f0(3.14)
print b.class_attr
print b.f1(2, 3)
此打印:
31.4
42
Function <function f1 at 0x107812d70> raised integer division or modulo by zero
None
你想要做什麼,其實通常由元類完成,這是一個類的實例是一個類:這是一種基於其解析的Python代碼動態構建B
類的方法(類A
,代碼在問題中)。關於這方面的更多信息可以在Chris的Wiki中給出的關於元類的簡短描述中找到(在part 1和parts 2-4中)。
是的,使用類裝飾器。 –
但是,對於我的這種看起來有點像繼承,是你正在尋找還是有隱藏在你的問題背後的具體用法? – aweis
一個類裝飾器或(對於Python 2.x)一個元類將允許您在B編譯時檢查B的字典,並使用包裝器來替換其中的方法定義。 – millimoose