This is the last part of a 3 part exploration trip into Python. I wrote this for any programmer coming from a C-style language to highlight all the basic features and syntax of the language. Hopefully, someone reading this will save some time from reading the excellent but a bit lengthy official language tour.
# Simple exception handling try: x = int(input("Please enter a number: ")) break except ValueError: print("Not a number") # Catch multiple exceptions at once try: x = int(input("Please enter a number: ")) break except (RuntimeError, TypeError, NameError): print("Something went wrong") # `Else` contains code to be executed if `try` does not raise an exception try: f = open(arg, 'r') except OSError: print('Cannot open file') else: print(arg, 'has', len(f.readlines()), 'lines') f.close()
Except clause may specify a variable after the exception name. The variable is bound to an exception instance with the arguments stored in
try: raise Exception('spam', 'eggs') # Use `raise` to throw an exception except Exception as inst: print(type(inst)) # <class 'Exception'> print(inst.args) # ('spam', 'eggs') print(inst) # ('spam', 'eggs') x, y = inst.args print('x =', x) # x = spam print('y =', y) # y = eggs
finally clause is intended to define clean-up actions that must be executed under all circumstances.
try: result = x / y except ZeroDivisionError: print("Division by zero!") else: print("Result is", result) finally: print("This will be executed at all cases.")
class MyClass: """A simple example class""" i = 12345 def f(self): return 'hello world'
class MyClass: def __init__(self): print('Hello world') x = MyClass()
Instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class.
class Dog: kind = 'canine' # class variable shared by all instances def __init__(self, name): self.name = name # instance variable unique to each instance d = Dog('Fido') e = Dog('Buddy') d.kind # 'canine' e.kind # 'canine' d.name # 'Fido' (unique to d) e.name # 'Buddy' (unique to e)
Shared data can have possibly surprising effects with involving mutable objects such as lists and dictionaries. For example, if want to save the tricks list for each Dog, we should not use a class variable, but declare an instance variable:
class Dog: def __init__(self, name): self.name = name self.tricks =  # creates a new empty list for each dog def add_trick(self, trick): self.tricks.append(trick) d = Dog('Fido') e = Dog('Buddy') d.add_trick('roll over') e.add_trick('play dead') d.tricks # ['roll over'] e.tricks # ['play dead']
Used for resolving attribute references: if a requested attribute is not found in the class, the search proceeds to look in the base class. This rule is applied recursively if the base class itself is derived from some other class.
class DerivedClassName(modname.BaseClassName): [...]
Python supports a form of multiple inheritance. The search for attributes inherited from a parent class as depth-first, left-to-right, not searching twice in the same class where there is an overlap in the hierarchy.
# If an attribute is not found in DerivedClassName, it is searched for in Base1, # then (recursively) in the base classes of Base1, and if it was not found # there, it was searched for in Base2, and so on. class DerivedClassName(Base1, Base2, Base3): [...]
“Private” instance variables don’t exist in Python. However, there is a convention: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method, or a data member).
class MyClass: def __init__(self, name): self._name = name
Defines the method
__next__() which accesses elements in the container one at a time. When no more elements,
__next__() raises a
StopIteration exception. You can call the
__next__() method using the
next() built-in function (or use a
class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def __next__(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] rev = Reverse('spam') for char in rev: print(char)
Generators are a tool for creating iterators. They look like regular functions but use the
yield statement whenever they want to return data. Each time
next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed).
def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index]
Hopefully, this was a gently intro to the language. Happy coding (and learning) in Python!