domenica 8 novembre 2015

A crash course in Python - Lesson 5: some extra functionalities

Generators

A huge problem with lists is that they can grow really big. By using the following instruction:
L = range(1000000)
we actually create a list containing one million elements! If you only need to deal with one of them at a time, this results in a very inefficient code (supposing that you are able to fit the list in memory... if not, you are in trouble).

To overcome this problem, one can use generators. A generator is something that you can iterate over (e.g., by using a for loop) so that values are produced in a lazy manner, i.e., only when needed.

The creation of a generator resembles the creation of a list, with the only difference that elements are not materialized: we only suggest to the generator how to create the next elements when one need to use them.
To create a generator, one can use the following method:

def lazy_range(N):
    i = 0
    while i < N
        yield i
        i += 1

In this way, the yielded values are consumed one at a time, until none are left. The iteration over the generator is identical to the one we use over lists:

for i in lazy_range(10):
    do_something(i)

Actually, Python comes with a "lazy range function" as the one reported above, called xrange. Moreover, in Python 3 the function range is lazy itself.

By using generators, one could create even an infinite sequence! See the following:

def natural_numbers():
    n = 1
    while True:
        yield n
        n += 1

Note: the flip side of laziness is that you can only iterate through a generator once! If you need to iterate through something multiple times:

  • either you recreate the generator
  • or you use a list

Another way of creating a generator is by using list comprehension (see Lesson 2):

lazy_evens_below_20 = (i for i in lazy_range(20) if i % 2 == 0)

Randomness

The Python random module allows us to draw random numbers in the interval [0,1].
To draw a random number we do as follows:
import random
aRandomNumber = random.random()

Reproducibility

As usual, the random generator produces pseudorandom numbers (i.e., deterministic) based on an internal state. Such state can be initialize with random.seed. It is suggested to apply such approach, since you may want to get reproducible results in your experiments!
Every time you reset the seed to a specific value, the extraction of random numbers restarts, and redraws the same values it drew the first time you reset the seed to that value.
mySeed = 10

random.seed(mySeed)
print random.random()  # 0.5714

random.seed(mySeed)
print random.random()  # again 0.5714

Extracting values from a range

You can use random.randrange(), which takes:

  • a single arguments B, when you want to extract numbers from the range [0, 1, ..., B-1]
  • two arguments A and B, when you want to extract numbers from the range [A, A+1, ..., B-1]

Lists vs. random

The random module can be used to randomize the order of list elements, too. This is done via the random.shuffle() function:

upToTen = range(10)
random.shuffle(upToTen)
print upToTen
# [2,5,1,9,7,3,8,6,4,0]

With a similar mechanism, it is possible to pick up a random element from the list.

myBestFriend = random.choice(["Alice","Bob","Charlie"])  # 'Bob'

If you need to draw a sample of elements without replacement (i.e., without duplicates):

lotteryNumbers = range(60)
winningNumbers = random.sample(lotteryNumbers, 6)
# [16, 36, 10, 6, 25, 9]

To choose a sample of elements with replacement (i.e., with duplicates):

fourWithReplacement = [random.choice(range(10))
                          for _ in range(4)]

Regular expressions

Regular expressions provide a way of searching text.
The Python module that allows one to apply regular expressions to text is re.
We are not going to discuss regular expressions syntax in this article! Feel free to read some documentation.

args and kwargs

Python allows the programmer to declare function whose parameters are not specified. By using args and kwargs, one is able to read:

  • the parameter values (via args)
  • the parameter names (via kwargs)


def magic(*args, **kwargs):
    print "unnamed args: ", args
    print "keyword args:", kwargs

magic(1, 2, key="word", key2="word2")

# prints:
#   unnamed args: (1,2)
#   keyword args: {'key2': 'word2', 'key': 'word'}


Nessun commento:

Posta un commento