"""Python Cookbook

Chapter 7, Examples from the text.

•	Using a class to encapsulate data and processing
•	Essential Type Hints for class definitions
•	Designing classes with lots of processing
•	Using typing.NamedTuple for immutable objects
•	Using dataclasses for mutable objects
•	Using frozen dataclasses for immtable objects
•	Optimizing small objects with __slots__
•	Using more sophisticated collections
•	Extending a built-in collection – a list that does statistics
•	Using properties for lazy attributes
•	Creating contexts and context managers
•	Managing multiple contexts with multiple resources

"""

# Optimizing small objects with __slots__

>>> from Chapter_07.ch07_r07 import Card, Hand
>>> h1 = Hand(2)
>>> h1.deal(Card(rank=4, suit='♣'))
>>> h1.deal(Card(rank=8, suit='♡'))
>>> h1
Hand(bet=2, hand=[Card(rank=4, suit='♣'), Card(rank=8, suit='♡')])

>>> h1.bet *= 2
>>> h1
Hand(bet=4, hand=[Card(rank=4, suit='♣'), Card(rank=8, suit='♡')])

>>> h1.some_other_attribute = True
Traceback (most recent call last):
  File "/Users/slott/miniconda3/envs/cookbook/lib/python3.8/doctest.py", line 1328, in __run
    compileflags, 1), test.globs)
  File "<doctest examples.txt[45]>", line 1, in <module>
    h1.some_other_attribute = True
AttributeError: 'Hand' object has no attribute 'some_other_attribute'

# Extending a collection – a list that does statistics

>>> from Chapter_07.ch07_r09 import StatsList
>>> subset1 = StatsList([10, 8, 13, 9, 11])
>>> data = StatsList([14, 6, 4, 12, 7, 5])
>>> data.extend(subset1)

>>> data
[14, 6, 4, 12, 7, 5, 10, 8, 13, 9, 11]

>>> data.mean()
9.0
>>> data.variance()
11.0

>>> data.sort()
>>> data[len(data)//2]
9

>>> from Chapter_15.collector import arrival1, expected, coupon_collector, samples
>>> from collections import Counter
>>> def raw_data(n=8, limit=1000, arrival_function=arrival1):
...    expected_time = float(expected(n))
...    data = samples(limit, arrival_function(n))
...    wait_times = Counter(coupon_collector(n, data))
...    return wait_times


>>> import random
>>> from Chapter_07.ch07_r03 import CounterStatistics
>>> random.seed(1)
>>> data = raw_data()
>>> stats = CounterStatistics(data)
>>> print(f"Mean: {stats.mean:.2f}")
Mean: 20.81
>>> print(f"Standard Deviation: {stats.stddev:.3f}")
Standard Deviation: 7.025

# Optimizing small objects with __slots__

>>> from Chapter_07.ch07_r07 import Card, Hand
>>> h1 = Hand(2)
>>> h1.deal(Card(rank=4, suit='♣ '))
>>> h1.deal(Card(rank=8, suit='♡ '))
>>> h1
Hand(bet=2, hand=[Card(rank=4, suit='♣ '), Card(rank=8, suit='♡ ')])

>>> h1.bet *= 2
>>> h1
Hand(bet=4, hand=[Card(rank=4, suit='♣ '), Card(rank=8, suit='♡ ')])

>>> h1.some_other_attribute = True
Traceback (most recent call last):
  File "/Users/slott/miniconda3/envs/cookbook/lib/python3.8/doctest.py", line 1336, in __run
    exec(compile(example.source, filename, "single",
  File "<doctest examples.txt[34]>", line 1, in <module>
    h1.some_other_attribute = True
AttributeError: 'Hand' object has no attribute 'some_other_attribute'

# Extending a built-in collection – a list that does statistics

>>> from Chapter_07.ch07_r09 import StatsList
>>> subset1 = StatsList([10, 8, 13, 9, 11])
>>> data = StatsList([14, 6, 4, 12, 7, 5])
>>> data.extend(subset1)

>>> data
[14, 6, 4, 12, 7, 5, 10, 8, 13, 9, 11]

>>> data.mean()
9.0
>>> data.variance()
11.0

