我不太了解 Ruby,无法准确判断您要做什么,但请查看 __getattr__ 方法。如果你在你的类中定义它,当代码试图访问你的类的任何未定义的属性时,Python 会调用它。由于您希望它成为一个方法,因此它需要动态创建一个返回的方法。
>>> class Product:
... def __init__(self, number):
... self.number = number
... def get_number(self):
... print "My number is %d" % self.number
... def __getattr__(self, attr_name):
... return lambda:"stubbed_"+attr_name
...
>>> p = Product(172)
>>> p.number
172
>>> p.name()
'stubbed_name'
>>> p.get_number()
My number is 172
>>> p.other_method()
'stubbed_other_method'
另请注意__getattr__ 需要不使用您的类的任何其他未定义属性,否则它将无限递归,调用__getattr__ 为不存在的属性。
... def __getattr__(self, attr_name):
... return self.x
>>> p.y
Traceback (most recent call last):
#clipped
RuntimeError: maximum recursion depth exceeded while calling a Python object
如果您只想从测试代码而不是生产代码中执行此操作,则将您的普通类定义放在生产代码文件中,然后在测试代码中定义 __getattr__ 方法(未绑定),然后然后将其绑定到您想要的类:
#production code
>>> class Product:
... def __init__(self, number):
... self.number = number
... def get_number(self):
... print "My number is %d" % self.number
...
#test code
>>> def __getattr__(self, attr):
... return lambda:"stubbed_"+attr_name
...
>>> p = Product(172)
>>> p.number
172
>>> p.name()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
AttributeError: Product instance has no attribute 'name'
>>> Product.__getattr__ = __getattr__
>>> p.name()
'stubbed_name'
我不确定这会对已经使用__getattribute__ 的类产生什么反应(与__getattr__ 不同,__getattribute__ 对所有属性都调用,无论它们是否存在)。
如果您只想对已经存在的特定方法执行此操作,那么您可以执行以下操作:
#production code
>>> class Product:
... def __init__(self, number):
... self.number = number
... def get_number(self):
... return self.number
...
>>> p = Product(172)
>>> p.get_number()
172
#test code
>>> def get_number(self):
... return "stub_get_number"
...
>>> Product.get_number = get_number
>>> p.get_number()
'stub_get_number'
或者如果你真的想要优雅,你可以创建一个包装函数来简化执行多个方法:
#test code
>>> import functools
>>> def stubber(fn):
... return functools.wraps(fn)(lambda self:"stub_"+fn.__name__)
...
>>> Product.get_number = stubber(Product.get_number)
>>> p.get_number()
'stub_get_number'