Python has greatly changed from ver. 3.x. This tutorial only deals with this version (code below has been tested with ver. 3.7).
- Where is Python on macOS ⤳
which python3.7
⤳/usr/local/bin/python3.7
- Where is Python on Windows ⤳
Get-Command python
⤳C:\Python311\python.exe
- Python shell (current directory) ⤳
>>> import os; print(os.getcwd())
- Python shell (current directory) ⤳
>>> from pathlib import Path; print(Path.cwd())
- Operating System -OS- shell ⤳
python .\EA.py
- Python shell ⤳
>>> exec(open("C:\\Users\\franc\\Desktop\\EA.py").read())
- Python shell ⤳
>>> exit()
or>>> quit()
- Update of Python ⤳ best and simpler solution is downloading the latest version and installing it…
pip install pywin32
- -OR- macOS (install Node Version Manager) ⤳
python .\EA.py
- macOS ⤳
import os; print(os.getcwd())
Most programming languages require a way of representing types (numbers especially) in memory. Interpreters as Python crucially rely on type representation to instrument calculations: +, -, *, /, … Rule(s)
- Python views common numbers (integers, floating point numbers…) as constructed types instead of primitive types. For example, integers are unbounded in Python.
Example
import math import sys # Integers are unbounded in Python 3.x my_int = int() print('my_int', my_int) # '0' print('Size of \'int\'', sys.getsizeof(int())) # Size (in bytes) of an *instance* of the 'int' class, namely size of '0'... # Disappeared from Python 3.x: # print('long', sys.getsizeof(long())) # Size of an *instance* of the 'long' class one_bit_set = [False, False, False, False, False, False, False, True] # 8 bits... one = int() for value in one_bit_set: one = one << 1 one = one | 1 if value else one print(bin(one)) # '0b1' two_bit_set = [False, False, False, False, False, False, True, False] two = int() for value in two_bit_set: two = two << 1 two = two | 1 if value else two print(bin(two)) # '0b10' three = int('00000011', 2) print(three) minus_nine = ~(9 - 1) print(minus_nine, bin(minus_nine)) minus_ten = ~(10 - 1) print(minus_ten, bin(minus_ten)) print(type(math.pi)) # '<class 'float'>' # https://docs.python.org/3/library/stdtypes.html#float.hex -> print(float.hex(math.pi)) # [sign] ['0x'] integer ['.' fraction] ['p' exponent] -> '0x1.921fb54442d18p+1' print(float.fromhex('0x1.921fb54442d18p+1'))
Numerical stability
Rule(s)
sys.float_info
provides information on memory representation constraints about floating point numbers.Example
# https://docs.python.org/3/library/sys.html#sys.float_info print('Max float: ', sys.float_info.max) print('Epsilon such that there is *no* \'x\' such that \'1 < x < 1 + sys.float_info.epsilon\': ', sys.float_info.epsilon) # Floating point numbers are not primitive: my_float = float() my_other_float = float() my_yet_another_float = my_float print(my_float == my_other_float) # 'True' is displayed since both are equal to '0' assert (not my_float is my_other_float) # 'is' and 'id()' are *totally* equivalent assert (my_float is my_yet_another_float) assert (not id(my_float) == id(my_other_float)) assert (id(my_float) == id(my_yet_another_float))
Accessing to bytes…
Rule(s)
- In a more generic way,
bytearray
is a relevant class to deal with byte sets as internal representation of objects: strings, etc.Example
b = bytearray('ABC', 'utf-8') print(b, 'size:', len(b)) for character in b: print(bin(character)) # Display: '0b1000001' '0b1000010' '0b1000011' print('**') print(bytearray([65, 66, 67]).decode('utf-8')) # Display: 'ABC'
Resource(s)
Class functions are identified by, either the @classmethod
or@staticmethod
decorators. Instead of “instance functions”, class functions are called from classes themselves. As for class attributes, they are declared “as is” since “instance attributes” are declared in constructors only.Example
class Carrefour_Items: _X_ibm_client_id = os.getenv("_X_ibm_client_id") # Class attribute… _X_ibm_client_secret = os.getenv("_X_ibm_client_secret") # Class attribute… @classmethod def Get_X_ibm_client_id(Carrefour_Items_class): # First argument is implicitly the class itself… return Carrefour_Items_class._X_ibm_client_id @staticmethod def Get_X_ibm_client_secret(): # … while this is not the case here… return Carrefour_Items._X_ibm_client_secret
Resource(s)
Sets are here…
Although dictionaries (a.k.a. hash tables, hash maps, associative containers, etc.) are fully fledged collections, choosing a dictionary as underlying data representation structure hotly is a question of fluent data processing. More details on Python collections are here… Example
from collections import OrderedDict class Polynomial: def __init__(self, *elements): self.__representation = {} # Python common dictionary... for e in elements: # print(e) self.__representation[e[1]] = e[0] # Powers are keys... # sorted(self.__representation) # Sort on keys (ascending)... returns a list... # Required for Horner eval.: self.__representation = OrderedDict(sorted(self.__representation.items(), key=lambda pair: pair[0], reverse=True)) # Sort on keys (descending)... # print(type(self.__representation)) # '<class 'collections.OrderedDict'>' is displayed # print(self.__representation) def eval(self, x): result = 0 for key, value in self.__representation.items(): # print(key) result += pow(x, key) * value return result # https://en.wikipedia.org/wiki/Horner%27s_method def eval_Horner(self, x): # Horner method that required less multiplication stuff... prior_key = None result = 0 for key in self.__representation: if prior_key is not None: assert key < prior_key # Imposed by sorting in '__init__' # print(key) result += self.__representation.get(prior_key) for i in range(prior_key, key, -1): # print(i, end='-') result *= x prior_key = key result += self.__representation.get(prior_key) for i in range(prior_key, 0, -1): # print(i, end='-') result *= x return result p1 = Polynomial((5, 2), (-3, 1), (8, 0)) print('eval p1:', p1.eval(2)) # '22' is displayed print('eval_Horner:', p1.eval_Horner(2)) p2 = Polynomial((-12, 10), (8, 39)) print('eval p2:', p2.eval(1)) # '-4' is displayed print('eval_Horner:', p2.eval_Horner(1)) p3 = Polynomial((3, 11), (-8, 7), (-7, 1), (-43, 0)) print('eval p3:', p3.eval(5)) # '145859297' is displayed print('eval_Horner:', p3.eval_Horner(5))
Resource(s)
Hash method overriding
Rule(s)
- For homemade built types acting as the type of keys in dictionaries, the overriding of the
__hash__
function is mandatory along with that of the__eq__
function.- As in many other programming languages, the crucial rule to be respected is:
x == y ⇒ hash(x) == hash(y)
.Example (homemade built type)
import re class N_INSEE: # Similar to 'static initializer' in Java: _Expression_reguliere_N_INSEE = re.compile("^\d{13}$", re.ASCII) # 're.ASCII' only allows [0-9] in excluding UNICODE digits # Improve regular expression as follows (https://fr.wikipedia.org/wiki/Num%C3%A9ro_de_s%C3%A9curit%C3%A9_sociale_en_France): # One digit sex between '1' and '2' # 2 digits birth year between '01' and '99' # 2 digits birth month between '01' and '12' # Etc @staticmethod def Format_N_INSEE(): return N_INSEE._Expression_reguliere_N_INSEE def __init__(self, valeur, clef): assert clef >= 1 and clef <= 97 # Pre-condition # print(re.findall('^\d{13}$', valeur)) self._valeur = None if N_INSEE.Format_N_INSEE().match(valeur) is not None: self._valeur = int(valeur) def __eq__(self, n_insee): # Python 3 *IMPLICITELY* implements '__ne__(self, n_insee)' while Python 2 *DOESN'T*! return self.__class__ == n_insee.__class__ and self._valeur == n_insee._valeur def __hash__(self): return hash(self._valeur) def clef(self): if self._valeur is None: raise Exception("Le NĀ°INSEE n'est pas conforme au format " + '"^\d{13}$"') return 97 - self._valeur % 97
Example (homemade built type as type of keys in ordinary dictionaries)
from N_INSEE import N_INSEE class University: def __init__(self, *students): self.__students = {} # Python common dictionary... for s in students: # print(s) self.__students[s.get_n_insee()] = s # Danger: index is based on a *HOMEMADE* built type! def count(self): return len(self.__students) def search(self, s): if s.get_n_insee() in self.__students: return True return False class Student: def __init__(self, surname, given_name, student_id, n_insee, photo=None): self._surname = surname self._given_name = given_name self._student_id = student_id self._n_insee = n_insee # Type is 'N_INSEE' # Etc. def get_n_insee(self): return self._n_insee fb1 = Student('Barbier', 'Franck', '?', N_INSEE('1630125388055', 29)) fb2 = Student('Barbier', 'Franck', '?', N_INSEE('1630125388055', 29)) u = University(fb1, fb2) print(u.count()) # '2' is displayed '__eq__(self, n_insee)' '__hash__(self)' are *NOT* overridden!
Resource(s)
pip is the most famous Python library (package) manager as Maven Repository for Java or npm for JavaScript. Example (Operating System -OS- level)
# 'Carrefour_Items_requirements.txt' file beautifulsoup4 Pillow requests … # Test access and version: pip -V pip install -r Carrefour_Items_requirements.txt
Example (library access and use)
from bs4 import BeautifulSoup # https://pypi.org/project/beautifulsoup4/ import os # built-in package import requests # https://pypi.org/project/requests/ … def request_Carrefour_Items(search_text): headers = { 'accept': "application/json", 'content-type': "application/json", 'x-ibm-client-id': Carrefour_Items.Get_X_ibm_client_id(), 'x-ibm-client-secret': Carrefour_Items.Get_X_ibm_client_secret() } query = "{\"queries\":[{\"query\":\"" + search_text + "\",\"field\":\"barcodeDescription\"}]}" return requests.post("https://api.fr.carrefour.io/v1/openapi/items", data=query, headers=headers).json()
Resource(s)