[1, 2, 3]
{'key': 'value'}
set([1,2,3])
>>> # Create a list and a second reference to it
>>> ls = [1, 2, 3]
>>> ls_copy = ls
>>> # Append something to the original list
>>> ls.append(5)
>>> ls == ls_copy
True
>>> # The copy still references the same object, which is updated
>>> ls_copy
[1, 2, 3, 5]
>>> # Create a new list and copy the reference to ls
>>> new_ls = [5, 6]
>>> ls = new_ls
>>> # ls_copy still refers to the old list
>>> ls == ls_copy
False
'blah'
(1, 2, 3)
frozenset([1, 2,3 ])
>>> bikini_string = 'pink'
>>> marble_string = bikini_string
>>> # This creates a new object
>>> bikini_string += ' green'
>>> # Note: a += 1 is equivalent to a = a + 1
>>> bikini_string
'pink green'
>>> marble_string
'pink'
Actually, variables are references to objects.
References are passed in arguments to functions and methods - not objects or variables.
def try_to_change_list_contents(the_list):
print 'got', the_list
the_list.append('four')
print 'changed to', the_list
outer_list = ['one', 'two', 'three']
print 'before, outer_list =', outer_list
try_to_change_list_contents(outer_list)
print 'after, outer_list =', outer_list
Credits: Blair Conrad on StackOverflow
Consequence: mutable objects can be modified from within methods and functions.
before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']
Reassigning objects replaces the references so:
def try_to_change_list_reference(the_list):
print 'got', the_list
the_list = ['and', 'we', 'can', 'not', 'lie']
print 'set to', the_list
outer_list = ['we', 'like', 'proper', 'English']
print 'before, outer_list =', outer_list
try_to_change_list_reference(outer_list)
print 'after, outer_list =', outer_list
Yields:
before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']
import random
def random_integer(start, end=15):
"""
Return a random integer between start and end,
the default end being 15.
"""
print 'Returning integer between %d and %d' % (start, end)
result = random.randint(start, end)
return result
>>> random_integer(5)
Returning integer between 5 and 15
6
>>> random_integer(5, 5)
Returning integer between 5 and 5
5
>>> # Optionally: name parameters
>>> random_integer(start=5, end=5)
Returning integer between 5 and 5
5
class Food(object):
""" Something you can eat. """
# Class properties are shared across instances
destination = 'mouth'
def __init__(self, name):
"""
The initialization method is called whenever
instances are created.
"""
# Store the name property on the object
self.name = name
# Create the object unused
self.used = False
def use(self):
""" Use this particular item, marking it as used. """
print 'Using %s in %s' % (self.name, self.destination)
# Instance properties are specific to one instance
self.used = True
For similar types of data and related behaviour.
>>> lunch = Food(name='banana')
>>> lunch.used
False
>>> lunch.use()
Using banana in mouth
>>> lunch.used
True
Because code is read more than it is written.
Four (4) spaces, no tabs!
if sugar == sweet:
# Note: there's spaces here!
print 'Better go to the dentist!'
79 characters on a single line
print (
'When longer lines are required, simply use ()\'s for concatenation '
'but watch out with tuples!'
)
import os, sys
from mountain import *
From more fundamental to less fundamental.
import os
import sys
# Numpy is more fundamental than matlab
import numpy
# Group utils with the same base together
from matlab import polyplot, somethingelse
from matlab.utils import UselessUtilClass
# '.' imports from local directory (module)
from .utils import FunkyPlotHelper
Required and forbidden whitespace.
# Like this
my_dict = {
'key': 'value',
'otherkey': 'othervalue'
}
value = value + 5
do_something(1, 2, 3)
spam(ham[1], {eggs: 2})
# Not like this
my_dict = {'key' : 'value' , 'otherkey': 'othervalue'}
value=value+5
do_something(1 , 2 , 3 )
spam( ham[ 1 ], { eggs: 2 } )
Refer to PEP8
Write for reading!
def my_function():
""" What does it do, what does it return? """
# Note: empty functions require a 'pass' statement
pass
def other_function():
"""
This text is a bit longer so it needs to be spread over
multiple lines. Note that the quotes are on a line by themselves.
"""
# Now doing something useful
x = do_something_useful()
# Use inline comments sparingly
x = x + 1 # Don't do this
Go for descriptive!
# Good
max_value = 5
min_value = 3
class MyClass(object):
def square_number(self, n):
return n*n
# Bad
a = 5
B = 3
class my_Class(object):
def doit(n):
return n*n
$ pip install pep8
$ pep8 neat_code.py
neat_code.py:59:80: E501 line too long (96 > 79 characters)
neat_code.py:65:80: E501 line too long (90 > 79 characters)
neat_code.py:82:80: E501 line too long (89 > 79 characters)
neat_code.py:91:80: E501 line too long (80 > 79 characters)
neat_code.py:103:80: E501 line too long (81 > 79 characters)
neat_code.py:133:80: E501 line too long (113 > 79 characters)
neat_code.py:136:80: E501 line too long (103 > 79 characters)
Don't do stuff more than twice.
__init__.py
to any folder:
$ touch __init__.py
fromagerie.py
.import fromagerie
or
from fromagerie import MyClass
utils.py
for the rest
snowball --- __init__.py
|- main.py
|- utils.py
|- climate.py
`- water --- __init__.py
`- phases.py
main.py
Contains 'main' functionality typically used in external
applications. Could also be named core.py
or snowball.py
.
No clear naming convention here - just the fact that only minimal work should be done from the 'main' module.
utils.py
Non-specific util functions or classes that are otherwise ungroupable.
Examples: data conversion, common data structure manipulation, file reading wrappers.
climate.py
Contains climate-related classes and functions.
In this case a WeatherProbe
.
water
Module grouping code related to water physics, like
phase-transition logic in water/phases.py
which contains WaterVapor
, IceCrystal
and SnowFlake
.
Reference: The Hitchhiker’s Guide to Packaging
snowball --- setup.py
|- README.rst
|- LICENSE.rst
`- snowball --- __init__.py
|- main.py
|- utils.py
|- climate.py
`- water --- __init__.py
`- phases.py
setup.py
from setuptools import setup, find_packages
setup(
name = 'snowball',
version = '0.1dev',
packages = find_packages(),
license = 'BSD',
long_description = open('README.rst').read(),
)
Creating a distribution (tarball)
$ python setup.py sdist
Install without publishing
$ pip install -e git+https://github.com/dokterbob/snowball.git#egg=snowball
$ pip install http://some.domain/snowball-0.1.tar.gz
Registering it for PyPI
$ python setup.py register
Uploading and publishing
$ python setup.py sdist bdist_wininst upload
Installing
$ pip install snowball
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the SLF nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
Reference: Full 3-clause BSD license
Reference: choosealicense.com
README.rst
and LICENSE.rst
Title of file
=============
Subtitle
--------
* List item 1
* List item 2
`Link <https://www.google.com>`_
Similar to Markdown.
Comments and Docstrings
Care about your successors!
Be verbose, be very verbose!