As you've taken most of our advice to heart, there isn't much to complain on stylewise, but a few pointers from my personal opinion:
- If possible, avoid doing function call for constants, and avoid redefining constants – You set
FULL_ENGLISH_ALPHABET = FULL_ENGLISH_ALPHABET + FULL_ENGLISH_ALPHABET.lower()
. Both the redefining of a constant, and doing the lower()
on previous version could and should be avoided in my opinion. Just set it to the correct version directly, you know in advance what it is going to be.
- Write out variable names – Type out in full the
tran_tab
variable, and since you're not going to change it, uppercase it, i.e make it ENGLISH_TO_ENTEAN
which also encompasses the use instead of just translation_table
which is kind of meaningless.
- Add docstrings to functions and module – You could/should add documentation to your module, to help understand what this module does
Extend to translate both ways
A natural extension now is to extend it so that it can translate both ways. In addition to the to_english(text)
function, I would also make a translate_to(language, text)
function so that you can make functions which can choose which way you want to translate.
Look into unit testing and/or doctest
Another possible extension is to add testing of your methods, to ensure proper translation and handling of different cases. Loads of alternatives exists, but I'm going to point you towards unittest and doctest. Both of these are included in vanilla Python. The former can be useful for slightly more complex cases, but I've opted for doctest in my review, as it has a nice side effect of displaying with the docstrings how to use the different functions.
Doctest can be invoked on your module in a variety of ways, but the two versions I've been using the most are either to call it direcly from the command line using python -m doctest my_module.py
or through calling a simple do_doctest()
function from the main code. The former doesn't require anything besides the actual docstrings, and if you use python -m doctest -v my_module.py
you get to see every test it performs (and not only failing tests) and the summary.
Try it out with code below, and change some of the stuff related to >>>
lines, and response on following line.
Make main()
useful
I know I was the one proposing the main()
function you're using, but now that it is maturing, I would make it into a loop asking for which language to translate to and text to translate. This way you'll get a meaning full script to run, in addition to a meaningful module to use.
Note how I used a little trick to 'alias' input = raw_input
if in Python 2, so I wouldn't need to do the if PY2
all over my script. Consider also looking into an extra module handling Python 2 and Python 3 like the six module.
Revamped code
Here is my version implementing all of the above suggestions:
"""
In the anime, "The Devil is a part timer", the language in Ente Isla is
called Entean, which is basically most of the consonants in the English
alphabet switched around. Vowels and the consonants 'L', 'N', 'Q' keep
their original position, whilst the rest is simply reversed.
The full alphabet then is that each letter of ABCDEFGHIJKLMNOPQRSTUVWXYZ
is changed to AZYXEWVTISRLPNOMQKJHUGFDCB. For example, 'human' is 'tupan',
and 'world' becomes 'foklx'. Other characters are kept as is.
Some typical usage situation offered by module:
>>> to_entean("Text, to be translated, into to Entean!")
'Hedh, ho ze hkanjlahex, inho ho Enhean!'
>>> to_english("Tupan foklx!")
'Human world!'
>>> translate_to('entean', 'Kind of cool')
'Rinx ow yool'
"""
import sys
# Set to True if Python major version is 2
PY2 = sys.version_info[0] == 2
if PY2:
from string import maketrans
# Alias input to simplify input routines
input = raw_input
else:
maketrans = str.maketrans
ENGLISH_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
ENTEAN_ALPHABET = "AZYXEWVTISRLPNOMQKJHUGFDCBazyxewvtisrlpnomqkjhugfdcb"
ENGLISH_TO_ENTEAN = maketrans(ENGLISH_ALPHABET, ENTEAN_ALPHABET)
ENTEAN_TO_ENGLISH = maketrans(ENTEAN_ALPHABET, ENGLISH_ALPHABET)
def to_entean(text):
"""Return text translated from English to Entean.
>>> to_entean("Some random text to translate, with punctuation chars!")
'Jope kanxop hedh ho hkanjlahe, fiht munyhuahion ytakj!'
>>> to_entean(ENGLISH_ALPHABET) == ENTEAN_ALPHABET
True
"""
return text.translate(ENGLISH_TO_ENTEAN)
def to_english(text):
"""Return text translated from English to Entean.
>>> to_english("Noh jo eajc ho unxekjhanx, kivth?")
'Not so easy to understand, right?'
>>> to_english(ENTEAN_ALPHABET) == ENGLISH_ALPHABET
True
"""
return text.translate(ENTEAN_TO_ENGLISH)
ALL_TRANSLATIONS = {
'entean' : to_entean,
'english' : to_english
}
def translate_to(language, text):
"""Return translated text according to mode.
>>> translate_to('english', 'Tupan foklx')
'Human world'
>>> translate_to('entean', 'Human world')
'Tupan foklx'
>>> translate_to('norwegian', 'This will fail!')
Traceback (most recent call last):
ValueError: Unknown translation language.
"""
translate_function = ALL_TRANSLATIONS.get(language, None)
if translate_function:
return translate_function(text)
else:
raise ValueError("Unknown translation language.")
def do_doctest():
"""Utility method to run all doctests from within script."""
import doctest
doctest.testmod()
def main():
"""Loop asking for language and text to translate."""
print(' Translation utility '.center(72, '*'))
print('\nLegal languages: {}'.format(', '.join(ALL_TRANSLATIONS)))
while True:
to_language = input("Language to translate to (or 'quit'): ").lower().strip()
if to_language == 'quit':
break
text = input("Enter text to translate: ")
print('Translated text: {}'.format(translate_to(to_language, text)))
if __name__ == "__main__":
do_doctest()
main()