X is positive
Lecture 03
Python supports typical if / else style conditional expressions,
This is a fairly unique feature of Python - expressions are grouped together via indenting. This is relevant for control flow (if
, for
, while
, etc.) as well as function and class definitions and many other aspects of the language.
Indents should be 2 or more spaces (4 is generally preferred based on PEP 8) or tab character(s) - generally your IDE will handle this for you.
Conditional expressions do not have their own scope, so variables defined within will be accessible / modified outside of the conditional.
This is also true for other control flow constructs (e.g. for
, while
, etc.)
while
loopsrepeats until the condition expression evaluates to False
,
for
loopsiterates over the elements of a sequence,
break
and continue
allow for either an early loop exit or step to the next iteration respectively,
else
Both for
and while
loops can also include an else
clause which execute when the loop is completes by either fully iterating (for
) or meetings the while
condition, i.e. when break
is not used.
pass
is a placeholder expression that does nothing, it can be used when an expression is needed syntactically.
List comprehensions provides a concise syntax for generating lists (or other sequences) via iteration over another list (or sequence).
if
List comprehensions can include a conditional clause(s) to filter the input list / sequence,
[0, 4, 16, 36, 64]
[1, 9, 25, 49, 81]
for
keywordsSimilarly, the comprehension can also contain multiple for
statements which is equivalent to nested for
loops,
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
zip
Is a useful function for “joining” the elements of multiple sequences (so they can be jointly iterated over),
zip
and length mismatchesThe length of the shortest sequence will be used, additional elements will be ignored (silently)
Using list comprehensions, complete the following tasks:
Create a list containing tuples of x and y coordinates of all points of a regular grid for \(x \in [0, 10]\) and \(y \in [0, 10]\).
Count the number of points where \(y > x\).
Count the number of points \(x\) or \(y\) is prime.
05:00
Functions are defined using def
, arguments can optionally have a default values. (Arguments with defaults must must follow the arguments without defaults)
return
statementsFunctions must explicitly include a return
statement to return a value.
Functions can return multiple values using a tuple or list,
A common practice in Python is to document functions (and other objects) using a doc string - this is a short concise summary of the objects purpose. Docstrings are specified by supplying a string as the very line in the function definition.
max(iterable, *[, default=obj, key=func]) -> value
max(arg1, arg2, *args, *[, key=func]) -> value
With a single iterable argument, return its biggest item. The
default keyword-only argument specifies an object to return if
the provided iterable is empty.
With two or more positional arguments, return the largest argument.
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to 'utf-8'.
errors defaults to 'strict'.
Return a copy of the string converted to lowercase.
In Python the argument order matters - positional arguments must always come before keyword arguments.
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
For the following function x
can only be passed by position and z
only by name
If the number of arguments is unknown / variable it is possible to define variadic functions using *
or **
. The former is for unnamed arguments which will be treated as a tuple
, the latter is for named arguments which will be treated as a dict
.
are defined using the lambda
keyword, they are intended to be used for very short functions (syntactically limited to a single expression, and do not need a return statement)
Python nows supports syntax for providing metadata around the expected type of arguments and the return value of a function.
These annotations are stored in the __annotations__
attribute
kg_to_lb
, that converts a list of weights in kilograms to a list of weights in pounds (there a 1 kg = 2.20462 lbs). Include a doc string and function annotations.total_lb
, that calculates the total weight in pounds of an order, the input arguments should be a list of item weights in kilograms and a list of the number of each item ordered.05:00
These are the basic component of Python’s object oriented system - we’ve been using them regularly all over the place and will now look at how they are defined and used.
When instantiating a class object (e.g. rect()
) we invoke the __init__()
method if it is present in the classes’ definition.
We’ve seen a number of objects (i.e. Pandas DataFrames) that allow for method chaining to construct a pipeline of operations. We can achieve the same by having our class methods return itself via self
.
class rect:
"""An object representing a rectangle"""
# Constructor
def __init__(self, p1 = (0,0), p2 = (1,1)):
self.p1 = p1
self.p2 = p2
# Methods
def area(self):
return ((self.p1[0] - self.p2[0]) *
(self.p1[1] - self.p2[1]))
def set_p1(self, p1):
self.p1 = p1
return self
def set_p2(self, p2):
self.p2 = p2
return self
All class objects have a default print method / string conversion method, but the default behavior is not very useful,
Both of the above are handled by the __str__()
method which is implicitly created for our class - we can override this,
There is another special method which is responsible for the printing the object (see rect()
above) called __repr__()
which is responsible for printing the classes representation. If possible this is meant to be a valid Python expression capable of recreating the object.
Part of the object oriented system is that classes can inherit from other classes, meaning they gain access to all of their parents attributes and methods. We will not go too in depth on this topic beyond showing the basic functionality.
class square(rect):
def __init__(self, p1=(0,0), l=1):
assert isinstance(l, (float, int)), \
"l must be a numnber"
p2 = (p1[0]+l, p1[1]+l)
self.l = l
super().__init__(p1, p2)
def set_p1(self, p1):
self.p1 = p1
self.p2 = (self.p1[0]+self.l, self.p1[1]+self.l)
return self
def set_p2(self, p2):
raise RuntimeError("Squares take l not p2")
def set_l(self, l):
assert isinstance(l, (float, int)), \
"l must be a numnber"
self.l = l
self.p2 = (self.p1[0]+l, self.p1[1]+l)
return self
def __repr__(self):
return f"square({self.p1}, {self.l})"
We can examine all of a classes’ methods and attributes using dir()
,
[['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__firstlineno__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__static_attributes__', '__str__', '__subclasshook__', '__weakref__', 'area', 'set_p1', 'set_p2']]
Where did p1
and p2
go?
[['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__firstlineno__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__static_attributes__', '__str__', '__subclasshook__', '__weakref__', 'area', 'p1', 'p2', 'set_p1', 'set_p2']]
Sta 663 - Spring 2025