Skip to content

Commit

Permalink
add session 28: modern python
Browse files Browse the repository at this point in the history
  • Loading branch information
midick committed Jan 24, 2020
1 parent d446e04 commit a2c3a25
Show file tree
Hide file tree
Showing 20 changed files with 634 additions and 0 deletions.
11 changes: 11 additions & 0 deletions session28_ModernPython/Chainmap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from collections import ChainMap

d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
d3 = {**d1, **d2}
chain = ChainMap(d1, d2)

print(chain)

for key, value in chain.items():
print(key, value)
14 changes: 14 additions & 0 deletions session28_ModernPython/Combinatorics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import itertools

abc = 'ABC'
print('permutations:')
for p in itertools.permutations(abc):
print(p)

print('with no repetition')
for c in itertools.combinations(abc, 2):
print(c)

print('with replacement:')
for c in itertools.combinations_with_replacement(abc, 2):
print(c)
84 changes: 84 additions & 0 deletions session28_ModernPython/ContextManager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from contextlib import contextmanager
import sys


# Where does a context manager make sense?

# Setup/Preperation:
f = open('./text.txt', 'w')

# Do the stuff you want to do:
f.write('text')

# Clean up so everything is nice and tidy:
f.close()


# Context Manager as Class
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)

def __enter__(self):
return self.file_obj

def __exit__(self, type, value, traceback):
print("Exception has been handled")
self.file_obj.close()
return True


@contextmanager
def ContextFile(filename, method):
try:
file_obj = open(filename, method)
yield file_obj
except Exception:
print("Exception has been handled")
finally:
file_obj.close()
return True


# Context Manager as Generator
@contextmanager
def open_file(name, method):
f = open(name, method)
yield f
f.close()


@contextmanager
def redirect_stdout(fileobj):
oldstdout = sys.stdout
sys.stdout = fileobj
try:
yield fileobj
finally:
sys.stout = oldstdout


with ContextFile('demo.txt', 'w') as opened_file:
opened_file.undefined_function()

print('This goes to the console')
with open('./ContextManager.py', 'a') as f:
with redirect_stdout(f):
print('# This goes down there:')


# Really nice stuff:
@contextmanager
def ignored(*exceptions):
try:
yield
except exceptions:
pass


@ignored(ZeroDivisionError)
def do_something_dangerous():
1 / 0

do_something_dangerous()
# This goes down there:
18 changes: 18 additions & 0 deletions session28_ModernPython/CustomSortOrder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
colors = ['mauve', 'taupe', 'teal', 'razzmatazz', 'gamboge']

# old way: Comparison Functions


def compare_length(c1, c2):
if len(c1) < len(c2):
return -1
if len(c1) > len(c2):
return 1
return 0

# doesn't work anymore in Python3
# print(sorted(colors, cmp=compare_length))


# new way: Key functions
print(sorted(colors, key=len))
24 changes: 24 additions & 0 deletions session28_ModernPython/Dataclass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from dataclasses import dataclass


@dataclass(
init=True, # generated __init__()
repr=True, # generates __reps__()
eq=True, # generates __eq__(), this compares the class as a tuple of
# fields but also checks if "other" is of the same type
order=False, # generates __lt__(), __le__(), __gt__(), and __ge__()
unsafe_hash=False, # not unsafe, just not very friendly.
# If False, __hash__() is set according
# to eq and frozen:
# eq & frozen: __hash__() will be generated
# eq & !frozen: __hash__() = None
# !eq: __hash__() is left untouched and only inherited
# unsafe_hash=True should be used if the class is
# logically immutable but can nonetheless be mutated
frozen=False # Assigning to fields raises an exception
)
class Point:
x: int
y: int


47 changes: 47 additions & 0 deletions session28_ModernPython/DataclassCards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from dataclasses import dataclass, field
from typing import List
from random import sample


@dataclass(order=True)
class PlayingCard:
rank: str
suit: str

def __post_init__(self):
self.sort_index = (RANKS.index(self.rank) * len(SUITS)
+ SUITS.index(self.suit))

def __str__(self):
return f'{self.suit}{self.rank}'


RANKS = '2 3 4 5 6 7 8 9 10 J Q K A'.split()
SUITS = '♣ ♢ ♡ ♠'.split()


def make_french_deck():
return [PlayingCard(r, s) for s in SUITS for r in RANKS]


@dataclass
class Deck:
cards: List[PlayingCard] = field(default_factory=make_french_deck)

def __repr__(self):
cards = ', '.join(f'{c!s}' for c in self.cards)
return f'{self.__class__.__name__}({cards})'

def shuffle(self):
self.cards = sample(self.cards, k=len(self.cards))

def sort(self):
self.cards = sorted(self.cards)


d = Deck()
print(d)
d.sort()
print(d)
d.shuffle()
print(d)
138 changes: 138 additions & 0 deletions session28_ModernPython/DataclassEmployeeExample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from dataclasses import dataclass, field, fields
from datetime import datetime
from pprint import pprint


@dataclass(order=True, unsafe_hash=True)
class Employee:
emp_id: int
name: str
gender: str
salary: int = field(hash=False, repr=False, metadata={"units": "bitcoin"})
age: int = field(hash=False)
viewed_by: list = field(default_factory=list, compare=False, repr=False)

def access(self, viewer_id):
self.viewed_by.append((viewer_id, datetime.now()))


e1 = Employee(emp_id='3536465054',
name='Rachel Hettinger',
gender='female',
salary=22,
age=0x30,
)

e2 = Employee(emp_id='4054646353',
name='Martin Murchison',
gender='male',
salary=20,
age=0x30,
)

e1.access('Roger Wastun')
e1.access('Shelly Summers')
pprint(e1.viewed_by)
pprint(sorted([e1, e2]))
assignments = {e1: 'gather requirements', e2: 'write tests'}
pprint(assignments)
fields(e1)[3]
"""
"""


# Generated Code:
"""
from dataclasses import _HAS_DEFAULT_FACTORY
def __init__(
self,
emp_id: int,
name: str,
gender: str,
salary: int,
age: int,
viewed_by: list = _HAS_DEFAULT_FACTORY,
) -> None:
self.emp_id = emp_id
self.name = name
self.gender = gender
self.salary = salary
self.age = age
self.viewed_by = list() if viewed_by is _HAS_DEFAULT_FACTORY else viewed_by
def __repr__(self):
return (
self.__class__.__qualname__
+ f"(emp_id={self.emp_id!r}, name={self.name!r}, gender={self.gender!r}, age={self.age!r})"
)
def __eq__(self, other):
if other.__class__ is self.__class__:
return (self.emp_id, self.name, self.gender, self.salary, self.age) == (
other.emp_id,
other.name,
other.gender,
other.salary,
other.age,
)
return NotImplemented
def __lt__(self, other):
if other.__class__ is self.__class__:
return (self.emp_id, self.name, self.gender, self.salary, self.age) < (
other.emp_id,
other.name,
other.gender,
other.salary,
other.age,
)
return NotImplemented
def __le__(self, other):
if other.__class__ is self.__class__:
return (self.emp_id, self.name, self.gender, self.salary, self.age) <= (
other.emp_id,
other.name,
other.gender,
other.salary,
other.age,
)
return NotImplemented
def __gt__(self, other):
if other.__class__ is self.__class__:
return (self.emp_id, self.name, self.gender, self.salary, self.age) > (
other.emp_id,
other.name,
other.gender,
other.salary,
other.age,
)
return NotImplemented
def __ge__(self, other):
if other.__class__ is self.__class__:
return (self.emp_id, self.name, self.gender, self.salary, self.age) >= (
other.emp_id,
other.name,
other.gender,
other.salary,
other.age,
)
return NotImplemented
def __hash__(self):
return hash((self.emp_id, self.name, self.gender))
"""
19 changes: 19 additions & 0 deletions session28_ModernPython/Decorator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import functools


def do_twice(func):
@functools.wraps(func)
def wrapper_do_twice(*args, **kwargs):
print('here I could do something beforehand')
func(*args, **kwargs)
func(*args, **kwargs)
print('here I could do something beforehand')
return wrapper_do_twice


@do_twice
def print_hello(name=''):
print(f"hello {name}")


print(print_hello.__name__)
Loading

0 comments on commit a2c3a25

Please sign in to comment.