patternpythonMinor
Python with alternative keywords
Viewed 0 times
withalternativepythonkeywords
Problem
A while ago, a user on Programming Puzzles and Code Golf had an idea:
How about a language where all of the core commands are PPCG usernames? -- Helka Homba
A list was made of username/(keyword|builtin function) pairs, but nobody really wanted to actually make the code, so it kinda went on hold.
Recently (read: yesterday) another user suggested using the
Here is my code:
This is the content of
```
{"Martin":"False",
"Geobits":"None",
"Denni
How about a language where all of the core commands are PPCG usernames? -- Helka Homba
A list was made of username/(keyword|builtin function) pairs, but nobody really wanted to actually make the code, so it kinda went on hold.
Recently (read: yesterday) another user suggested using the
tokenize module, so I did. With his help, I finished some py2 code for replacing the names.Here is my code:
import tokenize
import ast
import sys
def handle_token(type, token, (srow, scol), (erow, ecol), line):
# Return the info about the tokens, if it's a NAME token then replace it
if tokenize.tok_name[type] == "NAME":
token = token_names.get(token, token)
return (type, token, (srow, scol), (erow, ecol), line)
def run(assignments="assignments.txt",open_from="peoples.txt"):
with open(assignments, "r") as f:
# Read the replacements into token_names
global token_names
token_names = ast.literal_eval(f.read())
with open(open_from) as source:
# Get the tokenized version of the input, replace it, and untokenize into pretty output
tokens = tokenize.generate_tokens(source.readline)
handled_tokens = (handle_token(*token) for token in tokens)
output = tokenize.untokenize(handled_tokens)
with open(open_from[:-4]+"-output.txt",'w') as outfile:
# Write to the output file
outfile.write(output)
return output
if __name__ == "__main__":
if len(sys.argv) > 1:
if len(sys.argv) > 2:
try:exec run(assignments=sys.argv[1],open_from=sys.argv[2])
except:pass
else:
try:exec run(assignments=sys.argv[1])
except:pass
else:
try:exec run()
except:passThis is the content of
main.py. It uses assignments.txt, which is a file containing a python dict of the replacement pairs.```
{"Martin":"False",
"Geobits":"None",
"Denni
Solution
Some Musings about Exceptions
(1) NEVER pass on every single exception!
You're basically absorbing every possible exception without usefulness. Normally, to prevent runtime crashes, I do this with my excepts when I want to catch all:
... which will put a nicer message. Of course, you can expand this by defining different types to capture in the except blocks. There may be cases for this, but since this isn't a code golf challenge, you can do this here instead.
(2) "Blank"
There's a rule of thumb that I abide by: "In most cases, you should always try and catch the most narrow exception that you expect to end up seeing in a
In effect, we do something different with a
Since most errors inherit from Exception this captures all other errors, but not warnings, this will allow for us to capture unhandled exceptions and 'handle' them as a "final option" type of try/except block, for when they aren't handled in other blocks below
There are always rare cases where you want to do nothing when an exception happens, so you can use
Replace
JSON data is basically a structured
This way, we don't have to worry about
As for storing the 'massive dict' in main.py, if it's likely to expand in the future leave it in its own file, and continue to load it as a JSON object as my suggestion here has.
This isn't code golf! Whitespace is a good thing!
Your code is hard to read when your try/except blocks and such are all golfed to remove whitespace. Add whitespace for readability.
You don't need that many try/accept blocks around your 'run' calls, and you don't need
You have four separate try/except blocks, yet all they do is silently let exceptions go by. Taking into account I don't suggest using 'pass' on exceptions that could be important, we can just simply take a page from my book, and change your code to have one try/except block wrapped around all the
You also don't need the
So, ultimately, you save some code:
Nitpicking Section
I'mma nitpick a little here with some of your code, and bring more suggestions that are minor/aesthetic in nature, rather than code-critical. These suggestions are reflected below though.
This one's fairly obvious, but
Unnecessary parentheses on 'return' in `handle_toke
(1) NEVER pass on every single exception!
You're basically absorbing every possible exception without usefulness. Normally, to prevent runtime crashes, I do this with my excepts when I want to catch all:
try:
# some code here...
except Exception as e:
print "An exception has occurred:\n%s" % str(e)... which will put a nicer message. Of course, you can expand this by defining different types to capture in the except blocks. There may be cases for this, but since this isn't a code golf challenge, you can do this here instead.
(2) "Blank"
except blocksThere's a rule of thumb that I abide by: "In most cases, you should always try and catch the most narrow exception that you expect to end up seeing in a
try/except block, with an ultimate "catch-all" block later to handle any unexpected exceptions." That basically means that if I'm trying to catch an "Invalid JSON" error when running json.load (you'll see why I mention this later), I'd do something like this:with open('jsondata.json', 'r') as f:
try:
data = json.load(f)
except ValueError:
print "Could not properly parse JSON data, is the file 'jsondata.json' comprised of actual JSON data?"In effect, we do something different with a
ValueError (we could pass, or we could simply quit, or we can print a nice message like this does), but for all other Exceptions will not capture them and will raise whatever exception it was trying to raise. Let's say, though, this was in a run() function, and I call the run function in a manner like you do in your code:if __name__ == "__main__":
try:
run()
except Exception as e:
print "An unhandled exception has occurred:\n%s" % str(e)Since most errors inherit from Exception this captures all other errors, but not warnings, this will allow for us to capture unhandled exceptions and 'handle' them as a "final option" type of try/except block, for when they aren't handled in other blocks below
run directly.There are always rare cases where you want to do nothing when an exception happens, so you can use
pass in those cases, but in 99% of all cases, you should not be simply 'allowing exceptions to pass on without raising some notice'.Replace
ast with json insteadJSON data is basically a structured
dict. Since you're storing a dict and it meets the most basic JSON formatting, we can just parse your assignments file as JSON instead, and remove the literal_eval and import ast. This does require you to import json instead of import ast but this is a more sane approach:with open(assignments, "r") as f:
# Read the replacements into token_names
global token_names
token_names = json.load(f)This way, we don't have to worry about
ast and having a literal evaluation that could cause evil in the future. This also permits us to error out proper with an exception if we don't have a valid assignments file. (And we can handle it with customized error messages if we wish).As for storing the 'massive dict' in main.py, if it's likely to expand in the future leave it in its own file, and continue to load it as a JSON object as my suggestion here has.
This isn't code golf! Whitespace is a good thing!
Your code is hard to read when your try/except blocks and such are all golfed to remove whitespace. Add whitespace for readability.
You don't need that many try/accept blocks around your 'run' calls, and you don't need
exec either!You have four separate try/except blocks, yet all they do is silently let exceptions go by. Taking into account I don't suggest using 'pass' on exceptions that could be important, we can just simply take a page from my book, and change your code to have one try/except block wrapped around all the
run calls, and handle exceptions whenever they come up, without having individual try/except blocks just for each call.You also don't need the
exec calls you have in here.So, ultimately, you save some code:
if __name__ == "__main__":
try:
if len(sys.argv) > 1:
if len(sys.argv) > 2:
run(assignments=sys.argv[1], open_from=sys.argv[2])
else:
run(assignments=sys.argv[1])
else:
run()
except Exception as e:
print "An exception has occurred:\n%s" % str(e)Nitpicking Section
I'mma nitpick a little here with some of your code, and bring more suggestions that are minor/aesthetic in nature, rather than code-critical. These suggestions are reflected below though.
type is actually a builtin, use a different name in handle_tokenThis one's fairly obvious, but
type is actually a built-in. Shadowing built-ins is bad if you eventually could use a builtin, so let's replace type with type_ in handle_token, to get rid of the "Shadows built-in 'type'" problems.Unnecessary parentheses on 'return' in `handle_toke
Code Snippets
try:
# some code here...
except Exception as e:
print "An exception has occurred:\n%s" % str(e)with open('jsondata.json', 'r') as f:
try:
data = json.load(f)
except ValueError:
print "Could not properly parse JSON data, is the file 'jsondata.json' comprised of actual JSON data?"if __name__ == "__main__":
try:
run()
except Exception as e:
print "An unhandled exception has occurred:\n%s" % str(e)with open(assignments, "r") as f:
# Read the replacements into token_names
global token_names
token_names = json.load(f)if __name__ == "__main__":
try:
if len(sys.argv) > 1:
if len(sys.argv) > 2:
run(assignments=sys.argv[1], open_from=sys.argv[2])
else:
run(assignments=sys.argv[1])
else:
run()
except Exception as e:
print "An exception has occurred:\n%s" % str(e)Context
StackExchange Code Review Q#156043, answer score: 9
Revisions (0)
No revisions yet.