Strange Coincidence

Great Stuff

Python not only offers generators with the yield keyword; classes can also implement generators as iterators. For this the Pythonista defines two methods: __iter__() and __next__(). The quadruple underscores ("dunders") mark the official entry points for Python's standard library. If the Python interpreter sees a loop head like for n in Roulette(), it instantiates an object of the Roulette class, uses __iter__() to access its iterator, and then retrieves new values from it with calls to __next__() until the iterator throws an exception.

In the class defined in Listing 2, __iter__() conveniently returns the Roulette instance itself, because the class does not need a separate iterator, since it implements the iterator itself with __next__(). The latter always returns a new random number in the range 0 to 36 and never throws an exception, so that the flow of the for loop in the main program never stops.

Listing 2

roulette.py

01 #!/usr/bin/env python3
02 import random
03
04 class Roulette:
05   slots   = 36
06   numbers = range(0,slots+1)
07
08   def __iter__(self):
09     return self
10
11   def __next__(self):
12     return self.__class__.numbers[random.randint(0, self.__class__.slots)]

The Roulette class defines two class variables: slots as the highest number on the roulette wheel and numbers as a sequence of numbers from 0 to 36 inclusive. It makes sense to define the variables once only for the class and not to rebuild them for each instance or even every time the iterator is called.

Class or Instance?

Python's class variables differ from instance variables in that they are not accessed with self.variable, but with __class__.variable or self.__class__.variable. For read-only access, you could even reference the class variable using the self.variable instance path.

But if you modify the latter, you may be in for a surprise, because Python creates a new instance variable behind your back. The instance variable will be decoupled from the class variable so that each object will modify its own, instead of propagating changes to the class level. Also, methods do not find the class variable simply by its name; if you simply reference slots in __iter__(), you can expect the syntax checker to blow up in your face.

As so often in the Python world, there is a small but subtle difference between versions 2 and 3: The iterator entry into the generator class goes by the name of next in Python 2 and not __next__ as in Python 3; programmers who want to use both versions thus typically simply define another next() method, which passes the parameters fed to it to __next__() without modification. Python 3 does not use next(), so the compatibility trick does no harm there.

The output of the statistical evaluation of the roulette generator is shown in Listing 3. After 27 rounds, a doublet appeared for the first time: the number 11 occurred twice in a row. After 6,249 rounds of Faites vos jeux, 15 occurred three times in a row; after 57,393 games, 34 occurred four times in a row, and so on.

Listing 3

roulette-run

1 $ ./roulette
2 max_run: 2 11 (27)
3 max_run: 3 15 (6249)
4 max_run: 4 34 (57393)
5 max_run: 5 1 (3363284)
6 max_run: 6 0 (95846456)
7 max_run: 7 26 (357289507)

Tumultuous Scenes

What would happen in Las Vegas at a roulette table if zero came up come six times in a row as in Listing 3 after 95 million rounds? Tumultuous scenes would probably take place in the casino before the pit boss appeared and sent the croupier home for the day, because every player at the table would immediately suspect that something fishy was going on. But, seen statistically, everything is above board; it's an inevitable fact that even random values will repeat at some time.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Coin Counter

    Parking meters and vending machines detect and count the coins you insert, but how do they work? We'll show you how to mimic the functionality with some particleboard, a Raspberry Pi Pico, a few extra chips, and some Python code.

  • Making Money With Free Software

    A competition to design the new 5 euro commemorative coin, set by the Dutch Ministry of Finance, has been won by Stani Michiels, the Belgian artist and free software developer. His winning design, developed entirely with free software, has now been realized and is a legal coin in Holland.

  • ReportLab and Panda3D

    A game of bingo illustrates how to use the ReportLab toolkit and Panda3D real-time 3D engine.

  • KDE Plasma

    We take a peek at how to create your own plasmoids for the latest KDE desktop, giving you the power to build the perfect active desktop environment.

  • JavaScript Alternatives

    JavaScript is the stuff of which many interactive web clients is made, but it comes with a fair amount of historical ballast. The creators of four alternative scripting languages seek to ditch the ballast.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News