def __getitem__(self, idx): # __getitem__ make the class slicing like a sequence cls = type(self) if isinstance(idx, slice): return cls(self._components[idx]) elif isinstance(idx, int): return self._components[idx] else: msg = '{cls.__name__} indices must be integer' print_tab(msg.format(cls=cls))
def clocked(*args, **kwargs): t0 = time.time() result = func(*args, **kwargs) elapsed = time.time() - t0 name = func.__name__ arg_lst = [] if args: arg_lst.append(', '.join(repr(arg) for arg in args)) if kwargs: pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())] arg_lst.append(', '.join(pairs)) arg_str = ', '.join(arg_lst) print_tab('[%0.8fs] %s(%s) -> %r ' % (elapsed, name, arg_str, result)) return result
import collections import math from utils import print_tab ##### Using namedtuple to contruct class with no methods print("[+] Using namedtuple to contruct class with no methods") Student = collections.namedtuple('Student', ['GPA', 'department']) student_1 = Student(3.5, 'Economy') student_2 = Student._make((3.9, 'Computer Science')) print_tab("Student 1: " + str(student_1)) print_tab("Student 2: " + str(student_2)) ##### Implementing special methods print('[+] Implementing special methods') class Vector: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return f"Vector x: {self.x}, y: {self.y}" def __str__(self): return f"Vector x: {self.x}, y: {self.y}" def __abs__(self): return math.sqrt(self.x**2 + self.y**2)
from collections import defaultdict, UserDict from utils import print_tab ### USE defaultdict TO HANDLE MISSING KEYS print("USE defaultdict TO HANDLE MISSING KEYS") dd = defaultdict(list) country_city = [('HaNoi', 'VietNam'), ('Tokyo', 'Japan')] for city, country in country_city: dd[country].append(city) country_city = [('HaiPhong', 'VietNam'), ('Osaka', 'Japan')] for city, country in country_city: dd[country].append(city) print_tab(dd) ### USE UserDict TO CREATE A NEW MAPPING CLASS print('USE UserDict TO CREATE A NEW MAPPING CLASS') class StrKeyDict(UserDict): ''' A MAPPING TYPE WHICH ONLY ACCEPT KEY AS STRING TYPE ''' def __missing__(self, key): if isinstance(key, str): raise KeyError(key) return self[str(key)] def __contains__(self, item): return str(item) in self.data
from utils import print_tab print("Chapter 8: Object References, Mutability,and Recycling".upper()) print("Variable are not boxes".upper()) a = [1, 2, 3] b = a print_tab(f'b and a refer to the same object in memory') a.append(4) print_tab(f'b get updated if a get updated {b} == {a}') print('IDENTITY, EQUALITY, ALIASES') print_tab( f'Using id() to get identity of a variable, id of b is: {id(b)}, id of a is: {id(a)}' ) print_tab(f'a is b if only id of a == id of b') print_tab(f'a equal to b if only value of a == value of b') print('CHOOSING BETWEEN == AND is') print_tab( f'In most cases, we use == to compare two variables. However if we compare with singleton (eg: None), we better use is' ) print('COPY IS SHALLOW BY DEFAULT') a = [1, (2, 3, 4)] b = a[:] # this is copy a to b print_tab(f'b == a: {b==a}, b is a: {b is a}') print( f'SHALLOW COPY WILL CLONE THE OUTTERMOST OBJECT. IF THE OBJECT CONTAINS MUTABLE OBJECTS, IT DOES NOT CLONE THE INSIDE MUTABLE OBJECTS' ) a = [1, [2, 3, 4]] b = list(a) # shallow copy b[1].append(5)
def func(a,*,b): print_tab(f'a: {a} is positional argument, and b: {b} is keyword-only argument')
''' CODE EXAMPLES OF CHAPTER 5 ''' from utils import print_tab print('CHAPTER 5: FIRST-CLASS FUNCTIONS') print_tab('In python, functions are first class objects') print('TREATING FUNCTION AS AN OBJECT') def factorial(n): ''' Function to calculate factorial of an integer''' return 1 if n < 2 else n * factorial(n-1) print_tab(f'{factorial.__doc__}, type: {type(factorial)}') print('HIGHER ORDER FUNCTION') print_tab('Pass function as argument to another function') list_str = ['chào mừng', 'tiếng cười', 'bố', 'mẹ', 'con', 'ngôi nhà'] print_tab(f'Using sorting string by length: {sorted(list_str, key=len)}') print('map, filter CAN BE REPLACED BY LIST COMP') list_facts = [factorial(n) for n in range(5)] print_tab(str(list_facts)) list_facts = [factorial(n) for n in range(10) if n%2 == 0] print_tab(str(list_facts)) from functools import reduce from operator import add print('USING reduce, add TO SUM ALL ELEMENTS IN LIST') print_tab(f'Sum of 10 first integers: {reduce(add, range(10))}') print('ANONYMOUS FUNCTION/LAMBDA EXPRESSION') names = ['TRAN MANH HUNG', 'NGUYEN QUANG HUNG', 'PHAN VAN ANH', 'ANH THI VIEN']
def print_mro(cls): # this function to print mro of a given class print_tab(', '.join([c.__name__ for c in cls.__mro__]))
from utils import print_tab outline = ''' CHAPTER 12: Inheritance: For Good or For Worse OUTLINE: • The pitfalls of subclassing from built-in types which use C implementation • Multiple inheritance and the method resolution order ''' print('Subclassing from built-in types such as list, dict do not allow you to override the superclass methods'.upper()) class SomeDict(dict): def __getitem__(self, item): return 100 # always return 100 no matter what somedict = SomeDict(a = 'hello') d = {} d.update(somedict) print_tab(f'Check getitem: {somedict["a"]}') print_tab(f'getitem in dict init will ignore getitem inplementation in SomeDict class: {d["a"]}') print_tab(f'All problems can be fixed if we subclass from collections.UserDict class') print('METHOD RESOLUTION ORDER') class A(): def msg(self): return 'This is class A' class B(): def msg(self): return 'This is class B' class C(A,B): def msg(self): return super().msg() c = C()
return len(self._components) def __getitem__(self, idx): # __getitem__ make the class slicing like a sequence cls = type(self) if isinstance(idx, slice): return cls(self._components[idx]) elif isinstance(idx, int): return self._components[idx] else: msg = '{cls.__name__} indices must be integer' print_tab(msg.format(cls=cls)) v1 = Vector([1, 2, 3, 4]) print_tab(f'Slicing Vector instance is still a Vector instance: {v1[1:3]}') v1[1.2] print('DYNAMIC ATTRIBUTE USING __getattr__') import string class Vector_Dyna_Attr(Vector): attr_list = string.ascii_lowercase def __str__(self): return "Vector_Dyna_Attr class, attributes: " + str(self._components) def __getattr__(self, name): if len(name) == 1:
def __init__(self, text): self.text = text self.words = RE_WORD.findall(text) #re.findall returns a list with all nonoverlapping matches of the regular expression, as a list of strings. def __len__(self): return len(self.words) def __getitem__(self, item): # if item == 0: # raise KeyError return self.words[item] def __repr__(self): return f'Sentence: {reprlib.repr(self.text)}' # def __iter__(self): s = Sentence('This book is awesome') print_tab('If __getitem__ is implemented and index starts from 0, class will behave like sequence') print_tab('__getitem__ does not guarantee the class is iterable when using checking type like issubclass/isinstance') print_tab(f'Sentence class is Iterable: {issubclass(Sentence, abc.Iterable)}') print(f'ITERABLEs vs ITERATORs') print_tab('Iterator can be built from Iterable') print_tab('Once iterator is exhausted, it is useless. You should delete it') it = iter(s) while True: try: print_tab(f'{next(it)}') except StopIteration: del it break print(f'DESIGN A CLASSIC ITERATOR')
from utils import print_tab ### BYTES ESSENTIALS print('BYTES ESSENTIALS') # string to bytes is encoding, bytes to string is decoding cafe = bytes("đứng", encoding='utf-8') print_tab(f'{cafe}, length = {len(cafe)}') print_tab( f'{cafe.decode(encoding="utf - 8")}, length = {len(cafe.decode(encoding="utf-8"))}' ) print('Bytes is immutable, Bytearray is mutable') b = bytes("hello", encoding='utf-8') b_array = bytearray(b) print_tab(b) print_tab(b_array) print('STRUCT AND MEMORYVIEW') print( 'Struct let you parse packed bytes into a tuple of values based on predefined format. Or it can do opposite converting from values to packed bytes' ) print( 'Memoryview do not create a new buffer, but provides shared memory access to slices of data' ) import struct fmt = '3s3sHH' # 3s3s two sequence of 3 bytes, HH two short integer 16bits with open('gif_img.gif', 'rb') as f: img = memoryview(f.read()) # no copy here header = img[:10] # slicing, no copy here print_tab(f'Pointer at: {header}, Byte values: {bytes(header)}') print_tab(f'Unpacked by struck: {struct.unpack(fmt, header)}')
def inner(): print_tab('running inner')
def register(func): print_tab('running register right after the decorator loaded (%s)' % func) registry.append(func) return func
import math import sys from utils import print_tab print('CHAPTER 6 - DESIGN PATTERN') print('Using inspect to get members of a module') def strategy_1(a, b): return (a + b) / 2 def strategy_2(a, b): return math.sqrt(a * b) def best_strat(a, b): import inspect strats = [ func for name, func in inspect.getmembers( sys.modules[__name__], inspect.isfunction) if 'strategy_' in name ] return max((strat(a, b) for strat in strats)) print_tab(f'{best_strat(20,10)}')
return len(self._cards) def __delitem__(self, key): del self._cards[key] def __setitem__(self, key, value): self._cards[key] = value def __getitem__(self, item): return self._cards[item] def insert(self, index: int, value) -> None: self._cards.insert(index, value) deck = FrenchDeck() print_tab(f'When inherit from a class with abstract methods. You must implement all abstract methods in subclass. Otherwise, TypeError will be raised in runtime') print('TO CHECK FOR INTEGER/FLOAT YOU CAN USE numbers MODULE') from numbers import * a = 10 print_tab(f'a = {a}, a is integer: {isinstance(a, Integral)}') print_tab(f'a = {a}, a is float: {isinstance(a, Real)}. a is float because integer is subclass of float') a = 10.5 print_tab(f'a = {a}, a is integer: {isinstance(a, Integral)}') print_tab(f'a = {a}, a is float: {isinstance(a, Real)}') import abc print('CREATE CUSTOM ABC (Abstract Base Class)') class Shape(abc.ABC): @abc.abstractmethod