This repository contains notes on Fundametals of Python.
-
A general purpose programming language.
-
Python is an interpreted language however the code in compiled invisibly.
-
Python is strongly typed i.e. every object has a type.
>> a = '1' + 1 >> This will give TypeError.
-
Python is dynamically typed which means there is no type checking prior to running the code.
>> a = '1' >> a = 1 >> This is allowed.
- PEP: python enhancement proposals
- Built-In data types:
- Primitive Scalar Type: int, float, None, Bool, Complex
- Collection Type: str, range, tuple, list, Dictionary, set
- collection of unicode codepoints.
- not called as collection of characters because not all unicode codepoints are characters.
- They are immutable. You can replace it but cannot update it.
- Python doesn't have char. Even string with single character is also a str.
- Check out Escape Sequence and Raw String.
- Because strings are immuatble, string functions returns a new updated strings instead of updating previous strings. e.g. s = s.upper()
- collection of bytes.
- Can be constructed using:
- s = b"data"
- using the bytes() constructor
- string can be encoded to bytes and bytes can be decoded to str.
- mutable sequence of objects.
- mutable sequence of key-value pair.
- dict are oredered from Python 3.6 onwards.
- Module: collection of similar functions in a source code file.
- Module is only run once and it is done when it is imported.
- print(
__name__
) gives different results on executing or when importing. - When imported,
__name__
attribute will store the name of the script file. - When executed as a isolated python script,
__name__
attribute will contain the value "main". - Hence, the code written under
if __name__ == "__main__":
will only be executed if the script is run and not when imported.
- Any .py file can be considered as a module.
- Modules and scripts are interchangable based on context and usage.
- A bigger python file handling large operations should be considered as Python Program instead of Python Script or Python module.
from module import *
opens up to possibility of namespace clash is python programs so it should be avoided.sys.argv
attribute gives access to command line arguments.sys.argv[0]
stores the name of the file.
- Variable Assignment:
-
- When we write
x = 1000
, x is an object refrence pointing to a int object 1000.
- When we write
-
- When we rewrite
x = 500
, int object being immutable is not updated, instead x points to a new int object 500.
- When we rewrite
-
- Because int 1000 is no longer referred by any object reference the python garbage collector clears the memmory.
id()
: Returns a integer identifier which is unique throughout the life of the object.a is b
gives same result asid(a) == id(b)
i.e. they both refer to same object.
- Arguments passed is a function are passed by refrence and not pass by value.
- Types of Argument:
- Positional Argument
- Arbitrary Positional Argument
- Keywoard Argument
- Arbitrary Keywoard Argument
- Default Argument
- Check out: 5 Types of Arguments in Python Function Definitions
- Python is stong and dynamic typed.
- Dynamic Typing indicates that the type of varaible is not defined and decided at run time.
- Strongly typed means the variables do have a type and it matters when performing operations.
- e.g. you cannot add a string with an integer as neither of it will be implicilty converted.
- LEGB Scope in Python:
- Local
- Enclosing
- Global
- Built-in
- Check LEGBscope.py file.
- Hetrogenous immutable sequence.
- Tuple unpacking
- Homogenous immutable sequence of unicode codepoints.
- String concatenation with
+
orjoin()
. join()
is preferred over+
as it does not use too many temporary variables.- Syntax:
"<seperator>".join(sequence)
. e.g.a = ";".join(["1","2","3"])
=>a = '1;2;3'
. - Use
a = a.split(";")
to reverse it. - To concatenate: Invoke Join on empty text.
- String Formatiing:
a = "{0}, {1}".format(1,2)
a = "{}, {}".format(1,2)
a = "{x}, {y}".format(y=2, x=1)
a = "{lst[0]}, {lst[1]}".format(lst = [1,2])
a = "{math.pi}, {math.e}".format(math = math)
# here math is the imported module
- a.p of integers.
- Syntax:
range(start, stop, step)
- Avoid:
for i in range(len(lst))
; Instead use:for index, item in enumerate(lst)
.
- Hetrogenous mutable sequence.
- List slicing:
lst_slice = lst[start:end+1]
- List Copying: List can be copied by following methods:
-
- Assignment Operator
lst2 = lst1
- Assignment Operator
-
- List Slicing:
lst2 = lst1[:]
- List Slicing:
-
- Copy Method:
lst2 = lst1.copy()
- Copy Method:
-
- List Comprehension:
lst2 = [item for item in lst1]
- List Comprehension:
- Shallow Copying in Python:
-
- When a list lst2 copies another list lst1, both lst1 and lst2 refer to different lists.
-
- But the elements in them still refer to same list (if the element inside the first list is a LIST).
-
- Check listCopying.py
- List Repetition:
-
- If an item inside a list is also a list, then repetition is shallow.
-
- The repeted item which is also a list (sublist/nested list) refers to the same previous item (sub;list/ nested list).
-
- Check listRepetition.py
- List Reverse:
-
- Inplace reverse:
lst.reverse()
- Inplace reverse:
-
- New List:
lst2 = list(reversed(lst))
- New List:
- List Sorting:
- 1.In-plcae sorting:
lst.sort()
-
- New List:
lst2 = lst1.sort()
- New List:
- Sort method takes two arguments: reverse and key
- Key can be any callable object based on which sorting needa to be performed.
- e.g.
lst.sort(key=len)
will sort based on the len(item).
- Stores key-value pairs.
- Has refrence for both keys and values.
- The key should be immutable so str, int and tuple are accepted and list are not.
- Because the keys are hashed and mutable objects like list can't be hashed.
- Dictionary Copying:
-
- Copy method:
dict2 = dict1.copy()
- Copy method:
-
- Dict constructor: `dict2 = dict(dict1)'
- Copy in dictionary is shallow just like in the list.
- Adding New items in dictionary:
dict1.update({dict2})
- Unordered collection of unique and immutable objects.
- Set is mutable and elements can be added or removed but it's items are immutable as they are hashed to make search faster.
- Because items are immutable, they can't be a list.
- Items can be added using
add()
andupdate()
where later is used for multiple items. - Items can be removed using
remove()
anddiscard()
where the latter doesn't give an error when element is not present. - Shallow Copying: Set supports shallow copying.
- Set Algebra:
-
- Union:
union()
- Union:
-
- Intersection:
intersection()
- Intersection:
-
- Difference:
difference()
- Difference:
-
- Exclusive (in either one but not both):
symmetric_difference()
- Exclusive (in either one but not both):
-
issubset()
-
issuperset()
-
isdisjoint()
- Lists are mutable and Tuples are not.
- New elements can be added to List using append() or extend() but not in Tuple.
- List can be sorted.
- List should be used when the data inside it can be updated. Tuple should be used to keep the data safe from alteration or data corruption.
- Tuple are hashable whereas List are not.
- Hence, Tuple can be used as key of a dictionary.
- Tuples are stored in single block of memory.
- Lists are stored in two blocks of memory: fixed block and variable block.
- Fix block stores the meta data which is the information regarding the object.
- Variable block stores the actual data.
- Tuple refers to it's elements directly whereas List requires an extra layer.
- Tuple stores an array to store pointers of it's element.
- List requires to store a pointer to the array which stores the pointer to the elements.
- Check collectionProtocol.jpg
- It gives mechansim to gracefully handle errors.
- Errors like
IndentationError
,SynataxError
, andNameError
shouldn't be handled inException
. - It is because these errors encompasses the errors caused by programmer's mistakes which should be handled at runtime.
- We can use Exception-Handling to handle an error and then proceed to re-raise the error.
- This way the error is raised like usual but along with that, we can peform little operations like printing our own error message.
- Check: reraiseError.py
- EAFP: It's Easier to Ask Forgiveness than Permission.
-
- It is a philosophy that says error should be handled when encountered and not before.
- LBYL: Look Before You Leap.
-
- It is a philosophy which suggests all possible cases of errors should be found and handled before executing an opertaion.
- Python offers EAFP with Exception-Handling.
- LBYL will require lot of if conditions to check for error before an operation is executed.
- Exception Handling first tries to execute operation and error is handled when generated.
finally
is used aftertry
and all theExcept
.- The code in
finally
is executed no matter iftry
is successful or any one of theExcept
. - Check exceptionHandling.py
- Some code are OS-depenedent and will be different for Windows or Linux or MacOS.
- Such code can be implemented using Try and Except block.
- Check platformSpecificCode.py
- It is an approach to define an iterable.
- It is declarative and functional in style.
- It is readable, expressive, effective and consice.
-
List Comprehension:
[ expr(item) for item in iterable if condition(item) ]
-
Set Comprehension:
{ expr(item) for item in iterable if condition(item) }
Note: Set Comprehension uses `{ }` instead of `( )`
-
Dictionary Comprehension:
{ key_expr: value_expr for item in iterable if condition(item) }
-
Generator Comprehension:
( expr(item) for item in iterable if condition(item) )
Note: Generator Comprehension uses `( )`
- Syntax:
[ expr(item) for item in iterable_object if condition(item)]
>>> even = [i for i in range(1,10) if i%2==0]
- Iterable object can be passed to a built-in iter() function to get an iterator.
>>> a = iter([1,2,3,4,5])
- Iterator object can be passed to a built-in next() funciton to fetch the next item.
>>> first_element = next(a)
>>> second_element = next(a)
[1,2,3,4,5]
is the iterable objecta
is the iterator.- Link: https://stackoverflow.com/questions/16301253/what-exactly-is-pythons-iterator-protocol
- Generators are functions that describe an iterable series.
- It is a
single-use
object. - Any function with
yield
keywoard is a generator. return
keywoard determines the end of the iterator.- All generators are iterbales.
- They are called
lazy-evaluator
because the next value is computed only on demand. - It can provide an infinite sequence with no end.
- They Easily Composable (attached) into pipelines for natural stram processing.
- The generator function returns a generator object.
- A generator can create multiple genreator_object which advances (tracks the progress of iterable_object) independently. Check:
generatorObjectAdvances()
ingenerator.py
. - It can have multiple yield keywoard.
- When next item of generator is demanded, code is just executed uptil the next
yield
statement and not further. - For the next item, code is resumed from the previous
yield
keywoard. CheckresumeExecution()
ingenerator.py
. - Check
generators.py
,factorialGenerator.py
- Generator Functoins stores the state of their variables to execute it the next item is evaluated from the generator object.
- This is done so the generator function can resume the function execution when the next item is evaluated.
- Check: statefulGenerator.py
- Generator Comprehension Syntax:
( expr(item) for item in iterable if condition(item) )
- Advantage of using Generator Comprehension over List Comprehension is it saves a lot of memory as it doesn't compute and store potentiall millions of data in a data structure.
- Disadvantage is items in List can be accessed anytime but in Generator Comprehension, items can be accessed only once.
- Check
Types of Generators
above.
- Every object in Python belongs to some Class.
- Class defines the structure and behaviour of it's object.
- User defined Classes are used when we want to create a new
type
in Python. type(class_object)
andtype(class_name)
both gives the name of the Class it belongs to.
- Method: Function defined within the Class.
- Instance Method: Function which can be called on an object.
- self: name of the first parameter to any and all instance method.
- self is a not a keywoard but is treated as a keywoard.
- Similar to
this
keywoard in Java and C++. - It is a coding standard but not a necessity.
- We can replace the word
self
with any other word to represent the object of a method. - Different methods can have different name as their first parameter.
- Check keywoardSelf.py
- The instance-method calling code
object_name.method_name()
is treated asclass_name.method_name(object_name)
- Hence,
self
parameter is kept in method definition to catch the object been passed. - Check
objectMethodRepresentation
function andneedOfSelf
function fromkeywoardSelf.py
.
- Initalizes the object.
- Should not return anything.
- It is not a constructor as opposed to in Java or C++.
- It is used to configure an item that already exists and it doesn't constructs it.
- Actual
constructor
is provided by the Python Runtime System which checks for the presence of__init__
which is the initializer.
- Limitations of an object that lasts for it's lifetime.
- Assertions can be used to implement Class Invariants.
- However, it is mostly considered non-pythonic and
Type-Hinting
is preffered over it. - Visit: https://stackoverflow.com/questions/40641019/class-invariants-in-python
- It is a concept of OOP-design aimed at reducing the number of coupling.
- It says you should never call method on objects you receive from other calls.
- Basically, only talk to your friends and not friend of friends.
- Check LawOfDemeter.py file.
- In LawOfDemeter.py, instead of allowing the client/user to reach through the object C to access
methodOfC()
method, there is a method created to delegate that task toobjectOfC
.
- Using objects of different types with common interface.
- e.g.
len([1,2,3,4])
andlen("abcd")
have common interface but different working. - Check Duck Typing.
- If it walks like a Duck and swims like a Duck and quack likes a Duck, then it is a Duck.
- In staticly typed language, the compiler decides if an object can be used for a purpose.
- In Python, an objects fitness for any purpose can be determined at run-time.
- If at run-time, it can walk, swim and quack like a Duck, it can be used as a Duck.