Source: Enriching Your Python Classes With Dunder (Magic, Special) Methods
__len__
for length__str__
for printing (human readable)__getitem__
for list slicing__init__
to construct an object__repr__
string representationclass Account:
# ... (see above)
def __repr__(self):
return 'Account({!r}, {!r})'.format(self.owner, self.amount)
def __str__(self):
return 'Account of {} with starting amount: {}'.format(
self.owner, self.amount)
>>> str(acc)
'Account of bob with starting amount: 10'
>>> print(acc)
"Account of bob with starting amount: 10"
>>> repr(acc)
"Account('bob', 10)"
class Account:
# _transations is a list of numbers
def __len__(self):
return len(self._transactions)
def __getitem__(self, position):
return self._transactions[position]
def __reversed__(self):
return self[::-1]
Import total_ordering to avoid implementing EVERY comparison method.
from functools import total_ordering
@total_ordering
class Account:
# ... (see above)
def __eq__(self, other): #equal
return self.balance == other.balance
def __lt__(self, other): # less than
return self.balance < other.balance
To merge to accounts, implement add:
owner = '{}&{}'.format(self.owner, other.owner)
start_amount = self.amount + other.amount
acc = Account(owner, start_amount)
for t in list(self) + list(other):
acc.add_transaction(t)
return acc
Not a standard practice, better to have a function on the class do this.
class Account:
# ... (see above)
def __call__(self):
print('Start amount: {}'.format(self.amount))
print('Transactions: ')
for transaction in self:
print(transaction)
print('\nBalance: {}'.format(self.balance))
>>> acc()
Start amount: 10
Transactions:
20
-10
50
-20
30
Balance: 80
With
A context manager is a simple “protocol” (or interface) that your object needs to follow so it can be used with the with statement. Basically all you need to do is add
__enter__
and__exit__
methods to an object if you want it to function as a context manager.
If balance goes negative, rollback to previous state:
# ... (see above)
def __enter__(self):
print('ENTER WITH: Making backup of transactions for rollback')
self._copy_transactions = list(self._transactions)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('EXIT WITH:', end=' ')
if exc_type:
self._transactions = self._copy_transactions
print('Rolling back to previous transactions')
print('Transaction resulted in {} ({})'.format(
exc_type.__name__, exc_val))
else:
print('Transaction OK')
Helper method to validate transaction
def validate_transaction(acc, amount_to_add):
with acc as a:
print('Adding {} to account'.format(amount_to_add))
a.add_transaction(amount_to_add)
print('New balance would be: {}'.format(a.balance))
if a.balance < 0:
raise ValueError('sorry cannot go in debt!')
Probability
- Theory: likelihood of an event happeningSample space
- the set of all possible events (heads / tails)Statistics
- Tools: calculate probability from real world observationsHigher number of trials gets closer to replicating probability
import random
def coin_trial():
heads = 0
for i in range(100):
if random.random() <= 0.5:
heads +=1
return heads
def simulate(n):
trials = []
for i in range(n):
trials.append(coin_trial())
return(sum(trials)/n)
simulate(10)
>>> 5.4
simulate(100)
>>> 4.83
simulate(1000)
>>> 5.055
simulate(1000000)
>>> 4.999781