How to name variables and methods when coding in a dynamic language
Dynamic languages lack the IDE intellisense that tells us the type of every variable. Thus it is necessary to choose variable names that allow future readers of the code to unambiguously determine the type and contents of the variable.
Method names
Method names should always be verbs or verb phrase - get_person, load_database, mark_job_completed, etc.
If the method has side effects and alters a passed in object (generally a bad idea but sometimes OK), then be explicit by using the verb 'fill' or 'hydrate':
def hydrate_context(context):
context['stuff'] = Stuff()
def fill_context(context):
context['stuff] = Stuff()
If the method has side effects that alter a permanent datastore, use a verb like 'update_db', 'save', or 'persist'
If you are grabbing a remote resource, use the verb 'fetch' rather than 'get' to imply that the code is reaching out a distance to get the content:
def fetch_embed_html():
return requests.get(self.url)
If your method does two things (generally a code smell, but sometimes you just need a method that wraps two other methods), then be explicit about what the method does and what it returns:
def fetch_and_normalize_embed_html(self):
html = self.fetch_embed_html()
return self.normalize(html)
If you have a variable that holds some sort of callback function, add 'callback' or 'method' or 'function' to the variable name:
#GOOD:
def process_task(task, success_callback, error_callback):
try:
self.dispatch(task)
succes_callback()
except Exception, e:
error_callback(e)
# BAD (It's unclear that "error" is a callback function,
# "error" could be anything, a message that's passed
# in, a list that collects error results, etc):
def process_task(task, success, error):
...
If you want to add a simple getter to an object, use a verb in the method name if it's a method, or use a property if there is no verb in the name. Do not create verbless methods. (This is a python specific rule. Javascript does not have getters, and so using methods that are just the attribute name is quite common in jQuery).
#GOOD:
def get_host(self):
return self.request.host
GOOD:
@property
def host(self):
return self.request.host
# BAD ( I will be very confused when I do
# "print obj.host" and get "<function host>"
# instead of the host name)
def host(self):
return self.request.host
Object instances
Object instances should be the lower case version of the class name, ex: game_type = GameType(), file_library = FileLibrary()
Sometimes this seems to verbose. You are tempted to write 'library' instead of 'file_library'. But remember, code is read many more times than it is written. Optimize for the developer reading the code four months from now, not for your typing speed this second.
Lists
Variables holding lists should always be the plural form of the thing the list is holding:
for person in people:
for name in names:
for account in accounts:
Dictionaries
Dictionaries are basically used in two different ways - as schemaless objects or as a lookup table.
Object-style dictionary usage
If you are in a small, standalone script, that uses almost all dictionaries and no classes, then it is OK to name the variable holding the dictionary for what the thing is:
person = {
'name': 'jim',
'birthdate': '4-17-1982',
'hometown: 'Boston'
}
But if you are in code that has a class Person, and you have a dictionary that is storing some serialized form of that class, then naming that dictionary 'person' creates confusion. Use 'person' to refer to an object instance, and use 'person_data' or 'person_dict' to refer to the dictionary form, and use 'person_str' or 'person_json' to refer to the serialized form:
person = Person()
person_data = Person.to_dict()
person_json = json.dumps(person_data)
Dictionaries as lookup tables
If the dictionary refers to some sort of mapping or lookup table, then name the variable for the lookup key and value:
# GOOD:
person_by_name = {
'jim': Person(),
'sam': Person()
}
cities_by_country = {
'United States': ['Boston', 'New York'],
'France': ['Paris', 'Orleans']
}
action_to_func_map = {
'deploy': deploy_project,
'kick' : kick_project,
}
# BAD - the code reader will think this is a
# list of persons, not a dictionary
persons = {
'jim': Person(),
'sam': Person()
}
In general, name the variable either 'value_by_key' or 'key_to_value'.
Never name a dictionary just 'persons' or 'cities'. The code reader will have no idea how to use the variable. They will think it is a list and be very confused to find it is a lookup table. Once they figure out it is a table, they will be unsure what the keys are.
Strings should end in a postfix that indicates stringness/wordness.
Examples of good string variable names include: author_name, field_label, img_src, template_source, body_text, page_key, data_str. If you have a variable holding a users name, do not call that variable ‘user’, because someone reading the code will get it confused with an instance of the User class. Call the variable username. Do not call a string holding the name of a file ‘file’, that confuses it with a file object. Call the string ‘file_name’ if it’s just the file name, or ‘file_path’ if it contains the full path to the file.
Numbers
Numbers should end with a postfix marking the variable as clearly numeric. Do not use plurals only as that makes the variable name confusing with lists – use 'result_count' not 'results'. Other examples: item_id, home_price_int, costs_sum, load_avg
Err on the side of being unambiguous at the expense of verbosity. Let's say you have a variable in a page template. The variable contains the percent of people who passed some academic test. If you name this variable 'percent_passed', it is not immediately obvious if the variable contains a string that looks like '34%' or a float that contains .34. Instead, name your variable 'percent_passed_formatted' for the string version and 'percent_passed_float' for the float version to make it obvious.
General Consistency
Try to be consistent within your code, so that a variable name always indicates the same thing wherever it is used.
For instance, create a convention whereby:
(thing)_file is an instance of a file object
(thing)_file_name is a string with the name part of the file 'mystuff.txt'
(thing)_path is a string with the file full path: '/home/patrick/mystuff.txt'
Do not have (thing)_file be a file object in one place and a file name in another place.
If in your app 'thing_guid' refers to a string, then it should always be a string. If it refers to an instance of a uuid() or Guid() object, then it should always refer to the instance, and never have a type of string. Pick one way and be consistent.
Using Judgement
The above guidelines should be followed 99% of the time for naming class attributes, module attributes, and method parameters. For local variables or loop variables, you can use your judgment. Since the variable is initialized so close to where the variable is used, it can be pretty obvious to the person reading the code exactly what it is in it, and thus having a verbose variable name is less critical.