Я не достаточно хорошо знаю 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__
(unbound), а затем привяжите его к нужному классу:
#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'
Или, если вы действительно хотите быть элегантным, вы можете создать функцию-обертку, чтобы сделать несколько методов easy:
#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'