kdocs
GitHub
Lang - Analytics
Lang - Analytics
  • Base
    • Python 3
      • New Project
Powered by GitBook
On this page
  • The use of __name__ == '__main__'
  • Types and Data Structures
  • Strings
  • Falsy values
  • Lists [] <class 'list'>
  • Tuples () <class 'tuple'>
  • Sets {} <class 'set'>
  • Dictionaries {} <class 'dict'>
  • Arrays
  • The range function
  • Else in For loops
  • Using pass statement
  • Variable declaration >3.6
  • Variable creation
  • String formatting with F_STRINGS
  • Classes
  • __init__() function
  • __str__() function
  • self parameter
  • Inheritance
  • Polymorphism
  • Lambda functions
  • Iterator
  • Scope in Python
  • Modules
  • Walrus Operator
  • Currying and Partials
  • Exceptions
  • Raising them
  • Catching them
  • Dealing with generic types
  • Default mutable values in parameters
  • Getting memory variable use
  • Python Decorators
  • Random Functions
  • Whatsapp library pywhatkit
  • Pdf library camelot
  1. Base

Python 3

NextNew Project

Last updated 6 months ago

The use of __name__ == '__main__'

Adding this to a python file script will ensure that everything inside this condition will be only ran, if the script file was runned directly.

if __name__ == '__main__':

This happens because when you import functions from other files, python runs the entire file. So if you have code executing there, it will execute it on the import.

To avoid this you put this code inside this condition.

Types and Data Structures

Strings

  • https://www.w3schools.com/python/python_strings_methods.asp

  • Can be accessed like arrays: str[0].

  • You can use in to check substrings.

Falsy values

  • False

  • None

  • 0

  • ""

  • (), [] and {}

Lists [] <class 'list'>

  • https://www.w3schools.com/python/python_lists_methods.asp

  • Are ordered, changeable and allow duplicates.

    • Ordered means the items have a defined order, and that order will not change.

    • Changeable means that we can change, add, remove items after the list was created.

    • Allow duplicates.

  • It's items are indexed [0]...[n].

  • Can have items of different data types.

Access

  • Can have negative indexing list[-1] that will access from end.

  • Can also index a range list[2:5], not including 5.

Check existence

  • With in.

Changing and Inserting values

  • You can change a range of values list[2:5] = ["", "", ""].

Inserting values

  • Insert values in a fixed position with list.insert(i, value).

  • Inserting at the end with list.append(value).

Merging lists

  • You can merge lists with list.extend(list) or by adding list = list + list2.

Removing values

  • Removing by value with list.remove(value).

  • Removing by index with list.pop(i).

  • Removing last item with list.pop().

  • Clear the list with list.clear().

Unpacking values (Destructuring)

  • Using * will throw the rest of the list to the variable.

[first, second, third] = list

# or

[first, *second] = list

List Comprehensions

s: list[str] = [p for p in people if len(p) > 7]

Sorting lists

  • You can sort with list.sort(key = myFunc).

  • You can reverse a list list.reverse().

Tuples () <class 'tuple'>

  • Are ordered, unchangeable and allow duplicates.

    • Unchangeable means that we cannot change, add or remove items after the tuple was created.

  • It's items are indexed [0]...[n].

  • Can have items of different data types.

Creating a tuple with one item requires a comma (value,)

Access

  • Can have negative indexing tuple[-1] that will access from end.

  • Can also index a range tuple[2:5], not including 5.

Changing/Inserting and Deleting values

  • Since they are immutable, you must transform them in a list, or create a new tuple.

Unpacking values (Destructuring)

  • Using * will throw the rest of the list to the variable.

(first, second, third) = list

# or

(first, *second) = list

Merging and Multiplying Tuples

  • You can merge tuples with tup1 + tup2.

  • You can multiply the values of a tuple with tup1 * 5, and this will copy the values 5 times inside the tuple.

Sets {} <class 'set'>

  • https://www.w3schools.com/python/python_sets_methods.asp

  • Are unordered, unchangeable, unindexed and cannot have duplicates.

    • Unordered means that items do not have a defined order.

    • Unchangeable means you cannot change its values after it was created, BUT you can INSERT new items and DELETE.

    • Unindexed means that items cannot be referenced by index or key.

Access

  • Although items cannot be accessed by index, you can loop a set with for x in set.

Check existence

  • With in.

Adding new values

  • Add new values with set.add(value).

Merging sets

  • Merge another set or iterable with set.update(otherSet).

Removing values

  • Remove a value with set.remove(value). (Will raise error if value DONT exists)

  • Remove a value with set.discard(value). (Will NOT raise error if value DONT exists)

  • Remove a random value with set.pop().

Combining sets

set_a: set[int] = {1,2,3,4,5}
set_b: set[int] = {4,5,6,7,8}

comnbined_sets = set_a | set_b

Subtrating sets (Exclusive elements)

set_a: set[int] = {1,2,3,4,5}
set_b: set[int] = {4,5,6,7,8}

comnbined_sets = set_a - set_b

Shared sets (Intersection)

set_a: set[int] = {1,2,3,4,5}
set_b: set[int] = {4,5,6,7,8}

comnbined_sets = set_a & set_b

Unique sets elements

set_a: set[int] = {1,2,3,4,5}
set_b: set[int] = {4,5,6,7,8}

comnbined_sets = set_a ^ set_b

Dictionaries {} <class 'dict'>

  • Are ordered >3.6 collections, storing data in key: value pairs.

    • Ordered means that items have a defined order.

    • Changeable means that we can change, add and remove items after its creation.

    • Don't allow Duplicates with the same key.

Access

  • You can access by key dict[key].

  • You can access by dict.get(key).

Check existence

  • You can check if a key exists with in.

Keys and values

  • You can get the keys in a list with dict.keys().

  • You can get the values in a list with dict.values().

  • You can get a list of tuples with dict.items() returning [(key, value), ...].

Merge dicts

  • You can merge dicst with dict.update(otherDict).

Removing items

  • By key with dict.pop(key) or del dict[key].

  • Remove the last item (Only >3.6) with dict.popitem().

Clearing dict

  • You can delete a dict with del dict, but this will also delete the variable.

  • You can clear a dict with dict.clear().

Looping with key, value

Regular for will give you access onlly to the key.

To loop having the key and value do it with .items().

for key, value in dict.items():
    ...

Copying dicts

You cannot copy a dictionary values by just assingning it to a new variable. Doing it like this will only copy the reference.

  • You must use newDict = dict.copy().

  • Or use the dict() constructor.

Arrays

Python does not natively supports Arrays

To use them you must import them from NumPy library.

They basically work just like a List.

The range function

range(start, end, step)

Returns an iterator from [start, end), and you can add a step number like:

range(0, 10, 2)

The current range index will add in steps of 2.

Don't convert range() to list(range())

  • range

  • map

  • filter

It is going to occupy A LOT more memory.

Else in For loops

An else statement after a for, is a block of code that will be executed after the loop ends.

If the for loop was breaked with break, than the else WILL NOT be executed.

for x in range(6):
    ...
else:
    print("For looop is finished")

Using pass statement

Use pass to fill empty blocks like if, for, class or etc.

for x in range(6):
    pass

Variable declaration >3.6

You can state the type in declaration.

Usefull for hiting and intelisense.

n: int = 1
n: str = ''

Variable creation

For code more readable only.

n: int = 100_000

String formatting with F_STRINGS

Thousand separator

print(f'{n:_}') => 1_000
print(f'{n:,}') => 1,000

Aligning output strings

s: str = 'var'

# Fill before
print(f'{s:>5}') => '  var'

#Fill After (Optional to specify '<')
print(f'{s:<5}') => 'var  '

# Center the text
print(f'{s:^5}') => ' var '

# Will fill the spaces with char '#'
print(f'{s:#^5}') => '##var'
print(f'{s:#^5}') => 'var##'
print(f'{s:#^5}') => '#var#'

Formatting datetime

now: datetime = datetime.now()

print(f'{now:%d/%m/%y (%H:%M:%S)}') => '09/02/24 (10:40:20)'

# Local version of datetime
print(f'{now:%c}') => 'Fri Feb  9 10:40:20 2024'

Formatting decimals

# For truncating, instead of rounding (2 decimals)
print(f'{n:.2f}')

# Removing decimals
print(f'{n:.0f}')

# Adding thousand separator
print(f'{n:,.2f}')

Showing var name in print

a: int = 5
b: int = 5
s: str = 'Hi bob'
b: bool = True

# For showing the formulas along with result
print(f'{a + b = }') => 'a + b = 10'
print(f'{bool(b) = }') => 'bool(b) = True'

# For showing the var name and the result
print(f'{s = }') => "s = 'Hi bob'"

Classes

Create a class with class ClassName:.

Then create an object from this class with obj = ClassName().

__init__() function

All classes have a function __init__() which is basically the class constructor.

class MyClass:
    __init__(self, otherParams):
        self.something = otherParams

obj = MyClass('someValue')

__str__() function

Controls what should be returned when the class object is represented as a string.

If not set, the string representation of the object is returned.

Use it to format the way you wish when printed.

self parameter

Is a reference to the current instance of the class.

Every function inside the class that have to access the class properties, MUST have a self as FIRST parameter.

You do not have to name it self, you can call it whatever you want, it just HAVE to be the first parameter.

Inheritance

Allows us to define a class that inherits all the methods and properties from another class.

To do this you simply inform the Parent class name when creating the class:

class Student(Person):
    ...

Overwriting the parent constructor

To overwrite it you just declare a constructor for the child class.

class Student(Person):
    def __init__(self, ...):
        ...

Overwriting but also calling the parents constructor

class Student(Person):
    def __init__(self, ...):
        Person.__init__(self, ...)
        ...

You can also use super():

class Student(Person):
    def __init__(self, ...):
        # Note that you don't have to pass the 'self' as parameter to the 'super'
        super().__init__(...)

Polymorphism

All these class have a move() method, since they inherit from Vehicle, and some class overwrite and some don't.

Also check the use of pass in the Car class, since it does nothing but inherit.

class Vehicle:
    def __init__(self, brand, model):
        self.brand = brand
        self.model = model

    def move(self):
        print("Move!")

class Car(Vehicle):
    pass

class Boat(Vehicle):
    def move(self):
        print("Sail!")

class Plane(Vehicle):
    def move(self):
        print("Fly!")

car1 = Car("Ford", "Mustang")        # Create a Car object
boat1 = Boat("Ibiza", "Touring 20")  # Create a Boat object
plane1 = Plane("Boeing", "747")      # Create a Plane object

for x in (car1, boat1, plane1):
    print(x.brand)
    print(x.model)
    x.move()

Lambda functions

Are small anonymous functions, that can have multiple arguments but only one returned expression.

You can assign them to variables.

lambda arguments : expression

myFunc = lambda a, b : a * b

Iterator

Are objects which implements the iterator protocol:

  • __iter__()

  • __next__()

string, List, Tuple, Dictionary and Set are all iterable objects.

You can call iter() function on them and iterate them with next().

myIter = iter("banana")

# or

myIter = iter(someList)
...


next(myIter)
next(myIter)
next(myIter)
...

for loops automatically create iterators on objects and execute next() at each loop.

You can create iterators by implementing the __iter__() and __next__() methods.

To avoid an iterator running forever, raise StopIteration.

class MyIterClass:
    def __iter__(self):
        self.a = 1
        return self

    def __next__(self):
        if self.a < 20:
            self.a += 1
            return self.a
        else:
            raise StopIteration

myIterClass = MyIterClass()

myIter = iter(myIterClass)
next(myIter)

# or

for x in myIterClass:
    ...

Scope in Python

Variable creation is limited by the scope of where it is created.

A variable created in the main body of the Python code is a global variable and belongs to the global scope.

Global variables

Creating or referencing global variables inside blocks can be done with global keyword.

def someFunc():
    # Creates a new global variable 
    global someVar
    someVar = 5
someVar = 5

def someFunc():
    # This will reference to the global variable
    global someVar
    someVar = 6

nonlocal variable reference

Using nonlocal to a variable will make the reference to the variable be of the outer scope.

Useful with nested functions.

def myfunc1():
    x = "Jane"
    def myfunc2():
        # This will change 'x' value from "Jane" to "hello"
        nonlocal x
        x = "hello"
    myfunc2()
    return x

Modules

Consider a module to be the same as a code library.

A file containing a set of method, classes or variables to be included.

mymodule.py

def someMethod():
    ...

someVar = List("", "", "")

class someClass:
    ...
import mymodule

# or

import mymodule as othername

# or

from mymodule import someMethod, someClass

Walrus Operator

Transform this

users: dict[int, str] = {0: 'Bob', 1: 'Mario'}

user: str | None = users.get(3)

if user:
    print('User exists')
else:
    print('User not found)

to this

users: dict[int, str] = {0: 'Bob', 1: 'Mario'}

if user := users.get(3):
    print('User exists')
...

This operator firts evaluetes the expression or function and than assign it to the variable.

def get_into(text: str) -> dict:
    return {
        'words': (words := text.split()),
        'word_count': len(words)
    }

Currying and Partials

def multiply_by(a: float) -> Callable:
    def multiply(b: float) -> float:
        return a * b;
    return multiply

double: Callable = multiply_by(2)
triple: Callable = multiply_by(3)

double(50)   # -> 100
triple(30)   # -> 90

Take a look at Partials

Exceptions

Raising them

You can raise exceptions with raise keyword.

  • raise Exception("Some exception").

  • raise TypeError("Only integers").

  • And many other types.

Catching them

  • else block executes code when there is no error.

  • finally block executes code regardless if there were errors or not.

You can have multiple except statements for different exceptions.

try:
    ...
except Exception as e:
    print(repr(e))
except:
    ...
else:
    ...
finally:
    ...

Dealing with generic types

This is a better aprouch than using Any type.

from typing import Iterable, TypeVar

T = TypeVar('T')

def append_to_list(elements: Iterable[T], target: list[T] = []) -> list[T]:
    target.extend(elements)
    return target

Default mutable values in parameters

If a parameter is of a type list or any mutable type, and has a default value - like an empty list -, calling the function multiples times might produce bugs, because the calls may share the same list object.

def append_to_list(..., list[T] = [])

should be

def append_to_list(..., list[T] = None)

Getting memory variable use

from sys import getsizeof

print(getsizeof(var))

Python Decorators

You can create custom decorators also, and import them in your scripts.

Like decorators, for performance, and etc.

@cache

Cache result of functions.

@cache
def some_func() -> int:
    ...

You can also see the cached info

print(some_func.cache_info())

@atexit.register

It will call this decorated function when script terminates, for whatever reason.

Interesting for DB connection close.

import atexit

@atexit.register
def exit_handler() -> None:
    print('something')

You can also unregister these functions

atexit.unregister(exit_handler)

Random Functions

shuffle

Shuffles a list in place.

from random import shuffle

people: list[str] = ['Bob', 'Tom', 'James']

shuffle(people)
print(people)

random

Returns a random number between 0 and 1.

from random import random

value: float = random()

randint

Returns a random int number within a specified range [beginning, end].

from random import randint

value: int = randint(10, 20)

randrange

Works the same as randint, but with a specified range [beginning, end).

It also let's you provide a step, randrange(beginning, end, step).

from random import randrange

value: int = randrange(10, 20)

value: list[int] = randrange(10, 20, 2)  # -> Produces only 10, 12, 14, 16 and 18

choice

Selects a random element from a list.

from random import choice

people: list[str] = ['Bob', 'Tom', 'James']

choosen: str = choice(people)

choices

Selects a specified k number of random elements from a list. (By default 1 element)

You can also provide a weight parameter, which will be a tuple | list of float that will be applied to the elements. (Must be in the same order as the element's list)

Returns a list.

from random import choices

people: list[str] = ['Bob', 'Tom', 'James']
selected: list[str] = choices(people, k=2)

weights: tuple = (.15, .50, .05)
selected: list[str] = choices(people, k=5, weights=weights)

sample

Does the same as choices, but it only retuns unique elements. (Each will only appear once)

This means k must be greater or equal to the length of the provided list.

If the element is repeated inside the provided list, IT CAN repeat.

from random import sample

samples: list[int] = sample(range(100), k=10, weights=[...])

seed

It will "save" the state of the other random functions, so that, they will reproduce the same result if necessary.

from random import seed, ...

seed(1)

random()
choice(...)
sample(...)

seed(5)

...

Whatsapp library pywhatkit

Pdf library camelot

Python Tutorial
Logo
W3Schools.com
W3Schools.com
Logo
Logo