ch06
This commit is contained in:
parent
ef37ce0c4e
commit
b6eb3ef8a7
37
ch06/decorators/decorators.factory.py
Normal file
37
ch06/decorators/decorators.factory.py
Normal file
@ -0,0 +1,37 @@
|
||||
# decorators/decorators.factory.py
|
||||
from functools import wraps
|
||||
|
||||
def max_result(threshold):
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
result = func(*args, **kwargs)
|
||||
if result > threshold:
|
||||
print(
|
||||
f'Result is too big ({result}). '
|
||||
f'Max allowed is {threshold}.'
|
||||
)
|
||||
return result
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@max_result(75)
|
||||
def cube(n):
|
||||
return n ** 3
|
||||
|
||||
@max_result(100)
|
||||
def square(n):
|
||||
return n ** 2
|
||||
|
||||
@max_result(1000)
|
||||
def multiply(a, b):
|
||||
return a * b
|
||||
|
||||
print(cube(5))
|
||||
|
||||
|
||||
"""
|
||||
$ python decorators.factory.py
|
||||
Result is too big (125). Max allowed is 75.
|
||||
125
|
||||
"""
|
||||
40
ch06/decorators/syntax.py
Normal file
40
ch06/decorators/syntax.py
Normal file
@ -0,0 +1,40 @@
|
||||
# decorators/syntax.py
|
||||
# This is not a valid Python module - Don't run it.
|
||||
|
||||
# ONE DECORATOR
|
||||
def func(arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
func = decorator(func)
|
||||
|
||||
# is equivalent to the following:
|
||||
|
||||
@decorator
|
||||
def func(arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
|
||||
# TWO DECORATORS
|
||||
def func(arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
func = deco1(deco2(func))
|
||||
|
||||
# is equivalent to the following:
|
||||
|
||||
@deco1
|
||||
@deco2
|
||||
def func(arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
# DECORATOR WITH ARGUMENTS
|
||||
def func(arg1, arg2, ...):
|
||||
pass
|
||||
|
||||
func = decoarg(arg_a, arg_b)(func)
|
||||
|
||||
# is equivalent to the following:
|
||||
|
||||
@decoarg(arg_a, arg_b)
|
||||
def func(arg1, arg2, ...):
|
||||
pass
|
||||
14
ch06/decorators/time.measure.arguments.py
Normal file
14
ch06/decorators/time.measure.arguments.py
Normal file
@ -0,0 +1,14 @@
|
||||
# decorators/time.measure.arguments.py
|
||||
from time import sleep, time
|
||||
|
||||
|
||||
def f(sleep_time=0.1):
|
||||
sleep(sleep_time)
|
||||
|
||||
def measure(func, *args, **kwargs):
|
||||
t = time()
|
||||
func(*args, **kwargs)
|
||||
print(func.__name__, 'took:', time() - t)
|
||||
|
||||
measure(f, sleep_time=0.3) # f took: 0.30056095123291016
|
||||
measure(f, 0.2) # f took: 0.2033553123474121
|
||||
18
ch06/decorators/time.measure.deco1.py
Normal file
18
ch06/decorators/time.measure.deco1.py
Normal file
@ -0,0 +1,18 @@
|
||||
# decorators/time.measure.deco1.py
|
||||
from time import sleep, time
|
||||
|
||||
def f(sleep_time=0.1):
|
||||
sleep(sleep_time)
|
||||
|
||||
def measure(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
t = time()
|
||||
func(*args, **kwargs)
|
||||
print(func.__name__, 'took:', time() - t)
|
||||
return wrapper
|
||||
|
||||
f = measure(f) # decoration point
|
||||
|
||||
f(0.2) # f took: 0.20372915267944336
|
||||
f(sleep_time=0.3) # f took: 0.30455899238586426
|
||||
print(f.__name__) # wrapper <- ouch!
|
||||
22
ch06/decorators/time.measure.deco2.py
Normal file
22
ch06/decorators/time.measure.deco2.py
Normal file
@ -0,0 +1,22 @@
|
||||
# decorators/time.measure.deco2.py
|
||||
from time import sleep, time
|
||||
from functools import wraps
|
||||
|
||||
|
||||
def measure(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
t = time()
|
||||
func(*args, **kwargs)
|
||||
print(func.__name__, 'took:', time() - t)
|
||||
return wrapper
|
||||
|
||||
|
||||
@measure
|
||||
def f(sleep_time=0.1):
|
||||
"""I'm a cat. I love to sleep! """
|
||||
sleep(sleep_time)
|
||||
|
||||
|
||||
f(sleep_time=0.3) # f took: 0.3010902404785156
|
||||
print(f.__name__, ':', f.__doc__) # f : I'm a cat. I love to sleep!
|
||||
17
ch06/decorators/time.measure.dry.py
Normal file
17
ch06/decorators/time.measure.dry.py
Normal file
@ -0,0 +1,17 @@
|
||||
# decorators/time.measure.dry.py
|
||||
from time import sleep, time
|
||||
|
||||
|
||||
def f():
|
||||
sleep(.3)
|
||||
|
||||
def g():
|
||||
sleep(.5)
|
||||
|
||||
def measure(func):
|
||||
t = time()
|
||||
func()
|
||||
print(func.__name__, 'took:', time() - t)
|
||||
|
||||
measure(f) # f took: 0.30434322357177734
|
||||
measure(g) # g took: 0.5048270225524902
|
||||
18
ch06/decorators/time.measure.start.py
Normal file
18
ch06/decorators/time.measure.start.py
Normal file
@ -0,0 +1,18 @@
|
||||
# decorators/time.measure.start.py
|
||||
from time import sleep, time
|
||||
|
||||
|
||||
def f():
|
||||
sleep(.3)
|
||||
|
||||
def g():
|
||||
sleep(.5)
|
||||
|
||||
|
||||
t = time()
|
||||
f()
|
||||
print('f took:', time() - t) # f took: 0.3001396656036377
|
||||
|
||||
t = time()
|
||||
g()
|
||||
print('g took:', time() - t) # g took: 0.5039339065551758
|
||||
42
ch06/decorators/two.decorators.py
Normal file
42
ch06/decorators/two.decorators.py
Normal file
@ -0,0 +1,42 @@
|
||||
# decorators/two.decorators.py
|
||||
from time import time
|
||||
from functools import wraps
|
||||
|
||||
def measure(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
t = time()
|
||||
result = func(*args, **kwargs)
|
||||
print(func.__name__, 'took:', time() - t)
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
def max_result(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
result = func(*args, **kwargs)
|
||||
if result > 100:
|
||||
print(
|
||||
f'Result is too big ({result}). '
|
||||
'Max allowed is 100.'
|
||||
)
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
@measure
|
||||
@max_result
|
||||
def cube(n):
|
||||
return n ** 3
|
||||
|
||||
print(cube(2))
|
||||
print(cube(5))
|
||||
|
||||
|
||||
"""
|
||||
$ python two.decorators.py
|
||||
cube took: 3.0994415283203125e-06
|
||||
8
|
||||
Result is too big (125). Max allowed is 100.
|
||||
cube took: 5.9604644775390625e-06
|
||||
125
|
||||
"""
|
||||
53
ch06/iterators/iterator.py
Normal file
53
ch06/iterators/iterator.py
Normal file
@ -0,0 +1,53 @@
|
||||
# iterators/iterator.py
|
||||
class OddEven:
|
||||
|
||||
def __init__(self, data):
|
||||
self._data = data
|
||||
self.indexes = (list(range(0, len(data), 2)) +
|
||||
list(range(1, len(data), 2)))
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self.indexes:
|
||||
return self._data[self.indexes.pop(0)]
|
||||
raise StopIteration
|
||||
|
||||
oddeven = OddEven('ThIsIsCoOl!')
|
||||
print(''.join(c for c in oddeven)) # TIICO!hssol
|
||||
|
||||
oddeven = OddEven('CiAo') # or manually...
|
||||
it = iter(oddeven) # this calls oddeven.__iter__ internally
|
||||
print(next(it)) # C
|
||||
print(next(it)) # A
|
||||
print(next(it)) # i
|
||||
print(next(it)) # o
|
||||
|
||||
|
||||
# make sure it works correctly with edge cases
|
||||
oddeven = OddEven('')
|
||||
print(' '.join(c for c in oddeven))
|
||||
|
||||
oddeven = OddEven('A')
|
||||
print(' '.join(c for c in oddeven))
|
||||
|
||||
oddeven = OddEven('Ab')
|
||||
print(' '.join(c for c in oddeven))
|
||||
|
||||
oddeven = OddEven('AbC')
|
||||
print(' '.join(c for c in oddeven))
|
||||
|
||||
|
||||
"""
|
||||
$ python iterators/iterator.py
|
||||
TIICO!hssol
|
||||
C
|
||||
A
|
||||
i
|
||||
o
|
||||
|
||||
A
|
||||
A b
|
||||
A C b
|
||||
"""
|
||||
57
ch06/oop/cached.property.py
Normal file
57
ch06/oop/cached.property.py
Normal file
@ -0,0 +1,57 @@
|
||||
# oop/cached.property.py
|
||||
from functools import cached_property
|
||||
|
||||
|
||||
class Client:
|
||||
def __init__(self):
|
||||
print("Setting up the client...")
|
||||
|
||||
def query(self, **kwargs):
|
||||
print(f"Performing a query: {kwargs}")
|
||||
|
||||
|
||||
class Manager:
|
||||
@property
|
||||
def client(self):
|
||||
return Client()
|
||||
|
||||
def perform_query(self, **kwargs):
|
||||
return self.client.query(**kwargs)
|
||||
|
||||
|
||||
class ManualCacheManager:
|
||||
@property
|
||||
def client(self):
|
||||
if not hasattr(self, '_client'):
|
||||
self._client = Client()
|
||||
return self._client
|
||||
|
||||
def perform_query(self, **kwargs):
|
||||
return self.client.query(**kwargs)
|
||||
|
||||
|
||||
class CachedPropertyManager:
|
||||
@cached_property
|
||||
def client(self):
|
||||
return Client()
|
||||
|
||||
def perform_query(self, **kwargs):
|
||||
return self.client.query(**kwargs)
|
||||
|
||||
|
||||
manager = CachedPropertyManager()
|
||||
manager.perform_query(object_id=42)
|
||||
manager.perform_query(name_ilike='%Python%')
|
||||
|
||||
del manager.client # This causes a new Client on next call
|
||||
manager.perform_query(age_gte=18)
|
||||
|
||||
|
||||
"""
|
||||
$ python cached.property.py
|
||||
Setting up the client... # New Client
|
||||
Performing a query: {'object_id': 42} # first query
|
||||
Performing a query: {'name_ilike': '%Python%'} # second query
|
||||
Setting up the client... # Another Client
|
||||
Performing a query: {'age_gte': 18} # Third query
|
||||
"""
|
||||
36
ch06/oop/class.attribute.shadowing.py
Normal file
36
ch06/oop/class.attribute.shadowing.py
Normal file
@ -0,0 +1,36 @@
|
||||
# oop/class.attribute.shadowing.py
|
||||
class Point:
|
||||
x = 10
|
||||
y = 7
|
||||
|
||||
p = Point()
|
||||
print(p.x) # 10 (from class attribute)
|
||||
print(p.y) # 7 (from class attribute)
|
||||
|
||||
p.x = 12 # p gets its own `x` attribute
|
||||
print(p.x) # 12 (now found on the instance)
|
||||
print(Point.x) # 10 (class attribute still the same)
|
||||
|
||||
del p.x # we delete instance attribute
|
||||
print(p.x) # 10 (now search has to go again to find class attr)
|
||||
|
||||
p.z = 3 # let's make it a 3D point
|
||||
print(p.z) # 3
|
||||
|
||||
print(Point.z)
|
||||
# AttributeError: type object 'Point' has no attribute 'z'
|
||||
|
||||
|
||||
"""
|
||||
$ python class.attribute.shadowing.py
|
||||
10
|
||||
7
|
||||
12
|
||||
10
|
||||
10
|
||||
3
|
||||
Traceback (most recent call last):
|
||||
File "/Users/fab/srv/lpp3e/v3/ch06/oop/class.attribute.shadowing.py", line 20, in <module>
|
||||
print(Point.z)
|
||||
AttributeError: type object 'Point' has no attribute 'z'
|
||||
"""
|
||||
23
ch06/oop/class.init.py
Normal file
23
ch06/oop/class.init.py
Normal file
@ -0,0 +1,23 @@
|
||||
# oop/class.init.py
|
||||
class Rectangle:
|
||||
def __init__(self, side_a, side_b):
|
||||
self.side_a = side_a
|
||||
self.side_b = side_b
|
||||
|
||||
def area(self):
|
||||
return self.side_a * self.side_b
|
||||
|
||||
r1 = Rectangle(10, 4)
|
||||
print(r1.side_a, r1.side_b) # 10 4
|
||||
print(r1.area()) # 40
|
||||
|
||||
r2 = Rectangle(7, 3)
|
||||
print(r2.area()) # 21
|
||||
|
||||
|
||||
"""
|
||||
$ python class.init.py
|
||||
10 4
|
||||
40
|
||||
21
|
||||
"""
|
||||
52
ch06/oop/class.issubclass.isinstance.py
Normal file
52
ch06/oop/class.issubclass.isinstance.py
Normal file
@ -0,0 +1,52 @@
|
||||
# oop/class.issubclass.isinstance.py
|
||||
from class_inheritance import Car, RaceCar, F1Car
|
||||
|
||||
|
||||
car = Car()
|
||||
racecar = RaceCar()
|
||||
f1car = F1Car()
|
||||
cars = [(car, 'car'), (racecar, 'racecar'), (f1car, 'f1car')]
|
||||
car_classes = [Car, RaceCar, F1Car]
|
||||
|
||||
for car, car_name in cars:
|
||||
for class_ in car_classes:
|
||||
belongs = isinstance(car, class_)
|
||||
msg = 'is a' if belongs else 'is not a'
|
||||
print(car_name, msg, class_.__name__)
|
||||
|
||||
""" Prints:
|
||||
Starting engine Engine for car Car... Wroom, wroom!
|
||||
Starting engine V8Engine for car RaceCar... Wroom, wroom!
|
||||
Starting engine ElectricEngine for car CityCar... Wroom, wroom!
|
||||
Starting engine V8Engine for car F1Car... Wroom, wroom!
|
||||
car is a Car
|
||||
car is not a RaceCar
|
||||
car is not a F1Car
|
||||
racecar is a Car
|
||||
racecar is a RaceCar
|
||||
racecar is not a F1Car
|
||||
f1car is a Car
|
||||
f1car is a RaceCar
|
||||
f1car is a F1Car
|
||||
"""
|
||||
|
||||
print('-' * 60)
|
||||
|
||||
for class1 in car_classes:
|
||||
for class2 in car_classes:
|
||||
is_subclass = issubclass(class1, class2)
|
||||
msg = '{0} a subclass of'.format(
|
||||
'is' if is_subclass else 'is not')
|
||||
print(class1.__name__, msg, class2.__name__)
|
||||
|
||||
""" Prints:
|
||||
Car is a subclass of Car
|
||||
Car is not a subclass of RaceCar
|
||||
Car is not a subclass of F1Car
|
||||
RaceCar is a subclass of Car
|
||||
RaceCar is a subclass of RaceCar
|
||||
RaceCar is not a subclass of F1Car
|
||||
F1Car is a subclass of Car
|
||||
F1Car is a subclass of RaceCar
|
||||
F1Car is a subclass of F1Car
|
||||
"""
|
||||
27
ch06/oop/class.methods.factory.py
Normal file
27
ch06/oop/class.methods.factory.py
Normal file
@ -0,0 +1,27 @@
|
||||
# oop/class.methods.factory.py
|
||||
class Point:
|
||||
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
@classmethod
|
||||
def from_tuple(cls, coords): # cls is Point
|
||||
return cls(*coords)
|
||||
|
||||
@classmethod
|
||||
def from_point(cls, point): # cls is Point
|
||||
return cls(point.x, point.y)
|
||||
|
||||
|
||||
p = Point.from_tuple((3, 7))
|
||||
print(p.x, p.y) # 3 7
|
||||
q = Point.from_point(p)
|
||||
print(q.x, q.y) # 3 7
|
||||
|
||||
|
||||
"""
|
||||
$ python class.methods.factory.py
|
||||
3 7
|
||||
3 7
|
||||
"""
|
||||
35
ch06/oop/class.methods.split.py
Normal file
35
ch06/oop/class.methods.split.py
Normal file
@ -0,0 +1,35 @@
|
||||
# oop/class.methods.split.py
|
||||
class StringUtil:
|
||||
|
||||
@classmethod
|
||||
def is_palindrome(cls, s, case_insensitive=True):
|
||||
s = cls._strip_string(s)
|
||||
# For case insensitive comparison, we lower-case s
|
||||
if case_insensitive:
|
||||
s = s.lower()
|
||||
return cls._is_palindrome(s)
|
||||
|
||||
@staticmethod
|
||||
def _strip_string(s):
|
||||
return ''.join(c for c in s if c.isalnum())
|
||||
|
||||
@staticmethod
|
||||
def _is_palindrome(s):
|
||||
for c in range(len(s) // 2):
|
||||
if s[c] != s[-c -1]:
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_unique_words(sentence):
|
||||
return set(sentence.split())
|
||||
|
||||
print(StringUtil.is_palindrome('A nut for a jar of tuna')) # True
|
||||
print(StringUtil.is_palindrome('A nut for a jar of beans')) # False
|
||||
|
||||
|
||||
"""
|
||||
$ python class.methods.split.py
|
||||
True
|
||||
False
|
||||
"""
|
||||
40
ch06/oop/class.namespaces.py
Normal file
40
ch06/oop/class.namespaces.py
Normal file
@ -0,0 +1,40 @@
|
||||
# oop/class.namespaces.py
|
||||
class Person:
|
||||
species = 'Human'
|
||||
|
||||
|
||||
print(Person.species) # Human
|
||||
Person.alive = True # Added dynamically!
|
||||
print(Person.alive) # True
|
||||
|
||||
man = Person()
|
||||
print(man.species) # Human (inherited)
|
||||
print(man.alive) # True (inherited)
|
||||
|
||||
Person.alive = False
|
||||
print(man.alive) # False (inherited)
|
||||
|
||||
man.name = 'Darth'
|
||||
man.surname = 'Vader'
|
||||
print(man.name, man.surname) # Darth Vader
|
||||
|
||||
print(Person.name)
|
||||
# This doesn't work. We try to access an instance attribute
|
||||
# from a class. Doing the opposite works, but this will give
|
||||
# the following error:
|
||||
# AttributeError: type object 'Person' has no attribute 'name'
|
||||
|
||||
|
||||
"""
|
||||
$ python class.namespaces.py
|
||||
Human
|
||||
True
|
||||
Human
|
||||
True
|
||||
False
|
||||
Darth Vader
|
||||
Traceback (most recent call last):
|
||||
File "/Users/fab/srv/lpp3e/v3/ch06/oop/class.namespaces.py", line 21, in <module>
|
||||
print(Person.name)
|
||||
AttributeError: type object 'Person' has no attribute 'name'
|
||||
"""
|
||||
17
ch06/oop/class.price.py
Normal file
17
ch06/oop/class.price.py
Normal file
@ -0,0 +1,17 @@
|
||||
# oop/class.price.py
|
||||
class Price:
|
||||
def final_price(self, vat, discount=0):
|
||||
"""Returns price after applying vat and fixed discount."""
|
||||
return (self.net_price * (100 + vat) / 100) - discount
|
||||
|
||||
p1 = Price()
|
||||
p1.net_price = 100
|
||||
print(Price.final_price(p1, 20, 10)) # 110 (100 * 1.2 - 10)
|
||||
print(p1.final_price(20, 10)) # equivalent
|
||||
|
||||
|
||||
"""
|
||||
$ python class.price.py
|
||||
110.0
|
||||
110.0
|
||||
"""
|
||||
21
ch06/oop/class.self.py
Normal file
21
ch06/oop/class.self.py
Normal file
@ -0,0 +1,21 @@
|
||||
# oop/class.self.py
|
||||
class Square:
|
||||
side = 8
|
||||
def area(self): # self is a reference to an instance
|
||||
return self.side ** 2
|
||||
|
||||
sq = Square()
|
||||
print(sq.area()) # 64 (side is found on the class)
|
||||
print(Square.area(sq)) # 64 (equivalent to sq.area())
|
||||
|
||||
sq.side = 10
|
||||
print(sq.area()) # 100 (side is found on the instance)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
$ python class.self.py
|
||||
64
|
||||
64
|
||||
100
|
||||
"""
|
||||
57
ch06/oop/class_inheritance.py
Normal file
57
ch06/oop/class_inheritance.py
Normal file
@ -0,0 +1,57 @@
|
||||
# oop/class_inheritance.py
|
||||
class Engine:
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
class ElectricEngine(Engine): # Is-A Engine
|
||||
pass
|
||||
|
||||
class V8Engine(Engine): # Is-A Engine
|
||||
pass
|
||||
|
||||
class Car:
|
||||
engine_cls = Engine
|
||||
|
||||
def __init__(self):
|
||||
self.engine = self.engine_cls() # Has-A Engine
|
||||
|
||||
def start(self):
|
||||
print(
|
||||
'Starting engine {0} for car {1}... Wroom, wroom!'
|
||||
.format(
|
||||
self.engine.__class__.__name__,
|
||||
self.__class__.__name__)
|
||||
)
|
||||
self.engine.start()
|
||||
|
||||
def stop(self):
|
||||
self.engine.stop()
|
||||
|
||||
class RaceCar(Car): # Is-A Car
|
||||
engine_cls = V8Engine
|
||||
|
||||
class CityCar(Car): # Is-A Car
|
||||
engine_cls = ElectricEngine
|
||||
|
||||
class F1Car(RaceCar): # Is-A RaceCar and also Is-A Car
|
||||
pass # engine_cls same as parent
|
||||
|
||||
car = Car()
|
||||
racecar = RaceCar()
|
||||
citycar = CityCar()
|
||||
f1car = F1Car()
|
||||
cars = [car, racecar, citycar, f1car]
|
||||
|
||||
for car in cars:
|
||||
car.start()
|
||||
|
||||
"""
|
||||
$ python class_inheritance.py
|
||||
Starting engine Engine for car Car... Wroom, wroom!
|
||||
Starting engine V8Engine for car RaceCar... Wroom, wroom!
|
||||
Starting engine ElectricEngine for car CityCar... Wroom, wroom!
|
||||
Starting engine V8Engine for car F1Car... Wroom, wroom!
|
||||
"""
|
||||
25
ch06/oop/dataclass.py
Normal file
25
ch06/oop/dataclass.py
Normal file
@ -0,0 +1,25 @@
|
||||
# oop/dataclass.py
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Body:
|
||||
'''Class to represent a physical body.'''
|
||||
name: str
|
||||
mass: float = 0. # Kg
|
||||
speed: float = 1. # m/s
|
||||
|
||||
def kinetic_energy(self) -> float:
|
||||
return (self.mass * self.speed ** 2) / 2
|
||||
|
||||
|
||||
body = Body('Ball', 19, 3.1415)
|
||||
print(body.kinetic_energy()) # 93.755711375 Joule
|
||||
print(body) # Body(name='Ball', mass=19, speed=3.1415)
|
||||
|
||||
|
||||
"""
|
||||
$ python dataclass.py
|
||||
93.755711375
|
||||
Body(name='Ball', mass=19, speed=3.1415)
|
||||
"""
|
||||
31
ch06/oop/mro.py
Normal file
31
ch06/oop/mro.py
Normal file
@ -0,0 +1,31 @@
|
||||
# oop/mro.py
|
||||
class A:
|
||||
label = 'a'
|
||||
|
||||
class B(A):
|
||||
pass # was: label = 'b'
|
||||
|
||||
class C(A):
|
||||
label = 'c'
|
||||
|
||||
class D(B, C):
|
||||
pass
|
||||
|
||||
|
||||
d = D()
|
||||
print(d.label) # 'c'
|
||||
print(d.__class__.mro()) # notice another way to get the MRO
|
||||
# prints:
|
||||
# [<class '__main__.D'>, <class '__main__.B'>,
|
||||
# <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
|
||||
|
||||
|
||||
"""
|
||||
$ python oop/mro.py
|
||||
c
|
||||
[
|
||||
<class '__main__.D'>, <class '__main__.B'>,
|
||||
<class '__main__.C'>, <class '__main__.A'>,
|
||||
<class 'object'>
|
||||
]
|
||||
"""
|
||||
30
ch06/oop/mro.simple.py
Normal file
30
ch06/oop/mro.simple.py
Normal file
@ -0,0 +1,30 @@
|
||||
# oop/mro.simple.py
|
||||
class A:
|
||||
label = 'a'
|
||||
|
||||
class B(A):
|
||||
label = 'b'
|
||||
|
||||
class C(A):
|
||||
label = 'c'
|
||||
|
||||
class D(B, C):
|
||||
pass
|
||||
|
||||
d = D()
|
||||
print(d.label) # Hypothetically this could be either 'b' or 'c'
|
||||
print(d.__class__.mro()) # notice another way to get the MRO
|
||||
# prints:
|
||||
# [<class '__main__.D'>, <class '__main__.B'>,
|
||||
# <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
|
||||
|
||||
|
||||
"""
|
||||
$ python mro.simple.py
|
||||
b
|
||||
[
|
||||
<class '__main__.D'>, <class '__main__.B'>,
|
||||
<class '__main__.C'>, <class '__main__.A'>,
|
||||
<class 'object'>
|
||||
]
|
||||
"""
|
||||
74
ch06/oop/multiple.inheritance.py
Normal file
74
ch06/oop/multiple.inheritance.py
Normal file
@ -0,0 +1,74 @@
|
||||
# oop/multiple.inheritance.py
|
||||
class Shape:
|
||||
geometric_type = 'Generic Shape'
|
||||
|
||||
def area(self): # This acts as placeholder for the interface
|
||||
raise NotImplementedError
|
||||
|
||||
def get_geometric_type(self):
|
||||
return self.geometric_type
|
||||
|
||||
|
||||
class Plotter:
|
||||
|
||||
def plot(self, ratio, topleft):
|
||||
# Imagine some nice plotting logic here...
|
||||
print('Plotting at {}, ratio {}.'.format(
|
||||
topleft, ratio))
|
||||
|
||||
|
||||
class Polygon(Shape, Plotter): # base class for polygons
|
||||
geometric_type = 'Polygon'
|
||||
|
||||
class RegularPolygon(Polygon): # Is-A Polygon
|
||||
geometric_type = 'Regular Polygon'
|
||||
|
||||
def __init__(self, side):
|
||||
self.side = side
|
||||
|
||||
|
||||
class RegularHexagon(RegularPolygon): # Is-A RegularPolygon
|
||||
geometric_type = 'RegularHexagon'
|
||||
|
||||
def area(self):
|
||||
return 1.5 * (3 ** .5 * self.side ** 2)
|
||||
|
||||
|
||||
class Square(RegularPolygon): # Is-A RegularPolygon
|
||||
geometric_type = 'Square'
|
||||
|
||||
def area(self):
|
||||
return self.side * self.side
|
||||
|
||||
|
||||
hexagon = RegularHexagon(10)
|
||||
print(hexagon.area()) # 259.8076211353316
|
||||
print(hexagon.get_geometric_type()) # RegularHexagon
|
||||
hexagon.plot(0.8, (75, 77)) # Plotting at (75, 77), ratio 0.8.
|
||||
|
||||
square = Square(12)
|
||||
print(square.area()) # 144
|
||||
print(square.get_geometric_type()) # Square
|
||||
square.plot(0.93, (74, 75)) # Plotting at (74, 75), ratio 0.93.
|
||||
|
||||
print(square.__class__.__mro__)
|
||||
# prints:
|
||||
# (<class '__main__.Square'>, <class '__main__.RegularPolygon'>,
|
||||
# <class '__main__.Polygon'>, <class '__main__.Shape'>,
|
||||
# <class '__main__.Plotter'>, <class 'object'>)
|
||||
|
||||
|
||||
"""
|
||||
$ python multiple.inheritance.py
|
||||
259.8076211353316
|
||||
RegularHexagon
|
||||
Plotting at (75, 77), ratio 0.8.
|
||||
144
|
||||
Square
|
||||
Plotting at (74, 75), ratio 0.93.
|
||||
(
|
||||
<class '__main__.Square'>, <class '__main__.RegularPolygon'>,
|
||||
<class '__main__.Polygon'>, <class '__main__.Shape'>,
|
||||
<class '__main__.Plotter'>, <class 'object'>
|
||||
)
|
||||
"""
|
||||
28
ch06/oop/operator.overloading.py
Normal file
28
ch06/oop/operator.overloading.py
Normal file
@ -0,0 +1,28 @@
|
||||
# oop/operator.overloading.py
|
||||
class Weird:
|
||||
def __init__(self, s):
|
||||
self._s = s
|
||||
|
||||
def __len__(self):
|
||||
return len(self._s)
|
||||
|
||||
def __bool__(self):
|
||||
return '42' in self._s
|
||||
|
||||
|
||||
weird = Weird('Hello! I am 9 years old!')
|
||||
print(len(weird)) # 24
|
||||
print(bool(weird)) # False
|
||||
|
||||
weird2 = Weird('Hello! I am 42 years old!')
|
||||
print(len(weird2)) # 25
|
||||
print(bool(weird2)) # True
|
||||
|
||||
|
||||
"""
|
||||
$ python operator.overloading.py
|
||||
24
|
||||
False
|
||||
25
|
||||
True
|
||||
"""
|
||||
30
ch06/oop/private.attrs.fixed.py
Normal file
30
ch06/oop/private.attrs.fixed.py
Normal file
@ -0,0 +1,30 @@
|
||||
# oop/private.attrs.fixed.py
|
||||
class A:
|
||||
def __init__(self, factor):
|
||||
self.__factor = factor
|
||||
|
||||
def op1(self):
|
||||
print('Op1 with factor {}...'.format(self.__factor))
|
||||
|
||||
class B(A):
|
||||
def op2(self, factor):
|
||||
self.__factor = factor
|
||||
print('Op2 with factor {}...'.format(self.__factor))
|
||||
|
||||
|
||||
obj = B(100)
|
||||
obj.op1() # Op1 with factor 100...
|
||||
obj.op2(42) # Op2 with factor 42...
|
||||
obj.op1() # Op1 with factor 100... <- Wohoo! Now it's GOOD!
|
||||
|
||||
print(obj.__dict__.keys())
|
||||
# dict_keys(['_A__factor', '_B__factor'])
|
||||
|
||||
|
||||
"""
|
||||
$ python private.attrs.fixed.py
|
||||
Op1 with factor 100...
|
||||
Op2 with factor 42...
|
||||
Op1 with factor 100...
|
||||
dict_keys(['_A__factor', '_B__factor'])
|
||||
"""
|
||||
30
ch06/oop/private.attrs.py
Normal file
30
ch06/oop/private.attrs.py
Normal file
@ -0,0 +1,30 @@
|
||||
# oop/private.attrs.py
|
||||
class A:
|
||||
def __init__(self, factor):
|
||||
self._factor = factor
|
||||
|
||||
def op1(self):
|
||||
print('Op1 with factor {}...'.format(self._factor))
|
||||
|
||||
class B(A):
|
||||
def op2(self, factor):
|
||||
self._factor = factor
|
||||
print('Op2 with factor {}...'.format(self._factor))
|
||||
|
||||
|
||||
obj = B(100)
|
||||
obj.op1() # Op1 with factor 100...
|
||||
obj.op2(42) # Op2 with factor 42...
|
||||
obj.op1() # Op1 with factor 42... <- This is BAD
|
||||
|
||||
print(obj.__dict__.keys())
|
||||
# dict_keys(['_factor'])
|
||||
|
||||
|
||||
"""
|
||||
$ python private.attrs.py
|
||||
Op1 with factor 100...
|
||||
Op2 with factor 42...
|
||||
Op1 with factor 42...
|
||||
dict_keys(['_factor'])
|
||||
"""
|
||||
51
ch06/oop/property.py
Normal file
51
ch06/oop/property.py
Normal file
@ -0,0 +1,51 @@
|
||||
# oop/property.py
|
||||
class Person:
|
||||
def __init__(self, age):
|
||||
self.age = age # anyone can modify this freely
|
||||
|
||||
class PersonWithAccessors:
|
||||
def __init__(self, age):
|
||||
self._age = age
|
||||
|
||||
def get_age(self):
|
||||
return self._age
|
||||
|
||||
def set_age(self, age):
|
||||
if 18 <= age <= 99:
|
||||
self._age = age
|
||||
else:
|
||||
raise ValueError('Age must be within [18, 99]')
|
||||
|
||||
class PersonPythonic:
|
||||
def __init__(self, age):
|
||||
self._age = age
|
||||
|
||||
@property
|
||||
def age(self):
|
||||
return self._age
|
||||
|
||||
@age.setter
|
||||
def age(self, age):
|
||||
if 18 <= age <= 99:
|
||||
self._age = age
|
||||
else:
|
||||
raise ValueError('Age must be within [18, 99]')
|
||||
|
||||
person = PersonPythonic(39)
|
||||
print(person.age) # 39 - Notice we access as data attribute
|
||||
person.age = 42 # Notice we access as data attribute
|
||||
print(person.age) # 42
|
||||
person.age = 100 # ValueError: Age must be within [18, 99]
|
||||
|
||||
|
||||
"""
|
||||
$ python property.py
|
||||
39
|
||||
42
|
||||
Traceback (most recent call last):
|
||||
File "/Users/fab/srv/lpp3e/v3/ch06/oop/property.py", line 38, in <module>
|
||||
person.age = 100 # ValueError: Age must be within [18, 99]
|
||||
File "/Users/fab/srv/lpp3e/v3/ch06/oop/property.py", line 32, in age
|
||||
raise ValueError('Age must be within [18, 99]')
|
||||
ValueError: Age must be within [18, 99]
|
||||
"""
|
||||
18
ch06/oop/simplest.class.py
Normal file
18
ch06/oop/simplest.class.py
Normal file
@ -0,0 +1,18 @@
|
||||
# oop/simplest.class.py
|
||||
class Simplest(): # when empty, the braces are optional
|
||||
pass
|
||||
|
||||
print(type(Simplest)) # what type is this object?
|
||||
|
||||
simp = Simplest() # we create an instance of Simplest: simp
|
||||
print(type(simp)) # what type is simp?
|
||||
# is simp an instance of Simplest?
|
||||
print(type(simp) is Simplest) # There's a better way to do this
|
||||
|
||||
|
||||
"""
|
||||
$ python simplest.class.py
|
||||
<class 'type'>
|
||||
<class '__main__.Simplest'>
|
||||
True
|
||||
"""
|
||||
40
ch06/oop/static.methods.py
Normal file
40
ch06/oop/static.methods.py
Normal file
@ -0,0 +1,40 @@
|
||||
# oop/static.methods.py
|
||||
class StringUtil:
|
||||
|
||||
@staticmethod
|
||||
def is_palindrome(s, case_insensitive=True):
|
||||
# we allow only letters and numbers
|
||||
s = ''.join(c for c in s if c.isalnum()) # Study this!
|
||||
# For case insensitive comparison, we lower-case s
|
||||
if case_insensitive:
|
||||
s = s.lower()
|
||||
for c in range(len(s) // 2):
|
||||
if s[c] != s[-c -1]:
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_unique_words(sentence):
|
||||
return set(sentence.split())
|
||||
|
||||
print(StringUtil.is_palindrome(
|
||||
'Radar', case_insensitive=False)) # False: Case Sensitive
|
||||
print(StringUtil.is_palindrome('A nut for a jar of tuna')) # True
|
||||
print(StringUtil.is_palindrome('Never Odd, Or Even!')) # True
|
||||
print(StringUtil.is_palindrome(
|
||||
'In Girum Imus Nocte Et Consumimur Igni') # Latin! Show-off!
|
||||
) # True
|
||||
|
||||
print(StringUtil.get_unique_words(
|
||||
'I love palindromes. I really really love them!'))
|
||||
# {'them!', 'palindromes.', 'I', 'really', 'love'}
|
||||
|
||||
|
||||
"""
|
||||
$ python static.methods.py
|
||||
False
|
||||
True
|
||||
True
|
||||
True
|
||||
{'them!', 'palindromes.', 'I', 'really', 'love'}
|
||||
"""
|
||||
16
ch06/oop/super.duplication.py
Normal file
16
ch06/oop/super.duplication.py
Normal file
@ -0,0 +1,16 @@
|
||||
# oop/super.duplication.py
|
||||
class Book:
|
||||
|
||||
def __init__(self, title, publisher, pages):
|
||||
self.title = title
|
||||
self.publisher = publisher
|
||||
self.pages = pages
|
||||
|
||||
|
||||
class Ebook(Book):
|
||||
|
||||
def __init__(self, title, publisher, pages, format_):
|
||||
self.title = title
|
||||
self.publisher = publisher
|
||||
self.pages = pages
|
||||
self.format_ = format_
|
||||
31
ch06/oop/super.explicit.py
Normal file
31
ch06/oop/super.explicit.py
Normal file
@ -0,0 +1,31 @@
|
||||
# oop/super.explicit.py
|
||||
class Book:
|
||||
|
||||
def __init__(self, title, publisher, pages):
|
||||
self.title = title
|
||||
self.publisher = publisher
|
||||
self.pages = pages
|
||||
|
||||
|
||||
class Ebook(Book):
|
||||
|
||||
def __init__(self, title, publisher, pages, format_):
|
||||
Book.__init__(self, title, publisher, pages)
|
||||
self.format_ = format_
|
||||
|
||||
|
||||
ebook = Ebook(
|
||||
'Learn Python Programming', 'Packt Publishing', 500, 'PDF')
|
||||
print(ebook.title) # Learn Python Programming
|
||||
print(ebook.publisher) # Packt Publishing
|
||||
print(ebook.pages) # 500
|
||||
print(ebook.format_) # PDF
|
||||
|
||||
|
||||
"""
|
||||
$ python super.explicit.py
|
||||
Learn Python Programming
|
||||
Packt Publishing
|
||||
500
|
||||
PDF
|
||||
"""
|
||||
33
ch06/oop/super.implicit.py
Normal file
33
ch06/oop/super.implicit.py
Normal file
@ -0,0 +1,33 @@
|
||||
# oop/super.implicit.py
|
||||
class Book:
|
||||
|
||||
def __init__(self, title, publisher, pages):
|
||||
self.title = title
|
||||
self.publisher = publisher
|
||||
self.pages = pages
|
||||
|
||||
|
||||
class Ebook(Book):
|
||||
|
||||
def __init__(self, title, publisher, pages, format_):
|
||||
super().__init__(title, publisher, pages)
|
||||
# Another way to do the same thing is:
|
||||
# super(Ebook, self).__init__(title, publisher, pages)
|
||||
self.format_ = format_
|
||||
|
||||
|
||||
ebook = Ebook(
|
||||
'Learn Python Programming', 'Packt Publishing', 500, 'PDF')
|
||||
print(ebook.title) # Learn Python Programming
|
||||
print(ebook.publisher) # Packt Publishing
|
||||
print(ebook.pages) # 500
|
||||
print(ebook.format_) # PDF
|
||||
|
||||
|
||||
"""
|
||||
$ python super.implicit.py
|
||||
Learn Python Programming
|
||||
Packt Publishing
|
||||
500
|
||||
PDF
|
||||
"""
|
||||
Loading…
x
Reference in New Issue
Block a user