让我们说我们想要使用类
实现一个功能class MyClass():
def __init__(self):
pass
def generate_query(self):
# Generate the query
pass
def send_query(self):
# send the query over the network
pass
def receive_response(self):
# read the response from buffer
pass
确保在generate_query()
之前调用send_query()
的最佳方式是什么,反之亦然,这是没有意义的。这很重要,因为只需在API文档中提及在您调用send_query()
之前调用另一种方法是另一种方法,但在send_query()
generate_query()
中的代码中明确地检查它{{1}以前被称为IMO的好习惯。
我期待一个解决方案,如果没有调用generate_query()
,我们会引发异常。
有一种很好的pythonic方法可以做到这一点,我曾在某处读过,但我忘记了源码和解决方案。
非常感谢帮助!
答案 0 :(得分:0)
我的想法是保持实例变量名称标志为True,如果调用generate_query,并且如果flag为false,则表示不调用generate_query,因此,您将在send_query或show中调用generate_query一条消息。
答案 1 :(得分:0)
一个选项可能是使用布尔标志。这种方法很简单,但不是很干净。
class MyClass():
def __init__(self):
self.generated = False
def generate_query(self):
self.generated = True
# Generate query
def send_query(self):
if not self.generated:
self.generate_query()
# Send query
def receive_response(self):
pass
我建议你尝试重建课程和方法。要求以特定顺序运行的方法容易出错,尤其是在没有记录的情况下。
答案 2 :(得分:0)
我想出了一个可以从其继承的基类来强制执行方法调用顺序(已在Python 2.7和3.6中进行了测试):
from types import FunctionType, MethodType
class Sequenced(object):
def __init__(self):
_methods = [name for name, obj in self.__class__.__dict__.items()
if type(obj) == FunctionType]
assert set(self._method_sequence).issubset(set(_methods))
self._sequence_pos = 0
def __getattribute__(self, name):
attr = object.__getattribute__(self, name)
if type(attr) == MethodType:
if attr.__name__ in self._method_sequence:
if self._sequence_pos >= len(self._method_sequence):
raise RuntimeError("All sequenced methods already called.")
if attr.__name__ != self._method_sequence[self._sequence_pos]:
raise RuntimeError("{0} method call expected.".format(
self._method_sequence[self._sequence_pos]))
self._sequence_pos += 1
def func_wrapper(*args, **kwargs):
return attr(*args, **kwargs)
return func_wrapper
else:
return attr
请注意,我不完全了解它是如何工作的(我设法阻止__getattribute__
引起无限递归,但是我一开始不了解是什么原因引起的,所以我不知道无法理解为什么我必须在一个地方使用FunctionType
而在另一个地方使用MethodType
)。它通过了我的最低测试(Python 2.7和3.6),但是您需要确保也对其进行测试。
您需要对类进行的操作是使其继承自Sequenced
,并像下面这样修改其__init__
方法:
class MyClass(Sequenced):
def __init__(self):
self._method_sequence = [
"generate_query",
"send_query",
"receive_response"
]
super(MyClass, self).__init__()
def generate_query(self):
# Generate the query
pass
def send_query(self):
# send the query over the network
pass
def receive_response(self):
# read the response from buffer
pass
基类允许您的类包含其他方法(仅对_method_sequence
列表中的方法强制执行排序)。如果您希望多次调用方法,_method_sequence
可以包含重复项。
如果顺序方法被不按顺序调用,或者在已经遍历列表之后尝试使用顺序方法,则会引发RuntimeError
。
可以修改基类,以便一旦可用就可以重复调用序列方法,但我将其留给读者练习。