Code Style Guide
Good code samples are the core of a great Kite Answer. This document will show you how to write a good code sample -- one that demonstrates how to use a function, class, or API in an easy and quick to understand way.
Goals
With every code sample we write, we aim for:
- Readability -- How much mental energy does it take for a reader to understand the sample?
- Concision -- How long does it take to read the sample?
- Simplicity -- How difficult is it to interpolate this sample with the reader's current code?
- Consistency -- how difficult is it to find the similarities and differences between this code sample and the other code samples in the article?
Fortunately, these goals usually overlap with each other. But do not follow these guidelines when they do not make sense. Instead, use your best judgment about when to bend or break these rules.
In this document, good code samples are shown like this:
print("This is a positive example of how to write good code samples.")
And negative samples, showing what not to do, are shown like this:
print 'This is a negative example showing how NOT to write code samples.'
Examples of good code samples
How to write a simple object as JSON
KITE.start_prelude()
import json
KITE.stop_prelude()
print(json.dumps({"a":1}))
# OUTPUT
{"a": 1}
This code sample is excellent because:
- the main code section is short and quick to understand
- it shows one concept and does not try to show other concepts in the same sample
- the import statement is in the prelude, because it is necessary to run the code sample but is not the most important part of the sample
How to reverse a deque
object
KITE.start_prelude()
import collections
KITE.stop_prelude()
d = collections.deque([1, 2, 3])
d.reverse()
print(d)
# OUTPUT
deque([3, 2, 1])
This code sample is excellent because:
- it is short and can be understood very quickly
- it is easy to match the input
[1, 2, 3]
with the output[3, 2, 1]
, which makes the effect ofreverse()
clear - it shows one concept and does not try to show other concepts in the same sample
- the import statement is in the prelude, because it is necessary to run the code sample but is not the most important part of the sample
- the print function call is in the main code section, so the user can match the print function call with the output
How to inspect the arguments of a function
KITE.start_prelude()
import inspect
KITE.stop_prelude()
def f(a, b=2, *args, **kwargs):
return a
print(getargspec(f))
# OUTPUT
ArgSpec(args=['a', 'b'], varargs='args', keywords='kwargs', defaults=(2,))
- it is short and can be understood easily
- it shows one concept and does not try to show other concepts in the same sample
- it uses simple placeholders for the function and argument names
- it demonstrates all of the features of the function
How to extract the query string from a request on a Werkzeug server
KITE.start_prelude()
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run-simple
KITE.stop_prelude()
def application(environ, start_response):
request = Request(environ)
query = request.args.get("query")
response = Response("You searched " + query)
return response(environ, start_response)
This code sample is excellent because:
- the concept is demonstrated in the context of a minimal Werkzeug application
- the incidental code is limited to only what is necessary, while still showing the context of the sample
- the main code section contains only server-related code; imports and running the server are outside of it
Guidelines
The guidelines here are probably different from traditional coding style guidelines. Our guidelines focus on our goals of readability, concision, simplicity, and consistency. For example, many coding style guidelines recommend modularity and reusability, which are important in software engineering but not in our explanatory code samples.
Fundamental Concepts
Show only one concept per code sample
Examples
This sample shows two independent concepts, which is bad:
data = [1, 2, 3]
print(map(lambda x: x*2, data))
print(filter(lambda x: x<3, data))
Instead, split this into two separate samples:
data = [1, 2, 3]
print(map(lambda x: x*2, data))
data = [1, 2, 3]
print(filter(lambda x: x<3, data))
However, use a single sample to demonstrate the multiple ways to use a particular function.
# ANSWER: How to retrieve the timezone from a string
print(gettz())
print(gettz("UTC"))
print(gettz("America/Los Angeles"))
Duplicate code instead of using loops or extra variables
It is usually better to copy a line of code two or three times with small modifications than introduce a loop. It takes less time for a human to understand three duplicated lines with small changes than to understand a loop.
Examples
d = defaultdict(list)
d["a"].append(1)
d["b"].append(2)
d["c"].append(3)
print(d)
The same sample using a loop takes longer to understand, even though there are fewer lines of code:
d = defaultdict(list)
for i, v in enumerate(["a", "b", "c"]):
d[v].append(i)
print(d)
Minimize look-back distance
Try to keep variables close to the line where they are used. If you need to use a variable multiple times, consider replacing the variables with their literal values. Variables that are used too often get too far from their definition, and a user has to search for the value.
Examples
document = "document_a.txt"
print(fnmatch(document, "*.txt"))
print(fnmatch(document, "document_?.txt"))
print(fnmatch(document, "document_[abc].txt"))
print(fnmatch(document, "document_[!xyz].txt"))
print(fnmatch("document_a.txt", "*.txt"))
print(fnmatch("document_a.txt", "document_?.txt"))
print(fnmatch("document_a.txt", "document_[abc].txt"))
print(fnmatch("document_a.txt", "document_[!xyz].txt"))
a = f.open("a.txt")
b = f.open("b.txt")
a.write("A")
b.write("B")
a.close()
b.close()
a = f.open("a.txt")
a.write("A")
a.close()
b = f.open("b.txt")
b.write("B")
b.close()
Use newlines only to separate functionality, and do not separate outputs
Aside from class and function definitions, newlines should only be used to separate multiple sections of functionality to make the code sample more readable. Do not add new lines before or after print calls, since they are naturally separated by inline outputs.
Examples
q = Queue.Queue()
q.put("a")
q.put("b")
q.put("c")
print(q.get())
print(q.get())
print(q.get())
q = Queue.Queue()
q.put("a")
q.put("b")
q.put("c")
print(q.get())
print(q.get())
print(q.get())
f = open("sample.json")
print(json.load(f))
f = open("sample.json")
print(json.load(f))
Preserve structure across related code samples
Examples
For example, these two samples show how to express different recurrence rules using dateutil.rrule
:
# ANSWER: How to list the dates of the 100th day of every year
for date in dateutil.rrule(YEARLY, byyearday=100, count=3):
print(date)
# ANSWER: How to list the dates of the next 10th week of the year
for date in dateutil.rrule(DAILY, byweekno=10, count=3):
print(date)
If the second sample was written as follows, it would be more difficult to understand the differences:
# ANSWER: How to list the dates of the next 10th week of the year
dates = dateutil.rrule(DAILY, byweekno=10, count=3)
print(list(dates))
Follow PEP8 as a basic coding style guideline
The standard Python coding conventions used by almost all Python developers are described in a document called PEP8. The most important of these conventions are listed below:
- use 4 spaces per indentation
- never use wildcard imports (e.g.
from x import *
) - surround binary operators (
+
,-
,=
, etc.) with a space on each side - do not surround an assignment (
=
) with spaces when used for keyword or default arguments - do not put spaces immediately inside parenthesis and brackets (e.g.
spam( ham[ 1 ] )
) - always pair a specific error with an
except
clause; never use the baseException
or leave it empty - use
isinstance
for type comparison - use the fact that empty sequences evaluate to
False
to check emptiness, instead of checking length
We diverge from PEP8 as follows:
- no two-line spaces around classes and top-level functions
- when splitting long function calls across lines, use a single extra indent level instead of using extra whitespace to align with the opening delimiter
- we have our own set of rules for imports, as described in the prelude section
Setup Code
Setup code consists of preludes and nondisplayed code. These sections are executed in the preview engine, but are not displayed to the user.
Preludes are used for imports and other optionally helpful setup code. These segments are initially hidden but may be toggled by the user. Since imports are easily assumed by most python programmers, they clutter a solution without adding much value. However, to aid beginners, they are optionally available to clarify the solution.
Nondisplayed code will never be shown, but can be used to set up the question for a solution. For example, in a question asking how to read a file from the harddrive, the setup code may be used to write a file which will then be read in the solution. The code for writing a file to disk is not relevant for a reader since it can be assumed that they already have a target file on their machine.
Preludes
Code samples can include preludes. Code inside of preludes is executed at runtime along with main code, but will be initially hidden from the reader. The prelude is used for imports and other optional setup. The prelude includes code that can be easily implied by the reader, such as imports. However, it is available via toggle for less advanced programmers. Code that is helpful in understanding the function of the code, such as the definition of a class which is later instantaiated, should be included in the main code section.
Use the prelude to hide code that isn't directly relevant to the demonstrated concept
In the Kite app, only the main code section is visible in search results; preludes are not visible to a user. Use preludes for code that is needed for the sample to run, but is not part of the core concept of the sample.
Examples
# ANSWER: How to parse command line arguments to the CLI
KITE.start_prelude()
import argparse
KITE.stop_prelude()
parser = argparse.ArgumentParser()
parser.add_argument("-a", action="store_true")
parser.add_argument("-b")
print(parser.parse_args(["-a", "-b", "val"]))
Put import statements in the prelude
Examples
KITE.start_prelude()
import yaml
KITE.stop_prelude()
print(yaml.dump("abc"))
Use import x
syntax by default
We want samples to be as easy to understand as possible, so for most packages, we want to import at the package level and access its functions from the package, rather than using from x import y
to import functions directly.
Examples
KITE.start_prelude()
from json import dumps
KITE.stop_prelude()
print(dumps({"a": 1}))
KITE.start_prelude()
import json
KITE.stop_prelude()
print(json.dumps({"a": 1}))
Use from a.b.c import d
when there are multiple subpackages
If a package contains subpackages, accessing a subpackage through the top-level package can make the sample messy and hard to read. In these cases, it makes more sense to use from
.
Examples
# ANSWER: How to map a URL to a function using `getattr`
KITE.start_prelude()
from werkzeug.wrappers import Response, Request
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
KITE.stop_prelude()
class HelloWorld(object):
url-map = Map([
Rule("/home", endpoint="home"),
])
def dispatch_request(self, request):
url_adapter = self.url_map.bind_to_environ(request.environ)
try:
endpoint, values = url_adapter.match()
# Call the corresponding function by prepending "on\_"
return getattr(self, "on\_" + endpoint)(request, **values)
except HTTPException, e:
return e
def on_home(self, request):
return Response("Hello, World!")
def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request)
return response(environ, start_response)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
Use import conventions for common libraries
For libraries such as numpy
, pandas
, and matplotlib
there are standard import names that are widely used.
Examples
KITE.start_prelude()
import numpy as np
KITE.stop_prelude()
an_array = np.ndarray([1, 2, 3])
Examples
KITE.start_prelude()
import pandas as pd
KITE.stop_prelude()
df = pd.DataFrame([1, 2, 3])
Examples
KITE.start_prelude()
from matplotlib import pyplot as plt
KITE.stop_prelude()
x = [1, 2, 3]
y = [1, 2, 3]
plt.plot(x,y)
In general, prefer to put code in the main code section
If your sample involves helper classes or methods that are central to the sample then you should still include those in the main code section.
Examples
KITE.start_prelude()
import yaml
KITE.stop_prelude()
class Dice(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return 'Dice(%d, %d)' % (self.a, self.b)
def dice_constructor(loader, node):
value = yaml.loader.construct_scalar(node)
a, b = map(int, value.split('d'))
return Dice(a, b)
add_constructor('!dice', dice_constructor)
print(yaml.load("gold: !dice 10d6"))
Setup Code
Setup code is never displayed. Use this section when intial setup is necessary in the KITE Engine for the code to run, but does not clarify the solution and is irrelevant to the user's specific use-case.
For example, to demonstrate reading a file from disk, we need to first construct a file. While the code is necessary for the sample to run, the specific set up steps are not part of the demonstrated concept, so we should not display the code.
KITE.set_display_code(False)
text = "line1\nline2\n"
KITE.write_file('test.txt',text)
KITE.set_display_code(True)
file = open('test.txt')
for line in file:
print(line)
Variables
Quickstart to variable naming
See below for more detailed examples. Use the following hierarchy for naming:
-
Purposeful name, eg: start_time, ...
-
(Collections) describe contents, eg: numbers, items, elements. Use full words, not abbreviations (num, char, elem)
-
Class names
- For multiple, use [class name][numeral] eg: list1, list2
-
For one, use a_[class name]
-
Make an exception. If this hierarchy does not fit a specific situation, make exceptions to maximize clarity and conciseness. For example:
Examples
Demonstrating multiple assignment
(a,b) = (1,2)
number1, number2
would reduce the clarity of the solution.
Use concise and purposeful variable names
Use variable names that are short and describe what a variable is going to be used for.
Examples
This example is good because you can see what the purpose of each variable is:
xdata = np.arange(10)
ydata = np.zeros(10)
plot(xdata, ydata)
This example is bad because it's not clear what the variables do:
a = np.arange(10)
b = np.zeros(10)
plot(a, b)
Avoid 'foo' 'bar' etc. regardless of how/where you are considering using it.
Avoid variables like name or file that could be confused with part of the API
Examples
Consider the following sample using Jinja2:
template = Template("<div>{{name}}</div>")
print(template.render(name="abc")) # unclear - is "name" somehow special?
For somebody not familiar with Jinja, it unclear whether name
has some special meaning in the Jinja2 API, or whether it's used as an arbitrary placeholder. To make it clear, use a word that could not be confused for part of the API:
template = Template("<div>{{person}}</div>")
print(template.render(person="abc"))
Follow language conventions for separating words in a variable name
Examples
# Python
my_variable = 1
# Java
int myVariable = 1
Don't create variables that are only referenced once (with exceptions)
Examples
This is unnecessarily verbose:
pattern = r"abc .* def"
regex = re.compile(pattern)
Instead, put it all on one line:
pattern = re.compile(r"abc .* def")
But do introduce temporary variables rather than split expressions across lines
Examples
This is difficult to understand:
yaml.dump({"name": "abc", "age": 7},
open("myfile.txt", "w"),
default_flow_style=False)
Instead, it would be better to introduce two temporary variables:
data = {"name": "abc", "age": 7}
f = open("myfile.txt", "w")
yaml.dump(data, f, default_flow_style=False)
And use single-use variables when printing
Examples
print(np.asarray((1, 2)))
Instead, add a one-use variable to make the print call simple.
arr = np.asarray((1, 2))
print(arr)
Use variable names to explain parameters
Examples
This is difficult to understand:
print(np.where([False, True, True], [1, 2, 3], [100, 200, 300]))
Instead, introduce temporary variables to indicate what the variables mean:
condition = [False, True, True]
when_true = [1, 2, 3]
when_false = [100, 200, 300]
print(np.where(condition, when_true, when_false))
This will sometimes conflict with the rule about not creating variables that are only referenced once. Use your best judgment.
Single letter variable names
In general, avoid using single variable letter names except in specific cases.
Indexes
Use i
(then j
, then k
) as index variables.
x
, y
, and z
Avoid using x
, y
, or z
except when:
• You're writing a numerics code sample where someone would naturally use x
or y
.
• You're using it as an iteration variable in a list comprehension. ([for x.upper() in items]
)
• You're using it in a lambda expression. (items.sort(key=lambda x: x[0])
)
• You're using it in an inline code span (list.remove(x)
) that won't be executed by the sandbox.
Do not use x
as an iteration variable. Instead, use the singular form of the plural you're iterating over
Examples
for x in items:
print(x)
for item in items:
print(item)
Do not use k
orv
for keys and values
Use the full names instead.
Examples
for k, v in d.items():
print(v)
for key, value in d.items():
print(d)
When no purposeful name is available, use the first letter of the type name, other than l
and i
When creating a variable that doesn't serve a specific purpose, use a single letter name that still preserves as much meaning as possible. For example:
• s
if it is a string
• d
if it is a dict
Avoid using l
for list
, though, because it could be confused with the number 1
. Instead, use a_list
Avoid using i
for int
because i
is for indices. Use n
instead.
As a last resort, use a
, b
, and c
Examples
For example:
a = [1, 2, 3]
del a[0]
print(a)
Values and Placeholders
Use simple placeholders
Examples
This is unnecessarily long:
print(json.dump({"first_name": "Graham", "last_name": "Johnson", "born_in": "Antarctica"}))
Instead, use more concise data:
print(json.dump({"a": 1, "b": 2}))
Avoid 'foo' 'bar' etc. regardless of how/where you are considering using it.
When appropriate, use placeholders that are relevant to the package
Examples
This is simple, but makes no sense in the context of the Python module shlex
:
print(shlex.split("a b"))
Instead, since shlex
is used for parsing Unix shell commands, use a sample command:
print(shlex.split("ls -a path/to/file"))
Similarly, since HMAC is used to hash messages using a key, express those semantics in the placeholders:
h = hmac.new("key")
h.update("Hello, World!")
Minimize placeholders to only what is necessary
Use the smallest amount of placeholder content that still clearly demonstrates the concept. You should rarely ever need more than 3.
When choosing between 1, 2, or 3 placeholders, consider incremental cost:
Examples
- For example, in
"abc".upper()
, the lastc
, while not strictly necessary, is low cost - But
map(upper, ["abc", "def"])
is better thanmap(upper, ["abc", "def", "ghi"])
because each incremental item element adds seven characters to the code, gets us to a less familiar part of the alphabet, and adds considerable length to the output - In the case of
{"a": 1}.pop("a")
, one entry is sufficient becausepop
for dictionaries does not care about order
Be careful when using only one placeholder, as the sample may become ambiguous.
Examples
- if we show
"a".upper()
, it is unclear if it works for multiple characters - if we show
[1].pop()
, it is unclear ifpop
is getting the first or last item, or even the whole list
Sometimes there are additional reasons to consider using two vs three items. For example, when multiplying two matrices it's required to use non-square dimensions to illustrate how the dimensions need to line up.
Use the alphabet (a, b, c, ...) for string placeholders
Examples
my_string = "abc"
Use natural numbers (1, 2, 3, ...) for integer placeholders
Examples
numpy.array([1, 2, 3])
Use natural numbers with a ".0" suffix for float placeholders
Examples
my_list = [1.0, 2.0, 3.0]
Don't start numbers with a .
If a number is between 1 and -1 (exclusive), include a leading 0
.
Examples
my_number = 0.5
my_number = .5
Continue these sequences for hierarchies, sequences, or groups of placeholder content.
Examples
map(upper, ['abc', 'def'])
numpy.array([[1, 2, 3], [4, 5, 6]])
Use "path/to/file" for directory names
Again, only for non-purposeful placeholder directory names.
Examples
os.path.split("/home/user/docs/sample.txt")
os.path.split("path/to/file")
Don't use the same value twice unless for the same purpose each time
Examples
The following sample creates an HMAC hash using a key, then updates it with a value:
h = hmac.new("abc")
h.update("abc")
This is confusing since it leaves the user wondering whether there is an important reason to use "abc"
in both places. Instead, you should use different values so that there is no confusion:
h = hmac.new("key")
h.update("Hello, World!")
On the other hand, sometimes the same value is being used for the same purpose in two different places. In this case you should use the same value in both cases, for example:
data1 = numpy.zeros(8)
data2 = numpy.zeros(8)
For placeholder functions and classes, balance "simple" with "natural"
Examples
This sample has a bunch of incidental complexity:
# ANSWER: How to add test cases to a suite
class MyTest(TestCase):
def setUp(self):
self.name = "abc"
self.num = 123
def test_name_equals(self):
self.assertEqual(self.name, "abc")
def test_num_equals(self):
self.assertEqual(self.num, 123)
suite = TestSuite()
suite.addTest(MyTest("test_name_equals"))
suite.addTest(MyTest("test_num_equals"))
Here is a much simpler version, that forms a better sample:
# ANSWER: How to add test cases to a suite
class MyTest(TestCase):
def test_a(self):
self.assertTrue(0 < 1)
suite = TestSuite()
suite.addTest(MyTest("test_a"))
First, we don't need to use setUp
or instance variables. We do have a decision between assertTrue(True)
or assertTrue(0 < 1)
. Here we decided in favor of the second option, though not strongly.
Use double quotes for string literals by default
Reason: it's important to have a consistent standard, and double quotes are more consistent with string representations in other languages.
Examples
print("use double quotes by default")
Switch to single quotes if you need to include double-quotes inside a string
Examples
This is ugly:
s = "Greg said \"hello\" to Phil"
Instead, switch to single quotes:
s = 'Greg said "hello" to Phil'
Use triple-double-quotes for multi-line strings
Examples
document = """
{
"a": 20,
"b": \[1,2,3,"a"\],
"c": {
"d": \[1,2,3\],
"e": 40
}
}
"""
data = json.loads(document)
Put a new line at the start and end of multi-line strings, if possible
Examples
data = """This is a
little hard to read"""
data = """
This is a
lot easier to read
"""
Use strings for dictionary keys
If the key-value pairs are purposeful, use key names that correspond to the meaning of the value. Otherwise, use "a", "b"...
as placeholder keys, and 1, 2...
as placeholder values.
Examples
json.dumps({1: "a", 2: "b"})
json.dumps({"a": 1, "b": 2})
Use C[n]
for placeholder classes and f[n]
for placeholder functions
Note that this only applies to placeholder classes and functions, i.e. classes and functions that have no functionality or purpose, such as those used in demonstrating sys
and inspect
functionality.
Additionally, for class and instance attributes, use a[n]
.
Examples
class Dog:
def bark(self):
return "Bark bark!"
class Cat:
def meow(self):
return "meow"
class C:
pass
class C:
def f(self):
pass
class C1:
def f1(self):
return 1
class C2:
def f2(self):
return 2
Use mock.kite.com for samples that demonstrate communication with a server
Examples
print(requests.get("http://google.com").text)
print(requests.get("http://mock.kite.com/text").text)
A list of endpoints for mock.kite.com can be found here.
Files
Open file with a straightforward open
Unless absolutely necessary, do not use a with
statement for opening files (rationale: this is a difficult one to decide on but open
works fine for short samples, and with
is a language-level feature that some users may not be familiar with).
Examples
f = open("input.txt")
Output
Generate the minimal output needed to clearly demonstrate the concept
Output must be read and understood by the user, to, so the more output there is, the more time it takes users to understand the sample.
Examples
This code generates 24 lines of output, which is too much:
for x in itertools.permutations([1, 2, 3, 4]):
print(x)
# OUTPUT
(1, 2, 3, 4)
(1, 2, 4, 3)
(1, 3, 2, 4)
(1, 3, 4, 2)
(1, 4, 2, 3)
(1, 4, 3, 2)
(2, 1, 3, 4)
(2, 1, 4, 3)
(2, 3, 1, 4)
(2, 3, 4, 1)
(2, 4, 1, 3)
(2, 4, 3, 1)
(3, 1, 2, 4)
(3, 1, 4, 2)
(3, 2, 1, 4)
(3, 2, 4, 1)
(3, 4, 1, 2)
(3, 4, 2, 1)
(4, 1, 2, 3)
(4, 1, 3, 2)
(4, 2, 1, 3)
(4, 2, 3, 1)
(4, 3, 1, 2)
(4, 3, 2, 1)
Instead, do the following, which only generates six lines of output:
for x in itertools.permutations([1, 2, 3]):
print(x)
# OUTPUT
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)
However, the following generates too little output and does not show the concept clearly:
for x in itertools.permutations([1, 2]):
print(x)
# OUTPUT
(1, 2)
(2, 1)
Avoid unnecessary output formatting or explanations
If you feel the need to add expository, you probably need to simplify your sample so that it does not create complex outputs.
Examples
print("This is the value for a: " + a)
print("Person {name}: {sex}, age {age}".format(
name = name,
sex = sex,
age = str(age)
))
def print_dict(d):
output = ""
for k, v in d.items():
output += "Key: " + key + " Value: " + value + "\\n"
print_dict(some_dict)
Whenever possible, produce the same output every time
Examples
When demonstrating functions such as random number generators, set a deterministic seed in the prelude if it is available:
KITE.start_prelude()
import random
random.seed(0)
KITE.stop_prelude()
print(random.randint(0, 10))
This is good because the user will only see the main code section, which will not be cluttered with the call to random.seed
.
When using numpy.random
, there is a similar seed function:
KITE.start_prelude()
from numpy.random import randn, seed
seed(0)
KITE.stop_prelude()
print(randn(2, 5))
For samples that involve time stamps, HTTP requests, and random number generators with no seed, this is not possible, which is okay.
Keep print calls as simple as possible
Always use a simple print
call to output values. Note that we use Python 3-style print(value)
, not print value
.
Examples
Don't use statements like these:
[print(item) for item in some_list]
print value1, value2, value3
print(value1, value2, value3)
from pprint import pprint
pprint(some_dict)
Prefer to print lists with a for
statement
Examples
This sample requires a more advanced understanding of Python iterators and should be avoided:
print(list(itertools.permutations([1, 2, 3])))
Instead, use this syntax:
for x in itertools.permutations([1, 2, 3]):
print(x)
Output binary data as raw strings
Even though this can cause broken characters to appear, we still want to keep print calls as simple as possible.
Examples
print(binary_data)
If binary data will not output as a raw string (e.g. when the binary contains null bytes or is too small to be interpreted as a string), use binascii.hexlify
Examples
print(binascii.hexlify(binary_data))
When printing a return value and a side effect, start by printing the return value
Examples
a = [1, 2, 3]
val = a.pop(0)
print(a)
# output: [2, 3]
print(val)
# output: 1
Instead, start by printing the return value, then the side effect.
a = [1, 2, 3]
val = a.pop(0)
print(val)
# output: 1
print(a)
# output: [2, 3]
Miscellaneous
Don't use advanced concepts unless necessary
Examples
This sample works, but may be difficult for beginners who are not familiar with Python's dictionary unpacking syntax:
data = {"person": "abc", "age": 5}
print("{person} is age {age}".format(**data))
Instead, this sample is easy for everyone to understand:
print("{person} is age {age}".format(person="abc", age=5))
Don't write samples that demonstrate what not to do
Examples
try:
print(pickle.loads("pickle"))
except IndexError:
print("String does not contain pickle data")
However, it is sometimes good to include a demonstration of common failure modes as part of a larger sample.
dictionary = {"a": 1}
print(dictionary.pop("a"))
print(dictionary)
try:
print(dictionary.pop("a"))
except KeyError as e:
print("KeyError: " + e.message)
print(dictionary.pop("a", None))
Demonstrate the purpose, not simply the functionality
Code samples should demonstrate the purpose of its functions, not merely their functionality. Use functions in a way that mirrors their intended usage, and clearly show the purpose that the function serves.
Examples
print(secure_filename("a b"))
# OUTPUT: 'a_b'
print(secure_filename("../../../etc/passwd"))
# OUTPUT: 'etc_passwd'
Only use comments when a sample cannot be written in a self-explanatory way
Strive to write samples that do not need comments to explain what they do. If an explanation is absolutely necessary, include a brief comment above the section that requires explanation; do not use inline comments.
Examples
This is obvious and does not need a comment:
# Dump to string
output_string = csv.dumps([1, 2, 3])
This is obvious and is also using an inline comment:
csv.loads(string) # load from string
This comment is helpful to include because the line is confusing on its own, but cannot be written more clearly because has_header
cannot be called with a keyword argument:
# Sample the first 256 bytes of the file
print(sniffer.has_header(f.read(256)))
Bundle together simple demonstrations
Code samples that call the same function with different parameters can generally be bundled together into a "cheat sheet" sample that provides users with a quick reference to the usages of the function, if the function calls all demonstrate the same concept.
Examples
# ANSWER: How to construct a dictionary
print(dict(a=1, b=2))
print({"a": 1, "b": 2})
print(dict([("a", 1), ("b", 2)]))
print(dict({"a": 1, "b": 2}))
print(dict(zip(["a", "b"], [1, 2])))
Functions like dateutil.rrule
are exceptions because they provide conceptually different outputs based on the arguments provided.
Don't write samples that simply construct an object
Object construction on its own is not informative; it is much more helpful to see how an object is used.
Examples
pattern = re.compile("\[a-z\]+\[0-9\]+")
print(pattern)
pattern = re.compile("\[a-z\]+\[0-9\]+")
print(pattern.match("test123"))
Don't reimplement default behavior
Examples
Here is a bad sample showing a class with an explicit pickling function:
import cPickle
class Foo(object):
def __init__(self, value):
self.value = value
def __getstate__(self):
return {'the\_value': value}
f = Foo(123)
s = cPickle.dumps(f)
The problem with the code sample above is that, by default, cPickle uses the __dict__
attribute whenever there is no getstate
function. So the code in the sample above would have produced the exact same output even if the getstate
function had been omitted. This is bad because it's not clear to the user why the getstate
function is important, since the result is exactly what would have happened anyway if getstate
had been omitted. Instead, a better sample would implement getstate
in a way that is different to the default behavior.
Use explicit keyword arguments when there are many arguments to a function
Examples
xdata = np.arange(10)
ydata = np.zeros(10)
plot(xdata, ydata, style='r-', label='my data')
Use keyword arguments when it is standard practice to do so
Examples
This works but is non-standard:
a = array([1, 2, 3], float)
Whereas this is standard practice for numpy
code:
a = array([1, 2, 3], dtype=float)
When using multi-variable assignment with long tuples, print the tuple first
This allows users to more easily match up the variables with their values and helps users who are not familiar with the syntax understand what is going on.
Examples
st = os.stat(open("sample.txt"))
print(st)
mode, ino, dev, nlink, uid, gid, size, accessed, modified, created = st
Use the isoformat
method to format datetime
objects, instead of strftime
strftime
tends to be long and unwieldy, and is not completely standardized. isoformat
has a standard output that is decently readable and makes the code sample much more concise. Of course, when you can, you should print out the datetime
object directly, so you can take advantage of the default repr
method that outputs a nicely-formatted representation of the date and time.
When making comparisons, make your code samples as similar as possible
This will make it easy for the reader to compare them.
Examples
For example, when comparing list.pop()
and list.pop(i)
, make all surrounding parts of each code sample the same.
a = [1, 2, 3]
val = a.pop(0)
print(val)
# output: 1
print(a)
# output: [2, 3]
a = [1, 2, 3]
val = a.pop()
print(val)
# output: 3
print(a)
# output: [1, 2]
Reminder: Do not copy-and-paste from Stack Overflow
Our relationship with StackOverflow is that we are referring to them to know what topics need better answers. If the answers on StackOverflow were sufficient, our site would not be needed.
Be especially mindful of not replicating variable names, and other arbitrary elements of code samples from StackOverflow.
Also, do not copy text or code from StackOverflow, either directly or with minor changes.
Advanced Features
I/O Interleaving
# KITE.set_auto_io(val: bool = True), KITE.display_io()
# disables automatic I/O interleaving
KITE.set_auto_io(False)
print('abc')
print('xyz')
KITE.display_io()
# output is flushed automatically at KITE.set_auto_io(True) or at end of the code block
print('def')
KITE.set_auto_io(True)
Filestystem
Writing Files
# KITE.write_file(path: str, data: AnyStr, encoding: str = 'ascii', display: bool = False)
# write file to disk with the given contents.
# If isinstance(data, bytes), encoding is ignored.
# Otherwise, encoding can be any valid Python str encoding or 'base64'.
# If display is true, the file is also displayed.
KITE.write_file('test_file.txt', 'test contents\n'
Sample Files
# KITE.write_sample_file(name: str, dst: str = None, display: bool = False)
# writes sample file/directory `name` to the given `dst` path (defaults to dst = name).
# See below for a list of currently available samples.
KITE.write_sample_file("sample.html", dst="my_sample.html", display=True)
List Directory
# KITE.list_directory(path: str = ".", *, cols: Tuple[str, ...] = ('permissions', 'size', 'name'), depth: int = 1)
# displays a directory listing formatted similar to `ls`.
# Valid `cols` also include 'user', 'group'. The ordering is taken into account.
KITE.list_directory()
Display
File Display
# KITE.display_file(path: str, limit: int = 10000)
# displays file contents
KITE.display_file('test_file.txt')
Image Display
# KITE.display_image(path: str)
KITE.display_image('red_image.jpg')
Arbitrary Data Display
# KITE.display(title: str, data: str)
# displays arbitrary data in an output block.
# Furthermore, all KITE.display* commands support a `title` keyword argument
# to manually set a title for the output block.
KITE.display("My Custom Title", "custom output data")
Capture I/O
Warning: Currently unused
# KITE.set_capture_io(val: bool = True)
# disables capturing & displaying I/O
KITE.set_capture_io(False)
print('this is not printed')
KITE.set_capture_io(True
Interactive mode
Warning: Currently unused
# KITE.set_interactive_mode(val: bool = True)
# auotmatically prints expressions that don't evaluate to None
KITE.set_interactive_mode()
"this is printed automatically"
KITE.set_interactive_mode(False)
Networking
Warning: Currently unused
# KITE.do_async_http(method: str, url: str, *, display_request: bool = True, **kwargs)
# instructs the runtime to execute all following code asynchronously.
# At the end of execution, an HTTP request will be made using the provided arguments
# to requests.request(): see https://2.python-requests.org/en/master/api/#requests.request
# The `display_request` parameter allows control over whether the request text is displayed.
# I/O capture will be disabled until manually re-enabled via KITE.set_capture_io(True).
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
KITE.do_async_http('GET', 'http://localhost:8080')
app.run(host="0.0.0.0", port=8080)
HTTP Requests
To demonstrate code that needs to make a REST call to a webserver, use httpbin.
The sandbox can make HTTP requests, or example using requests.request()
. This includes GET, POST, etc... and customized request bodies and headers. However, the sandbox cannot dur multiple successions of HTTP requests, for example in OAuth.