Advanced Python (Fall 2017)/lecture3
Lecture 3
More scope (classes)
NB! Even though classes in python work as a namespace with their own scope, you should use modules (i.e .py files) instead of classes for this purpose.
Classes in python create their own scope. Symbols defined outside the class are available from inside the class.
MY_CONSTANT = 'constant outside of the class'
class MyClass():
print(MY_CONSTANT)
print('lines in my_class are executed')
def my_function():
print('my_function called')
my_function()
this prints
constant outside of the class lines in my_class are executed my_function called
NB! Even though classes in python work as a namespace with their own scope, you should use modules (i.e .py files) instead of classes for this purpose.
Symbols defined in the class are available outside the class using the class name as a namespace
class A:
my_variable = 'hi'
def my_function():
print('my_function called')
print(A.my_variable)
A.my_function()
NB! Even though classes in python work as a namespace with their own scope, you should use modules (i.e .py files) instead of classes for this purpose.
Classes in python should be used as a constructor for objects. like in this example. An object is created when the class is called.
methods in a class take a first argument called 'self'. This argument is added implicitly when the method is called, but needs to be added explicitly when the method is defined. 'self' refers to the instance (i.e the new object created when the class is called). See: https://julien.danjou.info/blog/2013/guide-python-static-class-abstract-methods
class MyClass():
A = 'class variable'
def __init__(self, c):
self.c = c # instance variable
def my_method(self):
"""
methods can only be called on the instance of the class.
So this will work:
`MyClass(4).my_method() # prints 4`
But this will not work:
`MyClass.my_method() # raises Error`
self refers to the instance. The instance has the attributes of the class including:
- class variables (i.e `self.A`)
- class methods (i.e. `self.my_class_method()`)
- static methods (i.e. `self.my_static_method()`)
and self also has attributes of the instance including:
instance variables (i.e. `self.c`)
instanct methods (i.e. `self.my_method`)
"""
print(self.c)
@classmethod
def my_class_method(cls):
"""
cls refers to the class. It has attributes of the class, including:
- class variables (i.e `self.A`)
- class methods (i.e. `self.my_class_method()`)
- static methods (i.e. `self.my_static_method()`)
"""
print(cls.A)
@staticmethod
def my_static_method():
"""
static methods work like a regular function that is not in a class.
They do not have access to variables and methods in the class or the instance.
They are only in the class for organizational reasons, and may be better
outside the class.
"""
print('static method called')
print(MyClass.A) # prints 'class variable'
MyClass.my_class_method() # prints 'class variable'
MyClass.my_static_method() # prints 'static method called'
my_instance = MyClass('my instance variable')
my_instance.my_class_method() # prints 'class variable'
print(my_instance.c) # prints 'my instance variable'
my_instance.my_method() # prints 'my instance variable'
my_instance.my_static_method() # prints 'static method called'
Generators
First we must learn about while loops. For iterating and counting, for
is superior. They are simple and usually only used in the following way:
while True:
do_something()
if some_condition:
break
Task 1
NOTE: you most likely will not need to write generators in your python code. iterate through a list using a while and print every element
"""
You should use a `for` loop instead in real world situations.
This is just for teaching about `while`
"""
MY_NAMES = ['hi', 'bye', 'peep']
for i in MY_NAMES:
print(i)
i = 0
while i < len(MY_NAMES):
print(MY_NAMES[i])
i += 1
A generator is a special object in python that can be iterated over, but each item in the iteration is generated lazily. That means it does not know the next element until it has been evaluated.
yield
is similar to return, as in the value yielded is used the next item in the generator. But yield
does not stop the execution of the function.
Here are some examples:
def my_generator_1():
yield 1
yield 2
yield 3
for i in my_generator_1():
print(i)
# 1
# 2
# 3
print(list(my_generator_1()))
# [1, 2, 3]
def my_generator_2():
for i in range(10, 0, -1):
yield i
print(list(my_generator_2()))
# [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Task 2
implement a range-like function using a generator
def my_function(first, second=None, third=1):
"""
NOTE: this implementation of range fails on negative step values
"""
if second:
stop = second
start = first
else:
stop = first
start = 0
step = third
i = start
while i < stop:
yield i
i += step