class MyClass:
= 55
x = "Allie Trent"
name = ["Bones", "Food", "Frisbee"] attr_list
Python Fundamentals
Python Fundamentals
Concepts and methods on the fundamentals of Python.
Modules & Methods
Modules contain a “library” of methods
Object Oriented Programming (OOP)
Classes
Consists of attributes and methods
Example: Car
Attributes: fuel, max speed, color
Method (function): refuel(), setSpeed()
Methods create attributes for classes
Creating a class
MyClass.name
'Allie Trent'
Methods in a class
class Methods_Class:
= "Hello World"
x
def my_method():
print("Contents of my_method")
def subtractor(num_one, num_two):
= num_one - num_two
product print(f"{num_two} - {num_one} = {product}")
def print_stuff(a, b):
print(a, b)
print(Methods_Class)
print(Methods_Class.x)
print(Methods_Class.my_method)
print(Methods_Class.my_method())
print(Methods_Class.subtractor(20, 5))
print(Methods_Class.print_stuff(3, "Hello"))
<class '__main__.Methods_Class'>
Hello World
<function Methods_Class.my_method at 0xffffab79b400>
Contents of my_method
None
5 - 20 = 15
None
3 Hello
None
__init__
Function defined at the start of a class
class Animals:
def __init__(self, size, noise, color, num_of_legs):
self.size = size
self.noise = noise
self.color = color
self.num_of_legs = num_of_legs
= Animals("Large", "Woof", "Liver & White", 4)
dog dog
<__main__.Animals at 0xffffab81e590>
dog.noise
'Woof'
Using attributes in a method
class Animals:
def __init__(self, species, name, noise, color):
self.species = species
self.name = name
self.noise = noise
self.color = color
def describe(self):
print(f"{self.name} is {self.color} which makes a {self.noise} noise")
= Animals("Dog", "Allie", "Woof", "Liver & White")
dog = Animals("Cat", "Misty", "Meow", "Black") cat
dog.describe()
Allie is Liver & White which makes a Woof noise
Changing variable names in a class object
class Ages:
def __init__(self, age):
self.age = age
def plus_year(self):
self.age += 1
def show_age(self):
print(f"Your age is {self.age}")
= Ages(27) me
me.plus_year() me.show_age()
Your age is 28
class Warrior:
def __init__(self, name, strength, health):
self.name = name
self.strength = strength
self.health = health
def report(self):
print(f"Hi {self.name}, your strength is {self.strength} and health is {self.health}")
def heal(self):
self.health += 1
def damage(self):
self.health -= 1
def workout(self):
self.strength += 1
= Warrior("Geocoug", 60, 100) character
for i in range(8)]
[character.damage()
character.report()for i in range(5)]
[character.heal()
character.report()
character.workout() character.report()
Hi Geocoug, your strength is 60 and health is 92
Hi Geocoug, your strength is 60 and health is 97
Hi Geocoug, your strength is 61 and health is 97
Practical Example - PayFriend
Create an online bank where: - User can create a new account that includes: Account type (current, savings, etc), name of account holder, account balance, etc. - User can withdraw or deposit money, or check balance
class Banking:
def __init__(self, name, account, balance):
self.name = name
self.account = account
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
def report(self):
print(f"{self.name}, the balance of {self.account} is ${self.balance}")
= Banking("Geocoug", "Savings", 1000) my_account
50)
my_account.deposit(
my_account.report()500)
my_account.withdraw( my_account.report()
Geocoug, the balance of Savings is $1050
Geocoug, the balance of Savings is $550
Functional Programming
Lambda
Quicker way of creating functions
def some_func(x):
= x + 2
y
lambda x: x + 2
<function __main__.<lambda>(x)>
= lambda x: x + 2
lambda_func 6) lambda_func(
8
= lambda name: f"Hello there, {name}"
other_func "Geocoug") other_func(
'Hello there, Geocoug'
= lambda x, y: x + y
another_func 3, 4) another_func(
7
Map
Apply the same function/operation on all elements in a list
map(name of function, name of list)
# using map as a normal function
= [1, 10, 20, 15]
somelist
def divider(x):
= x / 5
y return y
= list(map(divider, somelist))
newlist newlist
[0.2, 2.0, 4.0, 3.0]
= [1, 10, 20, 15]
somelist = list(map(lambda x: x / 5, somelist))
newlist newlist
[0.2, 2.0, 4.0, 3.0]
= (1, 10, 20, 15)
num_tuple = tuple(map(lambda x: x / 5, num_tuple))
new_tuple new_tuple
(0.2, 2.0, 4.0, 3.0)
= [1, 2, 3, 4]
list_one = [90, 80, 70, 60]
list_two
= map(lambda x, y: x + y, list_one, list_two)
new_list list(new_list)
[91, 82, 73, 64]
Filter
= [1, 14, 53, 72, 22, 99]
my_list = filter(lambda x: x >= 50, my_list)
filtered_list list(filtered_list)
[53, 72, 99]
Generators
Generators - yield
instead of return. Return terminates local variables, yield ‘pauses’.
See - How do python generators work?
def a():
= 5
x yield x
a()
<generator object a at 0xffffab9637d0>
def a():
= 5
x yield x
+= 1
x yield x
= a()
example print(next(example))
print(next(example))
print(next(example))
5
6
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) Cell In[30], line 9 7 print(next(example)) 8 print(next(example)) ----> 9 print(next(example)) StopIteration:
def generator_fn(x):
for i in range(x):
yield i
import sys
# bytes sys.getsizeof(example)
104
= generator_fn(100_000_000) g
dir(g)
['__class__',
'__del__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__lt__',
'__name__',
'__ne__',
'__new__',
'__next__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'close',
'gi_code',
'gi_frame',
'gi_running',
'gi_yieldfrom',
'send',
'throw']
next(g)
0
next(g)
1
next(g)
2
help(g)
Help on generator object:
generator_fn = class generator(object)
| Methods defined here:
|
| __del__(...)
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __next__(self, /)
| Implement next(self).
|
| __repr__(self, /)
| Return repr(self).
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(value)
| throw(type[,value[,tb]])
|
| Raise exception in generator, return next yielded value or raise
| StopIteration.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| gi_code
|
| gi_frame
|
| gi_running
|
| gi_yieldfrom
| object being iterated by yield from, or None
Nested Generators
def inner():
print("We're inside")
= yield 2
value print("Received", value)
return 4
def outer():
yield 1
= yield from inner()
retval print("Returned", retval)
yield 5
= outer() g
next(g)
1
next(g)
We're inside
2
3) g.send(
Received 3
Returned 4
5
Generator vs. List Comprehension
import time
= 100_000_000 n
= time.time()
start = [i * i for i in range(n)]
x = time.time()
end print(type(x))
print(f"{end - start:.4f}")
<class 'list'>
4.3685
= time.time()
start = (i * i for i in range(n))
g = time.time()
end print(type(g))
print(f"{end - start:.4f}")
<class 'generator'>
0.0001