Fast and basic Python introduction#

Prepared by G. Aznar Siguan

Most of the examples come from the official Python tutorial: https://docs.python.org/3/tutorial/

Contents#

Numbers and Strings#

The operators +, -, * and / work just like in most other languages:

[1]:
print('Addition: 2 + 2 =', 2 + 2)
print('Substraction: 50 - 5*6 =', 50 - 5*6)
print('Use of parenthesis: (50 - 5*6) / 4 =', (50 - 5*6) / 4)
print('Classic division returns a float: 17 / 3 =', 17 / 3)
print('Floor division discards the fractional part: 17 // 3 =', 17 // 3)
print('The % operator returns the remainder of the division: 17 % 3 =', 17 % 3)
print('Result * divisor + remainder: 5 * 3 + 2 =', 5 * 3 + 2)
print('5 squared: 5 ** 2 =', 5 ** 2)
print('2 to the power of 7: 2 ** 7 =', 2 ** 7)
Addition: 2 + 2 = 4
Substraction: 50 - 5*6 = 20
Use of parenthesis: (50 - 5*6) / 4 = 5.0
Classic division returns a float: 17 / 3 = 5.666666666666667
Floor division discards the fractional part: 17 // 3 = 5
The % operator returns the remainder of the division: 17 % 3 = 2
Result * divisor + remainder: 5 * 3 + 2 = 17
5 squared: 5 ** 2 = 25
2 to the power of 7: 2 ** 7 = 128

The integer numbers (e.g. 2, 4, 20) have type int, the ones with a fractional part (e.g. 5.0, 1.6) have type float. Operators with mixed type operands convert the integer operand to floating point:

[2]:
tax = 12.5 / 100
price = 100.50
price * tax
[2]:
12.5625

Strings can be enclosed in single quotes (‘…’) or double quotes (“…”) with the same result.  can be used to escape quotes.

If you don’t want characters prefaced by  to be interpreted as special characters, you can use raw strings by adding an r before the first quote.

[3]:
print('spam eggs')  # single quotes
print('doesn\'t')   # use \' to escape the single quote...
print("doesn't")    # ...or use double quotes instead
print('"Yes," he said.')
print("\"Yes,\" he said.")
print('"Isn\'t," she said.')
spam eggs
doesn't
doesn't
"Yes," he said.
"Yes," he said.
"Isn't," she said.

Strings can be indexed (subscripted), with the first character having index 0.

Indices may also be negative numbers, to start counting from the right. Note that since -0 is the same as 0, negative indices start from -1.

[4]:
word = 'Python'
print('word = ', word)
print('Character in position 0: word[0] =', word[0])
print('Character in position 5: word[5] =', word[5])
print('Last character: word[-1] =', word[-1])
print('Second-last character: word[-2] =', word[-2])
print('word[-6] =', word[-6])
word =  Python
Character in position 0: word[0] = P
Character in position 5: word[5] = n
Last character: word[-1] = n
Second-last character: word[-2] = o
word[-6] = P

In addition to indexing, slicing is also supported. While indexing is used to obtain individual characters, slicing allows you to obtain substring:

[5]:
print('Characters from position 0 (included) to 2 (excluded): word[0:2] =', word[0:2])
print('Characters from position 2 (included) to 5 (excluded): word[2:5] =', word[2:5])
Characters from position 0 (included) to 2 (excluded): word[0:2] = Py
Characters from position 2 (included) to 5 (excluded): word[2:5] = tho

Lists#

Lists can be written as a list of comma-separated values (items) between square brackets. Lists might contain items of different types, but usually the items all have the same type.

Like strings (and all other built-in sequence type), lists can be indexed and sliced:

[6]:
squares = [1, 4, 9, 16, 25]
print('squares: ', squares)
print('Indexing returns the item: squares[0]:', squares[0])
print('squares[-1]:', squares[-1])
print('Slicing returns a new list: squares[-3:]:', squares[-3:])
print('squares[:]:', squares[:])
squares:  [1, 4, 9, 16, 25]
Indexing returns the item: squares[0]: 1
squares[-1]: 25
Slicing returns a new list: squares[-3:]: [9, 16, 25]
squares[:]: [1, 4, 9, 16, 25]

Lists also support operations like concatenation:

[7]:
squares + [36, 49, 64, 81, 100]
[7]:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Unlike strings, which are immutable, lists are a mutable type, i.e. it is possible to change their content:

[8]:
cubes = [1, 8, 27, 65, 125]  # something's wrong here
cubes[3] = 64  # replace the wrong value
cubes.append(216)  # add the cube of 6
cubes.append(7 ** 3)  # and the cube of 7
cubes
[8]:
[1, 8, 27, 64, 125, 216, 343]
[9]:
# Note: execution of this cell will fail

# Try to modify a character of a string
word = 'Python'
word[0] = 'p'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[9], line 5
      1 # Note: execution of this cell will fail
      2
      3 # Try to modify a character of a string
      4 word = 'Python'
----> 5 word[0] = 'p'

TypeError: 'str' object does not support item assignment

List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.

[10]:
squares = []
for x in range(10):
    squares.append(x**2)
squares
[10]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[11]:
# lambda functions: functions that are not bound to a name, e.g lambda x: x**2
# Map applies a function to all the items in an input_list: map(function_to_apply, list_of_inputs)
squares = list(map(lambda x: x**2, range(10)))
squares
[11]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[12]:
squares = [x**2 for x in range(10)]
squares
[12]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Tuples#

A tuple consists of a number of values separated by commas, for instance:

[13]:
t = 12345, 54321, 'hello!'
t[0]
[13]:
12345
[14]:
t
[14]:
(12345, 54321, 'hello!')
[15]:
# Tuples may be nested:
u = t, (1, 2, 3, 4, 5)
u
[15]:
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
[16]:
# Note: execution of this cell will fail

# Tuples are immutable:
t[0] = 88888
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[16], line 4
      1 # Note: execution of this cell will fail
      2
      3 # Tuples are immutable:
----> 4 t[0] = 88888

TypeError: 'tuple' object does not support item assignment
[17]:
# but they can contain mutable objects:
v = ([1, 2, 3], [3, 2, 1])
v
[17]:
([1, 2, 3], [3, 2, 1])

Tuples are immutable, and usually contain a heterogeneous sequence of elements that are accessed via unpacking or indexing. Lists are mutable, and their elements are usually homogeneous and are accessed by iterating over the list.

[18]:
t = 12345, 54321, 'hello!' # tuple packing
x, y, z = t # tuple unpacking
x, y, z
[18]:
(12345, 54321, 'hello!')

Sets#

A set is an unordered collection with no duplicate elements. Basic uses include membership testing and eliminating duplicate entries. Set objects also support mathematical operations like union, intersection, difference, and symmetric difference.

Curly braces or the set() function can be used to create sets.

[19]:
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
basket # show that duplicates have been removed
[19]:
{'apple', 'banana', 'orange', 'pear'}
[20]:
'orange' in basket # fast membership testing
[20]:
True
[21]:
'crabgrass' in basket
[21]:
False
[22]:
# Demonstrate set operations on unique letters from two words
a = set('abracadabra')
b = set('alacazam')
a # unique letters in a
[22]:
{'a', 'b', 'c', 'd', 'r'}
[23]:
a - b # letters in a but not in b
[23]:
{'b', 'd', 'r'}
[24]:
a | b # letters in a or b or both
[24]:
{'a', 'b', 'c', 'd', 'l', 'm', 'r', 'z'}
[25]:
a & b # letters in both a and b
[25]:
{'a', 'c'}
[26]:
a ^ b # letters in a or b but not both
[26]:
{'b', 'd', 'l', 'm', 'r', 'z'}
[27]:
# check set documentation
help(set)
Help on class set in module builtins:

class set(object)
 |  set() -> new empty set object
 |  set(iterable) -> new set object
 |
 |  Build an unordered collection of unique elements.
 |
 |  Methods defined here:
 |
 |  __and__(self, value, /)
 |      Return self&value.
 |
 |  __contains__(...)
 |      x.__contains__(y) <==> y in x.
 |
 |  __eq__(self, value, /)
 |      Return self==value.
 |
 |  __ge__(self, value, /)
 |      Return self>=value.
 |
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |
 |  __gt__(self, value, /)
 |      Return self>value.
 |
 |  __iand__(self, value, /)
 |      Return self&=value.
 |
 |  __init__(self, /, *args, **kwargs)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |
 |  __ior__(self, value, /)
 |      Return self|=value.
 |
 |  __isub__(self, value, /)
 |      Return self-=value.
 |
 |  __iter__(self, /)
 |      Implement iter(self).
 |
 |  __ixor__(self, value, /)
 |      Return self^=value.
 |
 |  __le__(self, value, /)
 |      Return self<=value.
 |
 |  __len__(self, /)
 |      Return len(self).
 |
 |  __lt__(self, value, /)
 |      Return self<value.
 |
 |  __ne__(self, value, /)
 |      Return self!=value.
 |
 |  __or__(self, value, /)
 |      Return self|value.
 |
 |  __rand__(self, value, /)
 |      Return value&self.
 |
 |  __reduce__(...)
 |      Return state information for pickling.
 |
 |  __repr__(self, /)
 |      Return repr(self).
 |
 |  __ror__(self, value, /)
 |      Return value|self.
 |
 |  __rsub__(self, value, /)
 |      Return value-self.
 |
 |  __rxor__(self, value, /)
 |      Return value^self.
 |
 |  __sizeof__(...)
 |      S.__sizeof__() -> size of S in memory, in bytes
 |
 |  __sub__(self, value, /)
 |      Return self-value.
 |
 |  __xor__(self, value, /)
 |      Return self^value.
 |
 |  add(...)
 |      Add an element to a set.
 |
 |      This has no effect if the element is already present.
 |
 |  clear(...)
 |      Remove all elements from this set.
 |
 |  copy(...)
 |      Return a shallow copy of a set.
 |
 |  difference(...)
 |      Return the difference of two or more sets as a new set.
 |
 |      (i.e. all elements that are in this set but not the others.)
 |
 |  difference_update(...)
 |      Remove all elements of another set from this set.
 |
 |  discard(...)
 |      Remove an element from a set if it is a member.
 |
 |      If the element is not a member, do nothing.
 |
 |  intersection(...)
 |      Return the intersection of two sets as a new set.
 |
 |      (i.e. all elements that are in both sets.)
 |
 |  intersection_update(...)
 |      Update a set with the intersection of itself and another.
 |
 |  isdisjoint(...)
 |      Return True if two sets have a null intersection.
 |
 |  issubset(...)
 |      Report whether another set contains this set.
 |
 |  issuperset(...)
 |      Report whether this set contains another set.
 |
 |  pop(...)
 |      Remove and return an arbitrary set element.
 |      Raises KeyError if the set is empty.
 |
 |  remove(...)
 |      Remove an element from a set; it must be a member.
 |
 |      If the element is not a member, raise a KeyError.
 |
 |  symmetric_difference(...)
 |      Return the symmetric difference of two sets as a new set.
 |
 |      (i.e. all elements that are in exactly one of the sets.)
 |
 |  symmetric_difference_update(...)
 |      Update a set with the symmetric difference of itself and another.
 |
 |  union(...)
 |      Return the union of sets as a new set.
 |
 |      (i.e. all elements that are in either set.)
 |
 |  update(...)
 |      Update a set with the union of itself and others.
 |
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |
 |  __class_getitem__(...) from builtins.type
 |      See PEP 585
 |
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  __hash__ = None

[28]:
# check which methods can be applied on set
dir(set)
[28]:
['__and__',
 '__class__',
 '__class_getitem__',
 '__contains__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__iand__',
 '__init__',
 '__init_subclass__',
 '__ior__',
 '__isub__',
 '__iter__',
 '__ixor__',
 '__le__',
 '__len__',
 '__lt__',
 '__ne__',
 '__new__',
 '__or__',
 '__rand__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__ror__',
 '__rsub__',
 '__rxor__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__sub__',
 '__subclasshook__',
 '__xor__',
 'add',
 'clear',
 'copy',
 'difference',
 'difference_update',
 'discard',
 'intersection',
 'intersection_update',
 'isdisjoint',
 'issubset',
 'issuperset',
 'pop',
 'remove',
 'symmetric_difference',
 'symmetric_difference_update',
 'union',
 'update']
[29]:
# Define a new set and try some set methods (freestyle)

Dictionaries#

Unlike sequences, which are indexed by a range of numbers, dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys.

It is best to think of a dictionary as an unordered set of key: value pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: {}. Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the dictionary; this is also the way dictionaries are written on output.

[30]:
tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127
tel
[30]:
{'jack': 4098, 'sape': 4139, 'guido': 4127}
[31]:
tel['jack']
[31]:
4098
[32]:
del tel['sape']
[33]:
tel['irv'] = 4127
tel
[33]:
{'jack': 4098, 'guido': 4127, 'irv': 4127}
[34]:
list(tel.keys())
[34]:
['jack', 'guido', 'irv']
[35]:
sorted(tel.keys())
[35]:
['guido', 'irv', 'jack']
[36]:
'guido' in tel
[36]:
True
[37]:
'jack' not in tel
[37]:
False

Functions#

We can create a function that writes the Fibonacci series to an arbitrary boundary:

[38]:
def fib(n):    # write Fibonacci series up to n
     """Print a Fibonacci series up to n."""
     a, b = 0, 1            # two assignments in one line
     while a < n:
         print(a, end=' ')
         a, b = b, a+b      # two assignments in one line
     print()
[39]:
# Now call the function we just defined:
fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

The value of the function name has a type that is recognized by the interpreter as a user-defined function. This value can be assigned to another name which can then also be used as a function. This serves as a general renaming mechanism:

[40]:
print(fib)
print(type(fib)) # function type
f = fib
f(100)
<function fib at 0x7f4313cefb80>
<class 'function'>
0 1 1 2 3 5 8 13 21 34 55 89

Be careful when using mutable types as inputs in functions, as they might be modified:

[41]:
def dummy(x):
    x += x

xx = 5
print('xx before function call: ', xx)
dummy(xx)
print('xx after function call: ', xx)

yy = [5]
print('yy before function call: ', yy)
dummy(yy)
print('yy after function call: ', yy)
xx before function call:  5
xx after function call:  5
yy before function call:  [5]
yy after function call:  [5, 5]

Default argument values:#

The most useful form is to specify a default value for one or more arguments. This creates a function that can be called with fewer arguments than it is defined to allow. For example:

[42]:
def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)
[43]:
#This function can be called in several ways:

#giving only the mandatory argument:
ask_ok('Do you really want to quit?')

---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
Cell In[43], line 4
      1 #This function can be called in several ways:
      2
      3 #giving only the mandatory argument:
----> 4 ask_ok('Do you really want to quit?')

Cell In[42], line 3, in ask_ok(prompt, retries, reminder)
      1 def ask_ok(prompt, retries=4, reminder='Please try again!'):
      2     while True:
----> 3         ok = input(prompt)
      4         if ok in ('y', 'ye', 'yes'):
      5             return True

File ~/checkouts/readthedocs.org/user_builds/climada-python/conda/v3.3.0/lib/python3.9/site-packages/ipykernel/kernelbase.py:1172, in Kernel.raw_input(self, prompt)
   1165 """Forward raw_input to frontends
   1166
   1167 Raises
   1168 ------
   1169 StdinNotImplementedError if active frontend doesn't support stdin.
   1170 """
   1171 if not self._allow_stdin:
-> 1172     raise StdinNotImplementedError(
   1173         "raw_input was called, but this frontend does not support input requests."
   1174     )
   1175 return self._input_request(
   1176     str(prompt),
   1177     self._parent_ident["shell"],
   1178     self.get_parent("shell"),
   1179     password=False,
   1180 )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
[44]:
# giving one of the optional arguments:
ask_ok('OK to overwrite the file?', 2)

---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
Cell In[44], line 2
      1 # giving one of the optional arguments:
----> 2 ask_ok('OK to overwrite the file?', 2)

Cell In[42], line 3, in ask_ok(prompt, retries, reminder)
      1 def ask_ok(prompt, retries=4, reminder='Please try again!'):
      2     while True:
----> 3         ok = input(prompt)
      4         if ok in ('y', 'ye', 'yes'):
      5             return True

File ~/checkouts/readthedocs.org/user_builds/climada-python/conda/v3.3.0/lib/python3.9/site-packages/ipykernel/kernelbase.py:1172, in Kernel.raw_input(self, prompt)
   1165 """Forward raw_input to frontends
   1166
   1167 Raises
   1168 ------
   1169 StdinNotImplementedError if active frontend doesn't support stdin.
   1170 """
   1171 if not self._allow_stdin:
-> 1172     raise StdinNotImplementedError(
   1173         "raw_input was called, but this frontend does not support input requests."
   1174     )
   1175 return self._input_request(
   1176     str(prompt),
   1177     self._parent_ident["shell"],
   1178     self.get_parent("shell"),
   1179     password=False,
   1180 )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
[45]:
# or even giving all arguments:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
Cell In[45], line 2
      1 # or even giving all arguments:
----> 2 ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

Cell In[42], line 3, in ask_ok(prompt, retries, reminder)
      1 def ask_ok(prompt, retries=4, reminder='Please try again!'):
      2     while True:
----> 3         ok = input(prompt)
      4         if ok in ('y', 'ye', 'yes'):
      5             return True

File ~/checkouts/readthedocs.org/user_builds/climada-python/conda/v3.3.0/lib/python3.9/site-packages/ipykernel/kernelbase.py:1172, in Kernel.raw_input(self, prompt)
   1165 """Forward raw_input to frontends
   1166
   1167 Raises
   1168 ------
   1169 StdinNotImplementedError if active frontend doesn't support stdin.
   1170 """
   1171 if not self._allow_stdin:
-> 1172     raise StdinNotImplementedError(
   1173         "raw_input was called, but this frontend does not support input requests."
   1174     )
   1175 return self._input_request(
   1176     str(prompt),
   1177     self._parent_ident["shell"],
   1178     self.get_parent("shell"),
   1179     password=False,
   1180 )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.

Functions can also be called using keyword arguments of the form kwarg=value:

[46]:
ask_ok('OK to overwrite the file?', reminder='Come on, only yes or no!')
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
Cell In[46], line 1
----> 1 ask_ok('OK to overwrite the file?', reminder='Come on, only yes or no!')

Cell In[42], line 3, in ask_ok(prompt, retries, reminder)
      1 def ask_ok(prompt, retries=4, reminder='Please try again!'):
      2     while True:
----> 3         ok = input(prompt)
      4         if ok in ('y', 'ye', 'yes'):
      5             return True

File ~/checkouts/readthedocs.org/user_builds/climada-python/conda/v3.3.0/lib/python3.9/site-packages/ipykernel/kernelbase.py:1172, in Kernel.raw_input(self, prompt)
   1165 """Forward raw_input to frontends
   1166
   1167 Raises
   1168 ------
   1169 StdinNotImplementedError if active frontend doesn't support stdin.
   1170 """
   1171 if not self._allow_stdin:
-> 1172     raise StdinNotImplementedError(
   1173         "raw_input was called, but this frontend does not support input requests."
   1174     )
   1175 return self._input_request(
   1176     str(prompt),
   1177     self._parent_ident["shell"],
   1178     self.get_parent("shell"),
   1179     password=False,
   1180 )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.

Default None values: None default values can be used to handle optional parameters.

[47]:
def test(x=None):
    if x is None:
        print('no x here')
    else:
        print(x)
test()
no x here

Objects#

Example class definition:

[48]:
class Dog:                    # same as "class Dog(object)"

    kind = 'canine'           # class variable shared by all instances

    def __init__(self, name): # initialization method
        self.name = name      # instance variable unique to each instance
        self.tricks = []      # creates a new empty list for each dog

    def add_trick(self, trick):   # class method
        self.tricks.append(trick)

When a class defines an _init_() method, class instantiation automatically invokes _init_() for the newly-created class instance:

[49]:
d = Dog('Fido') # creates a new instance of the class and assigns this object to the local variable d
d.name
[49]:
'Fido'
[50]:
e = Dog('Buddy') # creates a new instance of the class and assigns this object to the local variable e
d.add_trick('roll over')
e.add_trick('play dead')
[51]:
d.tricks # unique to d
[51]:
['roll over']
[52]:
e.tricks # unique to e
[52]:
['play dead']
[53]:
d.kind # shared by all dogs
[53]:
'canine'
[54]:
e.kind # shared by all dogs
[54]:
'canine'

Inheritance:#

The syntax for a derived class definition looks like this:

class DerivedClassName(BaseClassName)

A derived class can override any methods of its base class or classes, and a method can call the method of a base class with the same name. Example:

[55]:
class Animal:         # base class

    def __init__(self, kind):
        self.kind = kind
        self.tricks = []

    def add_trick(self, trick):   # class method
        self.tricks.append(trick)

class Dog(Animal):   # derived class

    def __init__(self): # override of __init__ base method
        super(Dog, self).__init__('canine') # call Animal __init__ method with input string
[56]:
fido = Dog() # fido is automatically an animal of kind 'canine'
print(fido.kind)
fido.add_trick('play dead') # Dog class can use Animal class
print(fido.tricks)
canine
['play dead']

Python supports a form of multiple inheritance as well. A class definition with multiple base classes looks like this:

class DerivedClassName(Base1, Base2, Base3):

Private Variables and Methods:#

“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: 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).

Example of internal class use of private method __update. The user is not meant to use __update, but update. However, __update can be used internally to be called from the __init__ method:

[57]:
class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)