Here is a very basic object orientated implementation of a read evaluate print loop AKA REPL. I encluded REShell
to demonstrate how one could use Reple
#-*-coding:utf8;-*-
#qpy:3
#qpy:console
import re
import sre_constants
PS1 = '>> '
DEFAULT_EVALUATOR = print
class Repl(object):
def __init__(self, evaluator=DEFAULT_EVALUATOR):
self.ps1 = PS1
self.evaluator = evaluator
def read(self):
return input(self.ps1)
def evaluate(self):
return self.evaluator(self.read())
def run(self):
while 1:
try:
self.evaluate()
except KeyboardInterrupt:
sys.exit(0)
class REShell(Repl):
def __init__(self, data):
self.data = data
self.ps1 = PS1
def evaluate(self):
try:
expression = re.compile(self.read())
print(*expression.findall(self.data), sep='\n')
except sre_constants.error as error:
print(error)
def source_code():
with open(__file__, 'r') as source:
return source.read()
if __name__ == '__main__':
data = source_code()
print(data)
shell = REShell(data)
shell.run()
1 Answer 1
Looks quite good to me! There's some things I think you could improve:
When a user hits Ctrl-C, the program flow is suddenly interrupted. The call to
sys.exit
should use1
as a status code to indicate that something went wrong.The REPL prompt is currently hardcoded, but you could easily change
Reple
's signature to allow a custom prompt:class Reple(object): def __init__(self, evaluator=DEFAULT_EVALUATOR, prompt=PS1): self.prompt = prompt
On that note,
PS1
is a bit ambiguous, maybe rename it toDEFAULT_PROMPT
.This is more of a design argument, but in my opinion it would make more sense to have
run
callevaluate
, makingevaluator
superfluous; in pseudocode:while true read from stdin evaluate(expression)
And in Python:
class Reple(object): ... def run(self): while 1: try: expression = input(self.prompt) except KeyboardInterrupt: sys.exit(1) else: self.evaluate(expression=expression) def evaluate(self, expression): raise NotImplementedError("This method must be implemented in a derived class")
You can use
abc.ABCMeta
together withabc.abstractmethod
to provide 'truly' abstract methods:import abc class Reple(object, metaclass=abc.ABCMeta): ... @abc.abstractmethod def evaluate(self, expression): return
And here's a Python 2 version:
import abc class Reple(object): __metaclass__ = abc.ABCMeta ... @abc.abstractmethod def evaluate(self, expression): return
You don't have any docstrings, so it's hard to tell what certain methods do or how they should be implemented by subclasses of
Reple
.
-
2\$\begingroup\$
PS1
is a nod to us Linux hackers. Bash was my introduction to programming. I \$\endgroup\$Ricky Wilson– Ricky Wilson2017年12月24日 00:55:58 +00:00Commented Dec 24, 2017 at 0:55