Last active
August 29, 2015 14:21
-
-
Save bangedorrunt/f199e764f73cd11f230c to your computer and use it in GitHub Desktop.
Learning Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Spam: | |
def do_it(self, message): | |
print(message) | |
def do_it_without_self(message) | |
print(message) | |
spam = Spam() | |
bound_func = spam.do_it # Bound method object (automatically) | |
bound_func('yummy') # Same as spam.do_it('yummy') | |
bound_func2 = spam.do_it_without_self # Bound method object (automatically) | |
bound_func2('yummy') # Type Error: do_it_without_self() takes 1 positional argument but 2 were given | |
# because `bound_func2` automatically pass `self` or `spam` instance to method | |
# that does not expect one | |
unbound_func = Spam.do_it # Unbound method object | |
print(unbound_func) # Unbound methods are functions | |
unbound_func(spam, 'yummy') # Pass in instance | |
unbound_func2 = Spam.do_it_without_self # Unbound methods are functions | |
unbound_func2('yummy') #=> yummy | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Super: Defines a `method` function and a `delegate` that expects | |
an `action` in a subclass | |
Inheritor: Doesn't provide any new names, so it gets everything | |
defined in `Super` | |
Replacer: Overrides `Super`'s method with a version of its own | |
Extender: Customize `Super`'s method by overriding and all back | |
to run the default | |
Provider: Implement `action` method expected byu `Super` delegate method | |
""" | |
class Super: | |
def method(self): | |
print('in Super.method') # Default behavior | |
def delegate(self): | |
self.action() # Expected to be defined in subclass | |
class Inheritor(Super): | |
pass | |
class Replacer(Super): # Replace method completely | |
def method(self): | |
print('in Replacer.method') | |
class Extender(Super): # Extend method behavior | |
def method(self): | |
print('Starting Extender.method') | |
Super.method(self) | |
print('Ending Extender.method') | |
class Provider(Super): # Define required action method | |
def action(self): | |
print('in Provider.action') | |
for c in (Inheritor, Replacer, Extender): | |
print('\n' + c.__name__ + ': ') | |
c().method() | |
print('\nProvider: ') | |
Provider().delegate() # `delegate` is called from `Super` method | |
# with `self` is referenced to `Provider instance` passed in | |
# Then `action` is called | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Coordinate(object): | |
def __init__(self, x, y): | |
self.x = x | |
self.y = y | |
def __repr__(self): | |
return "Coord: " + str(self.__dict__) | |
def add(a, b): | |
return Coordinate(a.x + b.x, a.y + b.y) | |
def sub(a, b): | |
return Coordinate(a.x - b.x, a.y - b.y) | |
def wrapper(func): | |
def checker(a, b): # 1 | |
if a.x < 0 or a.y < 0: | |
a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0) | |
if b.x < 0 or b.y < 0: | |
b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0) | |
ret = func(a, b) | |
if ret.x < 0 or ret.y < 0: | |
ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0) | |
return ret | |
return checker | |
one = Coordinate(100, 200) | |
two = Coordinate(300, 200) | |
three = Coordinate(-100, -100) | |
add = wrapper(add) # This is a decorator | |
sub = wrapper(sub) # This is a decorator | |
sub(one, two) #=> Coord: {'y': 0, 'x': 0} | |
add(one, three) #=> Coord: {'y': 200, 'x': 100} | |
# Alternatively, use decorator | |
@wrapper | |
def add(a, b): | |
return Coordinate(a.x + b.x, a.y + b.y) | |
@wrapper | |
def sub(a, b): | |
return Coordinate(a.x - b.x, a.y - b.y) | |
sub(one, two) #=> Coord: {'y': 0, 'x': 0} | |
add(one, three) #=> Coord: {'y': 200, 'x': 100} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Sequence assignment | |
spam, ham = 'yum', 'yuck' # Tuple assignment | |
spam, ham = ham, spam # Tuple swap values | |
[spam, ham] = ['yum', 'yuck'] # List assignment | |
spam, ham = ['yum', 'yuck'] | |
[spam, ham] = ('yum', 'yuck') | |
s = 'Spam' | |
a, b, c, d = s | |
(a, b, c, d) #=> ('S', 'p', 'a', 'm') | |
((a, b), c) = ('Sp', 'am') # Nested destructure | |
(a, b, c) #=> ('S', 'p', 'am') | |
for (a, b, c) in ((1, 2, 3), (4, 5, 6)): | |
print(a, b, c) #=> 1 2 3 | |
#=> 4 5 5 | |
[a + b + c for (a, b, c) in [(1, 2, 3), (4, 5, 6)]] #=> [6, 15] | |
tuple(a + b + c for (a, b, c) in [(1, 2, 3), (4, 5, 6)]) #=> (6, 15) | |
{'Sum of {}, {}, {}'.format(a, b, c): a + b + c for (a, b, c) in [(1, 2, 3), (4, 5, 6)]} #=> {'Sum of 1, 2, 3': 6, 'sum of 4, 5, 6': 15} | |
# Extended Sequence Unpacking | |
# This is similar to `rest ...` operator in JavaScript | |
seq = 'Spam' | |
a, b, c, d = seq | |
a, b, c, d #=> ('S', 'p', 'a', 'm') | |
a, *b, c = seq | |
a, b, c #=> ('S', ['p', 'a'], 'm') | |
a, b, *c = seq | |
a, b, c #=> ('S', 'p', ['a', 'm']) | |
a, b, *c, d = seq | |
a, b, c, d #=> ('S', 'p', ['a'], 'm') | |
a, b, *c, d, e = seq | |
a, b, c, d, e #=> ('S', 'p', [], 'a', 'm') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
d = {'food': 'Spam', 'quantity': 4, 'color': 'pink'} | |
d['food'] #=> 'food' fetch value of key `food` | |
d['quantity'] += 1 | |
d #=> {'food': 'Spam', 'quantity': 5, 'color': 'pink'} | |
del d['color'] #=> {'food': 'Spam', 'quantity': 5} | |
d = {} | |
d['name'] = 'babygau' #=> Create key by assignment | |
d['job'] = 'freelancer' #=> Create key by assignment | |
d #=> {'name': 'babygau', 'job': 'freelancer'} | |
d1 = dict(name='babygau', job='freelancer') #=> {'name': 'babygau', 'job': 'freelancer'} | |
d2 = dict(zip(['name', 'job'], ['babygau', 'freelancer']) #=> {'name': 'babygau', 'job': 'freelancer'} | |
d3 = dict([('name', 'babygau'), ('job', 'freelancer')]) | |
d4 = dict.fromkeys(['name', 'job'], None) | |
d5 = dict.fromkeys(['name', 'job']) | |
d6 = {k:None for k in ['name', 'job']} | |
# Dictionary methods | |
list(d.keys()) #=> ['name', 'job'] `d.keys()` return iterable objects so wrap them in a list to collect their values | |
d.values() #=> ['babygau', 'freelancer'] `d.values()` return iterable objects too | |
d.items() #=> [('name', 'babygau'), ('job', 'freelancer')] | |
d.get('name') #=> babygau | |
d.get('gender') #=> NONE because `gender` is missing | |
d.get('gender', 'male') #=> 'male' as default value if 'gender' key is missing | |
d2 = {'gender': 'male'} | |
d.update(d2) #=> {'name': 'babygau', 'job': 'freelancer', 'gender': 'male'} merge `d2` into d | |
d.pop('gender') #=> {'name': 'babygau', 'job': 'freelancer'} | |
d.copy() | |
d.clear() | |
# Testing keys | |
if not 'discount' in d: | |
print('missing') | |
# Sorting keys | |
ks = list(d.keys()) | |
ks.sort() | |
ks #=> ['color', 'food', 'quantity'] | |
for key in ks: | |
print(key, '=>', d[key]) #=> 'color' => 'pink' | |
#=> 'food' => 'Spam' | |
#=> 'quantity' => '5' | |
for key in sorted(d): | |
print(key, '=>', d[key]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def generator_plus(number): | |
for i in range(number): | |
yield i | |
iter = generator_plus(5) # Return an iterator object | |
next(iter) #=> Start generator | |
next(iter) #=> 1 | |
next(iter) #=> 2 | |
next(iter) #=> 3 | |
next(iter) #=> 4 | |
next(iter) #=> StopIteration | |
# 2 way communication | |
# Note: `yield expression` must obtain value from `iterator's send()` method | |
# otherwise, `yield` will get `None` value | |
def generator_2way(): | |
a = 0 | |
b = (yield a) + 1 | |
c = (yield a + b) | |
print("a = {}, b = {}, c = {}".format(a, b, c)) | |
yield # Stupid fix for StopIteration occured before printing out values | |
iter = generator_2way() | |
next(iter) # Start generator for the first-run | |
# Don't send value, because just-started | |
# generator don't accept non-None value | |
#=> Yield out 0 | |
iter.send(7) #=> Yield out 8 | |
iter.send(10) #=> Yield nothing | |
#=> a = 0, b = 8, c = 10 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# `zip` | |
list(zip('abc', 'xyz')) #=> [('a', 'x'), ('b', 'y'), ('c', 'z')] | |
# map(func, *iterables) | |
tuple(map(lambda data: data * 2, range(3))) #=> (0, 2, 4) | |
m = map(lambda data: data *2, range(3)) | |
m.__iter__().__next__() #=> 0 | |
m.__iter__().__next__() #=> 2 | |
m.__iter__().__next__() #=> 4 | |
m.__iter__().__next__() #=> StopIteration Exception | |
# filter(func or None, *iterable) | |
tuple(filter(lambda data: data % 2, range(10))) #=> (1, 3, 5, 7, 9) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: List is the most general sequence provided by Python. | |
# they have no fixed size and are also mutable - lists can | |
# be modified in place by assignment to offsets as well as a | |
# variety of list method calls. | |
l = [123, 'hello', 1.23] | |
len(l) #=> 3 | |
l[0] #=> 123 | |
l[:-1] #=> [123, 'hello'] | |
l + [4, 5, 6] #=> [123, 'hello', 1.23, 4, 5, 6] | |
l * 2 #=> [123, 'hello', 1.23, 123, 'hello', 1.23] | |
# List methods | |
l.append('world') #=> [123, 'hello', 1.23, 'world'] | |
l.pop(2) #=> 1.23 | |
l.pop(0) #=> 123 | |
l #=> ['hello', 'world'] | |
l.sort() #=> ['hello', 'world'] | |
l.reverse() #=> ['world', 'hello'] | |
l.sort(key=str.lower) #=> ['hello', 'world'] | |
l.sort(key=str.lower, reverse=True) #=> ['world', 'hello'] | |
l.extend([456]) #=> ['world', 'hello', 456] | |
l.insert(0, '!') #=> ['!', 'world', 'hello', 456] | |
l.index('!') #=> 0 | |
l.count(456) #=> 1 | |
l.pop(3) #=> ['!', 'world', 'hello'] | |
l.remove('!') #=> ['world', 'hello'] | |
del l[0] #=> ['hello'] | |
lCopy = l.copy() #=> `lCopy` is not reference of `l` any more | |
lCopy = l[:] #=> The same with `copy()` method but use `empty-limit slice` approach | |
# Multi-dimensional array | |
m = [[1, 2, 3], | |
[4, 5, 6], | |
[7, 8, 9]] #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] | |
m[1] #=> [4, 5, 6] | |
m[1][2] #=> 6 get row 2, then get item 3 within the row | |
# List comprehensions | |
col2 = [row[1] for row in m] #=> [2, 5, 8] | |
col2 = [row[1] + 1 for row in m] #=> [3, 6, 9] | |
col2 = [row[1] for row in m if row[1] % 2 == 0] #[2, 8] fill out odd items | |
diag = [m[i][i] for i in [0, 1, 2]] #=> [1, 5, 9] collect a diagonal from matrix | |
list(range(4)) #=> [0, 1, 2, 3] | |
list(range(-6, 7, 2)) #=> [-6, -4, -2, 0, 2, 4, 6] collect of range from -6 to +6 by step of 2 | |
# Create generators | |
g = (sum(row) for row in m) | |
next(g) #=> 6 | |
next(g) #=> 15 | |
next(g) #=> 24 | |
list(map(sum, m)) #=> [6, 15, 24] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def func(): | |
data = 'local variable' | |
def nested_func(): | |
data += ' inside nested_func' # Bug here: `data + ' inside nested_func'` is evaluated first | |
# but actually it is not defined inside `nested_func` | |
print(data) | |
return nested_func | |
test = func() | |
test() #=> UnboundLocalError: local variable 'data' referenced before assignment | |
# Fix: | |
def func(): | |
data = 'local variable' | |
def nested_func(): | |
global data | |
data += ' inside nested_func' | |
print(data) | |
return nested_func | |
test = func() | |
test() #=> 'local variable inside nested_func' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Module Search Path | |
# ------------------ | |
""" | |
1. The home directory of program | |
2. PYTHONPATH directory | |
3. Standard library directories | |
4. The contents of any .pth files | |
5. The site-packages home of 3rd party extensions | |
""" | |
# Module Usage | |
# ------------ | |
import module1 | |
module1.printer('Spam') #=> Spam | |
from module1 import printer | |
printer('Spam') #=> Spam | |
from module1 import * | |
printer('Spam') #=> Spam | |
another_printer('Ham') #=> Ham | |
# Imports are passed by reference | |
# ------------------------------- | |
# mod1.py | |
int = 1 # This is immutable value | |
l = [1, 2, 3] # This is mutable list | |
# mod2.py | |
from mod1 import int, l | |
int = 2 # Change local `int` only | |
l[0] = 0 # Changes shared mutable `l` | |
import mod1 | |
mod1.x #=> 1 | |
mod1.l #=> [0, 2, 3] | |
# `import` and `from` equivalence | |
# ------------------------------- | |
from module1 import x, y | |
import module1 | |
x = module1.x | |
y = module1.y | |
del module1 # Get rid of module1 name | |
# Name conflicts among modules | |
# ---------------------------- | |
# mod1.py | |
def func(): | |
# mod2.py | |
def func(): | |
# main.py | |
from mod1 import func | |
from mod2 import func # This will overwrites `func` from `mod1` | |
func() # Only call `mod2.func` | |
# Fix | |
# main.py | |
import mod1 | |
import mod2 | |
mod1.func() | |
mod2.func() | |
# A better approach | |
# main.py | |
from mod1 import func as mod1_func | |
from mod2 import func as mod2_func | |
mod1_func() | |
mod2_func() | |
# Module Packages (or Regular Packages) | |
# ------------------------------------- | |
""" | |
In addition to a module name, an import can name a directory path. | |
A directory of Python code is said to be a package, so such imports are known | |
as package imports | |
At least until Python 3.3, each directory named within the path of a package | |
import statement must contain a file named `__init__.py__` or your package | |
import will fail | |
""" | |
# dir0/dir1/dir2/mod.py | |
# dir0/ | |
# dir1/ | |
# __init__.py | |
# dir2/ | |
# __init__.py | |
# mod.py | |
import dir1.dir2.mod | |
from dir1.dir2.mod import x, y | |
# Package Relative Imports | |
# ------------------------ | |
""" | |
Python imports select between relative (in the containing directory) | |
and absolute (in the directory on sys.path) resolution as follows: | |
- Dotted imports: from . import mod | |
Are relative-only in both 2.X and 3.X | |
- Non-dotted imports: import mod, from mod import x | |
Are relative-then-absolute in 2.X | |
To change 2.X import behavior to absolute only, use: from __future__import absolute_import | |
Are absolute-only in 3.X | |
""" | |
# mypkg/ | |
# __init__.py | |
# main.py | |
# string.py | |
# In 3.X | |
import string # Imports standard `string` lib | |
from string import name # Imports `name` from standard `string` lib | |
from . import string # Imports `string` lib from `mypkg` | |
from .string import name # Imports name from `string` lib from `mypkg` | |
from mypkg import string # Import `string` lib from `mypkg` only if | |
# `mypkg` is on `sys.path` | |
# Namespace Packages | |
# ------------------ | |
# mypkg/module1/sub/mod1.py | |
# mypkg/module2/sub/mod2.py | |
# Givent that `mypkg/module1` and `mypkg/module2` is on `sys.path` | |
import sub | |
sub #=> <module 'sub' (namespace)> namespace packages: nested search paths | |
sub.__path__ #=> _NamespacePath(['/usr/mypkg/module1', '/usr/mypkg/module2']) | |
from sub import mod1 | |
from sub import mod2 | |
# mod1.py | |
from . import mod2 | |
from .mod2 import x, y | |
# mod2.py | |
from . import mod1 | |
from .mod1 import a, z | |
# Module Attribute __name__ | |
# ------------------------- | |
""" | |
Each module has a built-in attribute called `__name__`, which Python creates | |
and assigns automatically as follows: | |
- If the file is being run as a top-level program: `__name__` is set to `__main__` | |
- If the file is being imported instead: `__name__` is set to `module_name` | |
""" | |
def tester(): | |
print("Spam is yummy") | |
if __name__ == '__main__': | |
tester() # Only called when run program at top-level | |
# Not when imported |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: By default, all the names assigned inside a function definition are | |
# put in the local scope (the namespace associated with the function call). | |
# If you want to assign a name that lives in an `enclosing def`, you can do | |
# so by declaring it in `nonlocal` statement. If you need to assign a name | |
# that lives at the top level of the module enclosing the function, you can do | |
# so by declaring it in an `global` statement. | |
value = 'global' | |
def func(): | |
def enclosing_func(): | |
nonlocal value # Explicitly declare non-local variable | |
value = 'non local' # `value` can live in `func()` | |
value = 'local' # Local value | |
enclosing_func() | |
print(value) | |
func() #=> 'non local' is printed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 + 234 #=> 357 | |
1.5 * 4 #=> 6.0 | |
2 ** 3 #=> 8 | |
len(str(2 ** 1000000)) # How many digits in a really BIG number? => 301030 | |
# Use standard module | |
import math | |
math.pi #=> 3.141592653589793 | |
math.sqrt(4) #=> 2 | |
import random | |
random.random() #=> 0.52342314324234 | |
random.choice([1, 2, 3, 4, 5]) #=> 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# `__getitem__` and `__setitem` | |
class Indexer: | |
data = [1, 2, 3 , 4] | |
def __getitem__(self, index): | |
print('getitem: ', index) | |
return self.data[index] | |
x = Indexer() | |
x[0] #=> 1 | |
x[-1] #=> 4 | |
x[1:3] #=> [2, 3] | |
for item in Indexer: | |
print(item, end=' ') #=> 1 2 3 4 | |
# `__iter__` and `__next__` | |
class Squares: | |
def __init__(self, start, stop): | |
self.value = start - 1 | |
self.stop = stop | |
def __iter__(self): # Get iterator object on iterable | |
return self | |
def __next__(self): | |
if self.value == self.stop: | |
raise StopIteration | |
self.value += 1 | |
return self.value ** 2 | |
for item in Square(1, 5): | |
print(item, end=' ') # 1 4 9 16 25 | |
iterator = iter(Square(1, 5)) # Obtain iterator from Square | |
next(iterator) #=> 1 | |
next(iterator) #=> 4 | |
next(iterator) #=> 9 | |
next(iterator) #=> 16 | |
next(iterator) #=> 25 | |
next(iterator) #=> StopIteration Exception | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# All parameters (arguments) in the Python language are passed by reference. | |
# It means if you change what a parameter refers to within a function, the | |
# change also reflects back in the calling function | |
list = [1, 2, 3] | |
id(list) #=> 4432037256 | |
def func(arg): | |
id(arg) | |
func(list) #=> 4432037256 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: Sets are unordered collections of unique and immutable objects | |
x = set('Spam') | |
y = {'m', 'e'} | |
x, y #=> ({'S', 'p', 'a', 'm'}, {'m', 'e'}) a tuple of two sets without parentheses | |
x & y #=> {'m'} intersection | |
x.intersection(y) #=> {'m'} intersection | |
x | y #=> {'S', 'p', 'a', 'm', 'e'} union | |
x - y #=> {'a', 'p', 'S'} differences from `y` | |
x > y #=> False superset | |
x.add('m') #=> insert one item at a time | |
x.update(y) #=> merge (union) | |
x.remove('m') #=> remove one item at a time | |
# Set comprehensions | |
{n ** 2 for n in [1, 2, 3]} #=> {9, 1, 4} | |
# Filtering out duplicates | |
list(set([1, 2, 2, 3, 4, 4])) #=> [1, 2, 3, 4] | |
# Finding differences in collections | |
set('Spam') - set('me') #=> {'S', 'p', 'a'} | |
# Testing equality | |
set('Spam') == set('maSp') #=> True | |
# Testing set items and other collections | |
'p' in set('Spam'), 's' in list('Spam'), 'h' in 'hello' #=> (True, False, True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: String is immutable, they cannot be changed in place after | |
# they are created. | |
s = 'hello' # Make a 5 character string, and assign it to a name | |
multiline = """hello | |
world""" #=> 'hello\n\tworld' | |
len(s) #=> 5 | |
s[0] #=> 'h' | |
s[4] #=> 'o' | |
s[-1] #=> 'o' last item from the end | |
s[-2] #=> 'l' | |
s[1:3] #=> 'el' slice of `s` offsets from 1 through 2 (not 3) | |
s[1:] #=> 'ello' everything past the first character | |
s[0:3] == s[:3] #=> True | |
s + ' world' #=> 'hello world' concatenation | |
s.__add__('world') #=> 'hello world' concatenation | |
s * 3 #=> 'hellohellohello' repetition | |
# String methods | |
s.find('ll') #=> 2 offset if a substring in `s` | |
s.replace('ll', 'LL') #=> 'heLLo' replace occurrences of a string in `s` with another | |
s.upper() #=> 'HELLO' upper-case conversion | |
s.lower() #=> 'hello' lower-case conversion | |
line = 'hello,world,!' | |
line.split(',') #=> ['hello', 'world', '!'] split on a delimiter `,` into a list of substrings | |
'{0} {1}'.format('hello', 'world') #=> 'hello world' | |
'{} {}'.format('hello', 'world') #=> 'hello world' | |
# Pattern matching | |
import re | |
match = re.match('hello[ \t]*(.*)world', 'hello python world') | |
match.groups() #=> ('python ',) | |
match.group(1) #=> 'python ' | |
match = re.match('[/:](.*)[/:](.*)[/:](.*)', '/usr/home:babygau') | |
match.groups() #=> ('usr', 'home', 'babygau') | |
re.split('[/:]', '/usr/home/babygau') #=> ['', 'usr', 'home', 'babygau'] | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: Tuples are immutable like Strings | |
# Tuples like a list, but support fewer operation. They are | |
# not generally used as often as list in practice, but their | |
# immutability is the key point. If you pass a collection of | |
# objects around your program as a list, it can be changed | |
# anywhere; if you use tuple, it cannot. | |
t = (1, 2, 3, 4) | |
len(t) #=> 4 | |
t + (5, 6) #=> (1, 2, 3, 4, 5, 6) concatenation | |
t[1:3] #=> (2, 3) | |
t.index(4) #=> 3 | |
t.count(4) #=> 1 | |
t[0] = 7 #=> Error because `tuples` are immutable | |
t = 'Spam', 1, 2.3, [4, 5, 6] # `Tuples` support mixed types and nesting | |
# Parenthese is OPTIONAL | |
tuple('Spam') #=> ('S', 'p', 'a', 'm') | |
tuple([1, 2, 3]) #=> (1, 2, 3) | |
tuple({'a': 1, 'b': 2}) #=> ('a', 'b') | |
# Use `namedtuple` | |
# Reference: http://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python | |
from collections import namedtuple | |
Point = namedtuple('Point', 'x y') | |
pt1 = Point(1.0, 5.0) #=> Point(x=1.0, y=5.0) | |
pt2 = Point(2.5, 1.5) #=> Point(x=2.5, y=1.5) | |
pt1.x == pt1[0] #=> True | |
pt2.y == pt2[1] #=> True | |
from math import sqrt | |
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Super-class | |
class Person: | |
def __init__(self, name, job=None, pay=0): | |
self.name = name | |
self.job = job | |
self.pay = pay | |
def last_name(self): | |
return self.name.split()[-1] | |
def give_raise(self, percent): | |
self.pay = int(self.pay * (1 + percent)) | |
def __repr__(self): | |
return '[Person: %s, %s]' % (self.name, self.pay) | |
# Sub-class | |
class Manager(Person): | |
def __init__(self, name, pay): | |
Person.__init__(self, name, 'mgr', pay) | |
def give_raise(self, percent, bonus=.10) # Override superclass method | |
Person.give_raise(self, percent + bonus) | |
# Embedding-based class (composite class) | |
# make use of `__getattr__` operator overloading | |
# However, note that: generic attribute managers such as | |
# `__getattr__` or `__getattribute__` never implicitly invoke | |
# built-in operator overlading methods such as `__repr__`, __str__` | |
# We have to define them explicitly if we want to use | |
class Manager | |
def __init__(self, name, pay): | |
self.person = Person(name, 'mgr', pay) # Embed a `Person` instance | |
def give_raise(self, percent, bonus=0.10): | |
self.person.give_raise(percent + bonus) # Intercept and delegate | |
def __getattr__(self, attr): | |
return getattr(self.person, attr) # Delegate all undefined attrs to `self.person` | |
# In other words, extending all `Person` attrs | |
def __repr__(self): # Must overload again in 3.X | |
return str(self.person) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment