How to Python
Basic Concepts
Strings & Variables
Control Structures
List Functions
List.append(value)- adds a value to the end of an existing list. Returns nonelen(list)- returns the length of a listList.insert(index, value)- insertsvalueat any specified position in a listList.index(value)- finds the first occurrence of avalueand returns its indexmax(list)min(list)- returns the highest or lowest value in a listlist.count(item)- returns count of how many timesitemoccurs in a listlist.remove(item)- removes an object from a listlist.reverse()- reverses the items in a list
while Loops
- while loops repeat code as long as a condition evaluates to true
i = 0
while i < 4:
print(i)
i += 1
# prints 0 1 2 3
breakcan be used to end an infinite loop by placing it inside a conditional.continueends the current iteration and starts the next iteration.
for Loops
- The
forloop is used to iterate over a given sequence, such as lists or strings.
words = ['hello', 'world', 'spam', 'eggs']
for word in words:
print(word + '!')
# hello!
# world!
# spam!
# eggs!
Range
range(num)returns a sequence of numbers.- By default, it starts from 0 and stops before the specified number.
range(start, stop)- A second argument can be included to change the start point. The start number will be included in the range, while the stop number will not be included in the range.range(start, stop, step)- A third argument can be included to determine the interval that steps increase by.range(20, 5, -2)- A negative step value can be used to generate a range of decreasing numbers.
Functions and Modules
Code Reuse
- When writing code, try to abide by DRY - Don’t Repeat Yourself
- The opposite principle is WET - Write Everything Twice
- DRY code is easier to maintain and can be achieved using functions
Functions
In python, functions are created using the def statement. They are invoked using function_name().
def my_fun():
print('hello')
print('world')
my_fun()
NOTE: Functions must be defined before they are called.
Function Arguments
When defining a function, arguments can be declared inside of the parentheses ().
def print_sum_twice(x, y):
print(x + y)
print(x + y)
print_sum_twice(3, 2)
# 5
# 5
Returning from Functions
return can be used to make a function output a result. It cannot be used outside of a function definition.
Upon return from a function, execution is stopped.
def add_numbers(x, y):
total = x + y
return total
print("this won't be printed")
Comment and Docstrings
Comments are annotations to make code easier to understand. They do not affect how code is run. Comments are annotated using an octothorpe #. Python doesn’t have general purpose multiline comments.
x = 365 #Comments can be inline
y = 7
#They can also have their own line
Docstrings are created under the first line of a function definition. They are retained throughout runtime and can be inspected at runtime. A docstring can include multiple lines of text and is enclosed by """ before and after the text:
def shout(word):
"""
Print a word with an
exclamation mark added.
"""
print(word + '!')
shout("hello")
Functions as Objects
After definition, functions behave similarly to any other value. They can be assigned and reassigned to variables.
Functions can also be used as arguments in other functions. When used as an argument, functions do not need to include their parentheses.
def square(x):
return x * x
#accepts func as argument and prints result of executing on x
def test(func, x):
print(func(x))
#execute.
test(square, 42)
#prints 1764
Modules
Modules are pieces of code that have already been written to fulfill common tasks. They are accessed using the import keyword, with module variables and functions accessed using module_name.var notation.
#imports math module, with all included variables and functions
import math
#only imports specified values from math module, separated by a comma (,)
from math import pi, sqrt
#imports from module and assigns new name
from math import sqrt as square_root
NOTE: Trying to import an unavailable module will result in an ImportError.
The Standard Library & pip
There are 3 types of modules in Python: those you write yourself, those you install from external sources, and those that are preinstalled with Python.
Preinstalled libraries are known as the standard library.
Many third-party Python modules are stored in the Python Package Index (PyPI). Third party libraries can be installed with a program called pip. Example: pip install library_name
Exceptions & Files
Exceptions
Exceptions occur when something goes wrong in code, such as incorrect code or input. When this happens, then program immediately stops.
Some common exceptions are:
- ImportError: an import fails
- IndexError: a list is indexed with an out-of-range number
- NameError: an unknown variable is used
- SyntaxError: the code can’t be parsed properly
- TypeError: a function is called on a value of an inappropriate type
- ValueError: a function is called on a value of the correct type but with an inappropriate value.
NOTE: Third-party libraries often define their own exceptions. Read the docs!
Exception Handling
Exceptions in Python are handled using try/except statements. Code in the try block attempts to execute. If an exception is encountered, execution stops and code in the except block is run.
# From sololearn.com:
try:
num1 = 7
num2 = 0
print(num1 / num2)
print("Done calculation")
except ZeroDivisionError:
print("An error ocurred")
print("due to zero division")
A single try statement an be followed by multiple different except statements for handling different exceptions.
An except statement without any exception specified will catch all errors.
finally
finally: can be placed at the end of a try/except block to specify code that will run no matter what.
Code in a finally code block runs even if an uncaught exception occurs in the preceding blocks (including exceptions in the except block).
Raising Exceptions
raise can be used to manually throw an exception. You must specify a type when raising an exception.
Arguments can be included in raised errors to provide more detail:
# From sololearn.com
name = "123"
raise NameError("Invalid name!")
Inside of an except block, raise can be used to raise whatever exception occurred.
Assertions
The assert keyword can be used to perform a sanity-check in code. assert will test a given condition and throw an exception if it evaluates false.
# From sololearn.com
print(1)
assert 2 + 2 == 4
print(2)
assert 1 + 1 == 3
#Exception will be thrown and execution will stop
print(3)
assert can take a second argument, passed to the error raised if the assertion fails.
assert (temp >= 0), "Colder than absolute zero!"
Opening Files
Python can read and write file contents. Before editing, a file must be opened using the open function, the argument of which is the file path:
my_file = open("filename.txt")
A second argument can be used to specify the mode used to open a file:
"r"- read mode (default)"w"- write mode, for rewriting contents. Creates new file if it doesn’t exist."a"- append mode, for adding new content"b"- can be added to open in binary mode, which is used for non-text files.
When done with a file, you should close it. this is done using close():
# closes file from previous example
my_file.close()
Reading Files
A file opened in text mode can be read using .read()
A number can be provided as an argument specify how many bytes of a file to read. Negative values will return the entire contents.
After all contents are read, further reading will return an empty string.
The .readlines() method can be used to return a list of individual lines in a file.
for can also be used to iterate through lines of an opened file.
Writing Files
Files can be written to using the .write() method.
CAUTION: When opening a file in write mode, the file’s existing content is deleted.
the .write() method returns the number of bytes written to a file, if successful.
Working with Files
Best practice dictates that files should always be closed after work is done. A good way to ensure this is the use of try/finally:
#From sololearn.com
try:
f=open("file.txt")
print(f.read())
finally:
f.close()
Another way to accomplish this is by using with statements. This allows for the creation of a temporary variable, only accessible inside the following code block. The file is automatically closed at the end of the statement.
# file is opened as f
with open("filename.txt") as f:
print(f.read())
# f is closed automatically at end of block
More Types
None
None is used to represent the absence of a value, similarly to null in other languages:
- Evaluates as False when used as a boolean
- Represented by an empty string in the Python console
- Any function without an explicit return returns
None
Dictionaries
Dictionaries are data structures that map keys to values. Can be indexed similarly to lists, using square brackets.
# Think objects from JS!
samus = {
"varia_suit": True,
"arm_cannon": True,
}
print(samus["varia_suit"])
Trying to index a key that doesn’t exist will return a KeyError.
Dictionary keys must be immutable. Using a mutable value as a key will cause a TypeError.
Dictionary Functions
Dictionary keys can be assigned values. New keys can also be assigned values.
samus["varia_suit"] = False
samus["gravity_suit"] = True
in and not in can be used to determine the presence of a key in a dictionary.
print("gravity_suit" in samus)
# True
print("missile" in samus)
# False
print("missile" not in samus)
# True
get behaves similarly to indexing, but can return another specified value is the key provided doesn’t exist: samus.get("morph_ball", "upgrade not found")
Tuples
Tuples are like lists, but they are immutable. A tuple is enclosed in parentheses ().
planets = ("ZDR", "SR388", "Zebes", "Phaaze", "Tallon IV", "K-2L", "Dark Aether", "Elysia")
Tuple values are still indexed by number, but trying to reassign an index value will cause a TypeError.
NOTE: A tuple can also be created without parentheses by simply separating values with commas.
#Also a valid tuple assignment
planets = "ZDR", "SR388", "Zebes", "Phaaze", "Tallon IV", "K-2L", "Dark Aether", "Elysia"
List Slices
List slices are a more advanced way of retrieving values from a list. Similarly to range the second index number in a slice is not included in the result.
List slices return a new list containing the index values specified.
hunters = ["Samus", "Noxus", "Spire", "Kanden", "Sylux", "Trace", "Weavel"]
print(hunters[2:5])
#['Spire', 'Kanden', 'Sylux']
Omitting the first or second number in a slice is taken to specify the start or end of the list, respectively.
print(hunters[:5])
#['Samus', 'Noxus', 'Spire', 'Kanden', 'Sylux']
print(hunters[2:])
#['Spire', 'Kanden', 'Sylux', 'Trace', 'Weavel']
Similarly to range, a third number can be included in slices to specify step size.
print(hunters[1:6:2])
#['Noxus', 'Kanden', 'Trace']
print(hunters[::3])
#['Samus', 'Kanden', 'Weavel']
Negative values can be used to count from the end of a list instead of the beginning. They can also be used for step value to perform a slice backwards.
NOTE: list[::-1] is a common and simple way to reverse a list.
List Comprehensions
List comprehensions are a way to quickly create lists with specific rules.
squares = [i**2 for i in range(4)]
print(squares)
#[0, 1, 4, 9]
List comprehensions can also include if statements:
evens = [i**2 for i in range(10) if i**2 % 2 == 0]
print(evens)
# [0, 4, 16, 36, 64]
Trying to create a very large or extensive list will result in a MemoryError. This is solved with generators, which will be covered later.
String Formatting
String formatting is used to substitute values into a string, instead of converting and adding values as done in previous examples.
nums = [3, 4, 5]
string = "Numbers: {0} {1} {2}".format(nums[0], nums[1], nums[2])
print(string)
# 'Numbers: 3 4 5'
In the above example, each argument of .format() corresponds to a number in curly braces of the preceding string.
String formatting can also be done with named arguments.
msg = 'My name is {name} and I am {age} years old'
print(msg.format(name='Bob', age=27))
# 'My name is Bob and I am 27 years old'
Useful Functions
- String Functions
str.join(list)- joins a list of strings with another string as a separatorstr.replace(orig, new)- replaces on substring inside a string with anotherstr.startswith(substr)/str.endswith(substr)- determine if there is a substring at the start or end of a string (True/False)str.lower()/str.upper()- change the case of a stringstr.split(separator)- The opposite of join. Makes a string into a list of strings using a separator.
- Numeric Functions
max/min- find the maximum or minimum value in some numbers or a list.abs- find the distance from zero of a number (absolute value)round- round an number to a certain number of decimal placessum- find the total of a list.
- List Functions
all/any- take a list as an argument and return True if all or any arguments evaluate to Trueenumerate- iterates through values and indices simultaneously, as tuples.
Text Analyzer
Example project from sololearn:
# From sololearn.com
def count_char(text, char):
count = 0
for c in text:
if c == char:
count += 1
return count
filename = input('Enter a filename: ')
with open(filename) as f:
text = f.read()
for char in "abcdefghijklmnopqrstuvwxyz":
perc = 100 * count_char(text, char) / len(text)
print("{0} - {1}%".format(char,round(perc,2)))
Idk, pretty cool guess. Prints percentage of characters that each letter takes up in a file.
Functional Programming
Intro to Functional Programming
Functional programming is programming based around functions.
Higher-order functions are functions that accept other functions as arguments.
Pure Functions are functions with no side effects. Their output is entirely depending on provided arguments, and will always be the same given the same values as arguments.
Memoization is possible with pure functions, and involves storing the results of a certain input for recall later, instead of executing a function multiple times for the same input.
Lambdas
lambda syntax is Python’s way of creating anonymous functions. It consists of lambda arg: function
# From sololearn
def my_fun(f, arg):
return f(arg)
my_fun(lambda x: 2*x*x, 5)
Lambda functions can only do things that require a single expression. (no code blocks like in JS)
Lambda functions can also be assigned to variables and used like normal functions. As a general rule, it’s better to use def in cases where a function will be assigned.
map & filter
map(f, iterable) accepts a function and iterable as arguments, and returns a new iterable with the function applied to each argument.
A lambda can be used in place of the function argument, if desired.
filter(f, iterable) removes items that don’t evaluate true in a given function.
NOTE: Both map and filter must be explicitly converted to a list if printing is desired, by wrapping in list()
Generators
Generators are a type of iterable. They don’t allow for arbitrary indices, but can be iterated through with for loops.
Generators are created using functions and the yield statement. yield is what defines a generator.
# from sololearn
def countdown():
i = 5
while i > 0:
yield i
i -=1
for i in countdown():
print(i)
Since generators only yield one item at a time, they don’t have a memory restriction, and can be infinite.
Finite generators can be converted to lists by using the list() function.
Generators also result in improved performance, on account of lower memory usage.
Decorators
Decorators are a way of modifying functions using other functions.
# From sololearn
def decor(func):
def wrap():
print("=====")
func()
print("=====")
return wrap
def print_text():
print("Hello world!")
decorated = decor(print_text)
# Executes wrap() with print_text() inside!
decorated()
Wow. A variable containing a function can be reassigned with a wrapped version, and Python allows for wrapping a function at definition using @:
#From Sololearn
def print_text():
print("Hello world!")
print_text = decor(print_text)
#the below and above lines accomplish the same task.
#print_text will be wrapped in decor when invoked.
@decor
def print_text():
print("Hello world!")
Recursion
Recursion at the most fundamental level involves a function calling itself. A classic example is the facorial function:
def facotrial(x):
if x == 1:
return 1
else:
return x * factorial(x-1)
In this example 1! = 1 and is known as our base case, or the condition that breaks out of the recursion and doesn’t involve further function calls.
Recursive functions can be infinite. This often happens when a base case if forgotten or incorrect. Infinitely recursive functions will result in a RuntimeError.
Recursion can also be indirect, in cases where one one function calls a second, which then calls the first, and so on.
# Fibonacci sequence using recursion
# (from sololearn):
def fib(x):
if x == 0 or x == 1:
return 1
else:
return fib(x-1) + fib(x-2)
Sets
Sets are similar to lists and dictionaries. They are created using {values...} or set(). To create an empty set, set() must be used, as {} will create an empty dict.
- Sets share certain operations with lists, such as
inandlen - Sets are unordered, and cannot be indexed
- Cannot contain duplicate elements
- Instead of
.append(), use.add() .remove()removes a specific element.pop()removes an arbitrary element
Mathematical operators can be used to combine sets:
|union - combines two sets to form a new one with the items in either&intersection - gets items only in both-difference - gets items in the first set but not the second^symmetric difference - gets items in either set, but not both
itertools
itertools is a standard library containing useful functions for functional programming:
count(num)- counts up infinitely from a value (iterable)cycle(iterable)- infinitely iterates through an iterablerepeat- repeats an object, either infinitely or a specific number of timestakewhile- takes items from an iterable while a predicate function remains truechain- combines several iterables into oneaccumulate- returns a running total of values in an iterable
Object Oriented Programming
Classes
In python, objects are created using classes.
A class describes what an object will be, but is separate from the object itself. It is essentially a blueprint used to create an object.
class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs
felix = Cat("ginger", 4)
stumpy = Cat("brown", 3)
__init__ is called when an instance of a class is created, and is the most important method in a class.
All methods must have self as their first parameter. When calling a method you don’t need to include self in the arguments as Python does it automatically.
instances of classes have attributes which can be accessed using dot notation. In __init__ we can use self.attribute to assign values to attributes.
Methods can be added within a class using def like other functions. The methods can then be accessed using dot notation like attributes.
class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs
def meow(self):
print("meow!")
felix = Cat("ginger", 4)
felix.meow()
# meow!
Class attributes can be defined by assigning a variable inside a class. They can then be accessed from an instance or the class itself.
Trying to access an attribute that doesn’t exist will result in an AttributeError
Inheritance
Inheritance allows for sharing of functionality between classes. Classes used for shared class functionality are referred to as superclasses.
Inheriting classes are called subclasses. A subclasses methods or attributes will override those of the superclass if they share the same name.
class Name(Superclass) is used to assign superclasses to classes, as seen below:
#from sololearn
class Animal:
def __init__(self, name, color):
self.name = name
self.color = color
class Cat(Animal):
def purr(self):
print("Purr...")
class Dog(Animal):
def bark(self):
print("Woof!")
fido = Dog("Fido", "brown")
print(fido.color)
fido.bark()
#fido inherited attributes from the Animal superclass!
Inheritance can be chained, which is called indirect inheritance.
super refers to the parent class and can be used to invoke methods from a superclass.
Magic Methods & Operator Overloading
Magic methods are special methods surrounded with double underscores, like __init__. They are also known as dunders.
One use of dunders is operator overloading which defines operators for customer classes.
# from sololearn
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
first = Vector2D(5, 7)
second = Vector2D(3, 9)
#__add__ redefines the + operator
result = first + second
print(result.x)
print(result.y)
Other operator magic methods are:
__sub__for-__mul__for*__truediv__for/__floordiv__for//__mod__for%__pow__for**__and__for&__xor__for^__or__for|
x + y is translated to x.__add__(y).
If __add__ isn’t implemented on x yet, the equivalent r method is called: y.__radd__(x)
Python also has comparison magic methods:
__lt__for<__le__for<=__eq__for==__ne__for!=__gt__for>__ge__for<=
If __ne__ is not implemented, it returns it’s opposite of __eq__. there are no other relationships for comparison operators.
Object Lifecycle
The object lifecycle goes creation > manipulation > destruction.
The first stage is the definition of a class, followed by instantiation when __init__ is called.
__new__ is called and memory is allocated for storing the instance.
An object is destroyed when it’s reference count reaches zero. Upon destruction, allocated memory is freed up.
del is used to reduce the reference count of an object by one, often leading to deletion. del relates to the __del__ magic method.
Data Hiding
Encapsulation involves packaging related variables and functions into an instance of a class.
Data Hiding is a related concept, which states that implementation details of a class should be hidden.
Python’s philosophy is “we are all consenting adults here”, meaning private methods aren’t restricted.
Weakly private methods and attributes are preceded by a single underscore. This is mostly a convention, and the only effect will be that from module_name import * won’t import private variables.
Strongly private methods and attributes are preceded by a double underscore.
Strongly private variabels have their name mangled, essentially including the class name. They can still be accessed by using _Class__privatemethod.
Class & Static Methods
Class methods are called by a class and passed to the cls parameter fo a method.
Class methods are marked with a @classmethod decorator:
#From sololearn:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def calculate_area(self):
return self.width * self.height
@classmethod
def new_square(cls, side_length):
return cls(side_length, side_length)
square = Rectangle.new_square(5)
print(square.calculate_area())
A common use of class methods is as factory methods. They can instantiate an instance of a class with different parameters.
Static methods are similar, but don’t receive additional arguments. They don’t receive any additional arguments. They are identical to normal functions that belong to a class.
Static methods are marked with a @staticmethod decorator:
#from sololearn
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
@staticmethod
def validate_topping(topping):
if topping == "pineapple":
raise ValueError("No pineapples!")
else:
return True
ingredients = ["cheese", "onions", "spam"]
if all(Pizza.validate_topping(i) for i in ingredients):
pizza = Pizza(ingredients)
For reference:
self- regular methodscls- classmethods- Just args - staticmethods
Properties
Properties provide a way fo customizing access to instance attributes.
They are created using the @property decorator. When accessed, a method marked in this way executes instead. This can be used to make a property read-only.
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
@property
def pineapple_allowed(self):
return False
pizza = Pizza(["cheese", "tomato"])
print(pizza.pineapple_allowed)
#Trying to assign will cause an AttributeError
pizza.pineapple_allowed = True
Properties can be set with setter/getter functions. As the name implies, setters set a properties value, and getters get the value.
To define a setter or getter, use a decorator of @property.setter or @property.getter.
A Simple Game
Object-orientation is useful for managing different objects, such as in a game. Below is example code from sololearn of a simple game.
#from sololearn:
def get_input():
command = input(": ").split()
verb_word = command[0]
if verb_word in verb_dict:
verb = verb_dict[verb_word]
else:
print("Unknown verb {}".format(verb_word))
return
if len(command) >= 2:
noun_word = command[1]
print (verb(noun_word))
else:
print(verb("nothing"))
def say(noun):
return 'You said "{}"'.format(noun)
verb_dict = {
"say": say,
}
while True:
get_input()
#from sololearn:
class GameObject:
class_name = ""
desc = ""
objects = {}
def __init__(self, name):
self.name = name
GameObject.objects[self.class_name] = self
def get_desc(self):
return self.class_name + "\n" + self.desc
class Goblin(GameObject):
class_name = "goblin"
desc = "A foul creature"
goblin = Goblin("Gobbly")
def examine(noun):
if noun in GameObject.objects:
return GameObject.objects[noun].get_desc()
else:
return "There is no {} here.".format(noun)
verb_dict = {
"say": say,
"examine": examine,
}
class Goblin(GameObject):
def __init__(self, name):
self.class_name = "goblin"
self.health = 3
self._desc = "A foul creature"
super().__init__(name)
@property
def desc(self):
if self.health >= 3:
return self._desc
elif self.health == 2:
health_line = "It has a wound on its knee."
elif self.health == 1:
health_line = "Its left arm has been cut off!"
elif self.health <= 0:
health_line = "It is dead."
return self._desc + "\n" + health_line
@desc.setter
def desc(self, value):
self._desc = value
def hit(noun):
if noun in GameObject.objects:
thing = GameObject.objects[noun]
if type(thing) == Goblin:
thing.health = thing.health - 1
if thing.health <= 0:
msg = "You killed the goblin!
else:
msg = "You hit the {}".format(thing.class_name)
else:
msg = "There is no {} here.".format(noun)
return msg
Neat!
Regular Expressions
Reg Ex
Regular expressions are a domain specific language (DSL) that can be used for two main purposes:
- Verifying that strings match a pattern
- Performing substitutions in a string
Regular expressions are accessed in Python using the re module from the standard library.
re.match can be used to find a match at the beginning of a string.
import re
pattern = r"spam"
if re.match(pattern, "spamspamspam"):
print ("Match")
else:
print("No match")
The convention of r”expression” uses a raw string as the regex pattern, which is generally easy to work with. More complex regex patterns can be build, as we’ll see later.
Other Python re methods include:
re.search- finds a match of a pattern anywhere in a string.group()- returns the string matched with search.start()/.end()- return the respective start and end positions of the first match.span()- returns the start and end positions of first match as a tuple
re.findall- returns a list of all substrings matching a patternre.sub(pattern, repl, string, count=0)- replaces all occurrences ofpatternin astringwithrepl, unlesscountis provided, in which case it replacescountoccurrences. Returns modified string.
Simple Metacharacters
Metacharacters allow for more advanced matching. Characters like $ or other special regex characters will have to be escaped with \$ in order to be matched.
.- matches any character, other than new line.^- start of string$- end of string
Character Classes
Character classes match only one of a specific set of characters. They are created with square brackets []
They can also be used for ranges of characters: [a-z], [0-9], [A-Z]
^ when used in a character class inverts it. This matches any character not inside the class.
More Metacharacters
There are metacharacters for specifying numbers of repetitions for a match:
*- match zero or more repetitions of the previous thing+- match one or more repetitions?- match zero or one repetitions{low, high}- represents number of repetitions to match between a low and high number.
Groups
A group is made using parentheses (), which can be passed to a metacharacter.
Groups in a match can be accessed using group(), group(n) where n is a number > 0, or groups().
There are special groups:
(?P<name>...)will create a named group wherenameis the name and...is the content to match.(?:...)will create a non-capturing group which is not accessible by thegroup()methods.(...|...)can create anorbetween two expressions...
Special Sequences
\1to\99- matches the group of that number\d&\D- digits and NOT digits\w&\W- word characters and NOT word characters\s&\S- whitespace and NOT whitespace\A&\Z- beginning and end of string\b- boundary between words\B- empty string anywhere else
Pythonicness & Packaging
The Zen of Python
The Zen of Python is a tongue-in-cheek set of principles for programming in Python.
# to access the Zen of Python:
import this
# The Zen of Python, by Tim Peters
# Beautiful is better than ugly.
# Explicit is better than implicit.
# Simple is better than complex.
# Complex is better than complicated.
# Flat is better than nested.
# Sparse is better than dense.
# Readability counts.
# Special cases aren't special enough to break the rules.
# Although practicality beats purity.
# Errors should never pass silently.
# Unless explicitly silenced.
# In the face of ambiguity, refuse the temptation to guess.
# There should be one-- and preferably only one --obvious way to do it.
# Although that way may not be obvious at first unless you're Dutch.
# Now is better than never.
# Although never is often better than *right* now.
# If the implementation is hard to explain, it's a bad idea.
# If the implementation is easy to explain, it may be a good idea.
# Namespaces are one honking great idea -- let's do more of those
PEP
Python Enhancement Proposals are suggestions for improvements to the language.
PEP 8 is a style guide for writing readable code. Summarized, it says:
- modules should have short, all-lowercase names
- class names should be in the CapWords style
- most variables and function names should be lowercase_with_underscores
- constants should be CAPS_WITH_UNDERSCORES
- names that would clash with Python keywords should have a trailing underscore_
- operators should be surrounded with spaces, commas should be trailed by spaces
- lines shouldn’t be longer than 80 chars
from module import *should be avoided- there should only be one statment per line
More on Function Arguments
Python allows for varying numbers of arguments using *args at the end of function argument upon definition.
These arguments that fall within *args are accessed through the tuple args inside the function.
Named values can be made optional by assigning a default value:
def function (x, y, food="spam"):
print(food)
function(1, 2)
#prints spam
function(1, 2, "eggs")
#prints eggs
**kwargs can be used to handle names arguments that are not defined in advance. kwargs will return a dictionary.
Tuple Unpacking
Tuple unpacking assigns each item in an iterable to a variable:
numbers = (1, 2, 3)
a, b, c = numbers
#This can be used for quick variable swapping as well:
a, b = b, a
A variable with * can be used to catch leftover values when unpacking:
a, b, *c, d = [1, 2, 3, 4, 5, 6, 7, 8]
print(a)
print(b)
print(c)
print(d)
# 1
# 2
# [3, 4, 5, 6, 7]
# 8
Ternary Operator
Conditional expressions provide if...else functionality with less code.
a = 7
b = 1 if a >= 5 else 42
print(b)
# 1
Ternary refers to the fact that 3 arguments are used in the expression.
More on else Statements
else can be used after for and while, giving it a different meaning. In these cases, code inside of else will run if the loop finishes normally, and without a break.
else can also be used with try/except statements. In these cases, code will execute in the case of no errors within the try block.
__main__
Python code is often either a module to be imported or a script to do a thing. It is possible to write code that can do both!
To accomplish this, place script code inside if __name__ == "__main__":. Code inside this statement will not be executed on import.
def function():
print("this ia a module function!")
if __name__=="__main__":
print("this is a script!")
This works because of the Python interpretter’s behavior. If a file is being executed as the main program, Python assigns the name "__main__" to it. When importing a file, however, __name__ will be assigned the module’s given name.
Major 3rd-Party Libraries
There are lots of useful tools in the standard library, but there are also great third party tools:
- Django - the most frequently used web framework
- CherryPy & Flask - other popular web frameworks
- BeautifulSoap - very useful library for scraping data from websites
- matplotlib - create graphs based on data in Python
- NumPy - faster multidimensional arrays and matrix transformations
- SciPy - extends the functionality of NumPy
- Panda3D & pygame - make games in Python
Packages
Packaging refers to placing modules you’ve written into a standard format for others to easily use. This will involve the use of the setuptools and distutils modules.
The first step to packaging is organizing files correctly:
SoloLearn/
LICENSE.txt
README.txt
setup.py
sololearn/
__init__.py
sololearn.py
sololearn2.py
The directory containing your modules must include __init__.py which can be blank.
setup.py is also an important file, and contains information for assembling your package:
from distutils.core import setup
setup(
name="SoloLearn",
version = "0.1dev",
packages=['sololearn',],
license = 'MIT',
long_description=open('README.txt').read(),
)
Packaging for Users
Sometimes users will not have Python installed, in which case you should package programs as executables. There are tools to help us do this!
For Windows: py2exe, PyInstaller, and cx_Freeze can be used to create executables.
For Mac: py2app, PyInstaller, or cx_Freeze will get the job done.