0% found this document useful (0 votes)
32 views17 pages

Full Circle Magazine 'Programming in Python' Series. Volume 9.

Full Circle Magazine 'Programming in Python' series. Volume 9.

Uploaded by

lukyanov
Copyright
© Attribution ShareAlike (BY-SA)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views17 pages

Full Circle Magazine 'Programming in Python' Series. Volume 9.

Full Circle Magazine 'Programming in Python' series. Volume 9.

Uploaded by

lukyanov
Copyright
© Attribution ShareAlike (BY-SA)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Full Circle

THE INDEPENDENT MAGAZINE FOR THE UBUNTU LINUX COMMUNITY

PROGRAMMING SERIES SPECIAL EDITION

PROGRAM
IN PYTHON
Volume Nine
Six
Parts 43
39-5
2-338
Full Circle Magazine is neither ailiated, with nor endorsed by, Canonical Ltd.
Full Circle Magazine Specials
About Full Circle
Full Circle is a free, Find Us
independent, magazine Website:
dedicated to the Ubuntu http://www.fullcirclemagazine.org/
family of Linux operating
systems. Each month, it Forums:
contains helpful how-to http://ubuntuforums.org/
articles and reader- forumdisplay.php?f=270
submitted stories. Welcome to another 'single-topic special' IRC: #fullcirclemagazine on
Full Circle also features a In response to reader requests, we are assembling the chat.freenode.net
companion podcast, the Full content of some of our serialised articles into dedicated Editorial Team
Circle Podcast which covers
editions. Editor: Ronnie Tucker
the magazine, along with
other news of interest. For now, this is a straight reprint of the series (aka: RonnieTucker)
'Programming in Python', Parts 49-53 from issues #79 ronnie@fullcirclemagazine.org

Please note: this Special through #84, allowing peerless Python professor Gregg Webmaster: Rob Keria
Edition is provided with Walters #83 as time of for good behaviour. (aka: admin / linuxgeekery-
absolutely no warranty admin@fullcirclemagazine.org
Please bear in mind the original publication date; current
whatsoever; neither the Editing & Proofreading
contributors nor Full Circle versions of hardware and software may difer from those
Mike Kennedy, Lucas Westermann,
Magazine accept any illustrated, so check your hardware and software versions Gord Campbell, Robert Orsino,
responsibility or liability for before attempting to emulate the tutorials in these special Josh Hertel, Bert Jerred
loss or damage resulting from editions. You may have later versions of software installed
readers choosing to apply this Our thanks go to Canonical and the
or available in your distributions' repositories.
content to theirs or others many translation teams around the
computers and equipment. Enjoy! world.

The articles contained in this magazine are released under the Creative Commons Attribution-Share Alike 3.0
Unported license. This means you can adapt, copy, distribute and transmit the articles but only under the following conditions:
You must attribute the work to the original author in some way (at least a name, email or URL) and to this magazine by name ('full circle magazine') and
the URL www.fullcirclemagazine.org (but not attribute the article(s) in any way that suggests that they endorse you or your use of the work). If you alter,
transform, or build upon this work, you must distribute the resulting work under the same, similar or a compatible license.
Full Circle Magazine is entirely independent of Canonical, the sponsor of Ubuntu projects and the views and opinions in the magazine should in
no way be assumed to have Canonical endorsement.

full circle magazine


HOW-TO
Written by Greg Walters
Programming In Python - Part 49
W hile I was working this week, 3.3000000000000003 >>>1/10 Decimal('3.300000000000000266
45352591003756970167160034179
a very wise person by the 0 6875')
name of Michael W. suggested that You stare at the screen in
I should consider what happens disbelief and first think “I must Oh, right. We have to have at It seems to just be getting
with floating-point numbers and have typed something wrong”. least one of the values a floating- worse and worse. So what is really
equality. Then you realize that you didn’t. So point value to show any decimal happening?
you type: points since an integer/integer
Take for example a simple returns an integer. So we try again. This is called Representation
>>>2.2+3.3
calculation: 1.1 + 2.2 Error, and exists in almost every
5.5 >>>1/10.0
modern programming language
The answer, you say, is 3.3! Any 0.1 (Python, C, C++, Java, and even
school-kid who has dealt with Now you are even more Fortran and more), and on almost
fractions knows that. Well, tell confused and you think to yourself Ok. Reality is back. No, not every modern computer. This is
your computer. If you start up the “Ok. This is either a bug or some really. Python is simply showing because these machines use IEEE-
Python Interactive Shell and at the kind of sick Easter egg.” No, it’s you a rounded version of the 754 floating-point arithmetic
prompt type neither a bug nor an Easter egg. answer. So, how do we see the which (on most machines and OS
It’s real. While I knew about this a “real” answer? We can use the platforms) maps to an IEEE-754
(1.1+2.2) == 3.3 very long time ago, it had slipped decimal library to see what’s really double-precision number. This
into the cobwebs hidden in the happening. double-precision number has a
you might be surprised that the dark recesses of my old mind, so I precision of 53 bits. So, our 0.1,
shell responds had to bring it up here. What we >>> from decimal import * when represented in this 53-bit
are seeing is the joy of binary double-precision, turns into:
“False” >>> Decimal(1/10.0)
floating-point numbers.
Decimal('0.100000000000000005 0.000110011001100110011001100
WHAT?!!?!? 55111512312578270211815834045 11001100110011001100110011010
We all know that ⅓ equates to 41015625')
.33333333333333333… for ever
Now, confused, you type at the That’s close to .1, but not close
and a day, but take, for example, WOW. So let’s try our original
prompt: enough to avoid issues.
the fraction 1/10. Everyone knows formula and see what that would
>>>1.1+2.2 that 1/10 is equal to .1, right? If you show:
use the interactive shell you can So what do we do about it?
see that: >>> Decimal(1.1+2.2)
Well, the quick answer is that you
And the shell responds back:
probably can live with it for 90% of

full circle magazine #79 8 contents ^


HOWTO - PYTHON PT49
the things we have to do out there the way.) have been talking about. The
in the real world – by using the actual conversion to a binary
round() method. While you have to >>> math.pi floating-point number that is 53
decide on the number of decimal 3.141592653589793 bits long, the number becomes:
points that you must have in your
world to carry the precision that 2.674999999999999822365316059 The Ubuntu Podcast covers all
Now, if we wanted to round 9749535221893310546875
you need, for the most part, this that value down to 5 decimal the latest news and issues facing
will be an acceptable workaround. places, we would use: Ubuntu Linux users and Free
which then rounds down to
Software fans in general. The
2.67.
I honestly don’t remember if we >>> round(math.pi,5) show appeals to the newest user
have gone over the round method, and the oldest coder. Our
3.14159 The bottom line here is when
so I’ll briefly go over it. The syntax discussions cover the
trying to compare floating-point
is very simple: development of Ubuntu but
That is the “standard” value of numbers, be aware that some
aren’t overly technical. We are
round(v,d) pi that most everyone knows off things just don’t translate well.
lucky enough to have some
the top of their head. That’s great.
great guests on the show, telling
where v is the value you want to However, if we set the number of See you next time!
us first hand about the latest
round and d is the number of decimal places to be returned to 4,
exciting developments they are
decimals (maximum) you want look what happens.
working on, in a way that we can
after the decimal point. According all understand! We also talk
>>> round(math.pi,4)
to the Python documentation, about the Ubuntu community
“Values are rounded to the closest 3.1416
and what it gets up to.
multiple of 10 to the power of
minus n digits; if two multiples are All that sounds good until you The show is presented by
equally close, rounding is done run into a value like 2.675 and try members of the UK’s Ubuntu
away from 0”. All that being said, if to round it to 2 decimal places. The Linux community. Because it is
the number is 1.4144, and we assumption (since it is exactly covered by the Ubuntu Code of
round it to 3 decimal places, the halfway between 2.67 and 2.68) is Conduct it is suitable for all.
returned value will be 1.414. If the that the returned value will be
number is 1.4145 it would be 2.68. Try it. The show is broadcast live every
returned as 1.415. Greg Walters is owner of RainyDay
>>> round(2.675,2) fortnight on a Tuesday evening
Solutions, LLC, a consulting company
in Aurora, Colorado, and has been (British time) and is available for
For example, let’s use the value 2.67 programming since 1972. He enjoys download the following day.
of pi that comes from the math cooking, hiking, music, and spending
library. (You must import the math That might cause a problem. It time with his family. His website is
podcast.ubuntu-uk.org
www.thedesignatedgeek.net.
library before you can do this, by goes back to the initial issue we
full circle magazine #79 9 contents ^
H O W-TO
Written by Greg Walters P ro g ra m m i n g I n P yt h o n - P a rt 5 0
T his month, I thought I’d talk
about a couple of lesser known
functions, maketrans and translate.
the
is
Notice that we included None as
translate table. While this part
cool, it gets better. There is a
intable = ‘aeiou’
outtable = ‘12345’
trantable = maketrans(intable,outtable)
function called maketrans. It takes astr = “The time has come”
astr.translate(trantable)
We’ll start with the translate an input string and an output string
method. The translate method as parameters and returns a table
returns a copy of a string – with all that is used as the first parameter If you look at it carefully, you’ll character, getting that characters
characters in the translate table into the translate method. Here see that the lowercase vowel value in Hex, and then finds that
replaced, or has the characters in (top right) is a very simple example. letters are replaced with the value in the translate table and
the optional parameter numbers we specified: substitutes it in the output string.
deletechars removed from the It returns: The Hex representation of our
string. Here’s the syntax. 1bcd2fgh3jklmn4pqrst5vwxyz original astr string (‘The time has
“Th2 t3m2 h1s c4m2” come’) is shown below.
s = If you look even closer, you’ll
str.translate(table[,deletech Let’s look at what this does. We see that there actually 256 entries So now it should be making
aracters])
assign intable to a string of vowels starting with “\x00” and ending sense.
as before. outtable is assigned the with “\xff”. So the table contains
Before we get to the table numbers 1 ,2,3,4,5 as a string. When
portion of the method, let’s look at we make the call to maketrans, our the entire 256 possible ascii Now the purpose of this whole
the delete portion. Let’s say that character set. So, when the thing. Think back to your schooling
actual trantable is as follows translate method gets the table, it where you learned about Julius
you have the string “The time has (shown below. The “\x” means that iterates (or walks through) each
come”. And you want to delete all it is hexadecimal char): Ceasar. Whenever he wanted to
the vowels (for some weird reason) send a message of a confidential
from that string. You can code it \x54\x68\x65\x20\x74\x69\x6d\x65\x20\x68\x61\x73\x20\x63\x6f\x6d\x65
like this: T h e t i m e h a s c o m e

'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\
astr = “The time has come” x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABC
DEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`1bcd2fgh3jklmn4pqrst5vwxyz{|}~\x7f\x80\x81\x82\x83
astr.translate(None,’aeiou’) \x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97
\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab
will return: \xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf
\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3
\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7
“Th tm hs cm” \xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb
\xfc\xfd\xfe\xff'
full circle magazine #80 8 contents ^
HOWTO - PYTHON PT50
matter, he would use a cipher that that Caesar used. For simplicity from string import maketrans
would shift all the letters of the sake, let’s only use uppercase #----------------------
alphabet three characters to the characters (shown top right). intab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
outtab = "DEFGHIJKLMNOPQRSTUVWXYZABC"
right. So, using todays english EncTrantab = maketrans(intab,outtab) #Encode
alphabet: Everything in the above code is DecTrantab = maketrans(outtab,intab) #Decode
ABCDEFGHIJKLMNOPQRSTUVWXYZabc
defghijklmnopqrstuvwxyz
pretty much what we’ve covered instring = raw_input("Enter the plaintext string -> ")
EncString = instring.translate(EncTrantab)
above or in earlier Python articles, DecString = EncString.translate(DecTrantab)
becomes: but I’ll go over it quickly. print("Encoded string is - %s" % EncString)
DEFGHIJKLMNOPQRSTUVWXYZabcdef print("Decoded string is - %s" % DecString)
ghijklmnopqrstuvwxyzABC The first two lines are the in and
out strings. We’ve just shifted the between the “Z” and the “A” in the COME
While this seems very simple by characters and wrapped around to outtab string. This helps keep the Encoded string is -
WKHCWLPHCKDVCFRPH
today’s standards, when I was a create the out string. The next two actual words from being too
school kid, we used this all the time lines create a table for encoding obvious in the encrypted string. And to test the decode side of
to send messages to each other. and one for decoding. Line 5 The next change is where we ask if things:
We used a different index into the prompts the user to enter a string the user wants to encode or Encode or Decode (E or D) -> D
string to start the encryption to encode. We then encode that decode the string. Finally we added Enter the string ->
WKHCWLPHCKDVCFRPH
string, the logic behind it was the string (EncString) in the next line. an if statement to control what we Decoded string is - THE TIME HAS
same. To decode it, we simply use the print (shown bottom right). COME

translate method on the encoded


No one knows how effective string to get the plain text back. The output from the program is: Well, hopefully you are starting
this actually was for good old Finally we print both strings out.
Encode or Decode (E or D) -> E to get ideas about how to use this
Julius. One would think that if Here’s the output of the program.
Enter the string -> THE TIME HAS
new information in your own code.
someone intercepted the message, from string import maketrans
they would have thought that it Enter the plaintext string ->
was in some foreign language. We THE TIME HAS COME #Be sure to include the space character in the strings
intab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
can only speculate. Encoded string is -
WKH WLPH KDV FRPH outtab = "DEFGHIJKLMNOPQRSTUVWXYZ ABC"
Decoded string is - EncTrantab = maketrans(intab,outtab) #Encode
We can easily use the translate THE TIME HAS COME DecTrantab = maketrans(outtab,intab) #Decode
method and the maketrans helper which = raw_input("Encode or Decode (E or D) -> ")
function to allow us to have fun Just like back in school. But let’s instring = raw_input("Enter the string -> ")
with this. Let’s say we want to flesh it out just a bit to make it a EncString = instring.translate(EncTrantab)
make a simple program that allows bit more usable. The code is almost DecString = instring.translate(DecTrantab)

us to enter a string of “plain text” the same with a few exceptions. if which == "E":
and get back an encrypted string First, we have added a space to the print("Encoded string is - %s" % EncString)
using the same side right method end of the intab string and in else:
print("Decoded string is - %s" % DecString)

full circle magazine #80 9 contents ^


H O W-TO
Written by Greg Walters P ro g ra m m i n g I n P yt h o n - P a rt 5 1
T his month, I’m going to discuss
a product that is new to me,
but has apparently been around for
tools, and I’m not sure how I have
missed this package for so many
years (version 2.1 was released in
the reports designer, but if the
designer is any indication of the
power, ease and flexibility of the
One of the first things you
should know is that it supports
databases like Oracle, MySql,
a number of years. It’s called March of 2009 and they are rest of the suite, this thing is aSQLite, MSSQL and more.
NextReports from Advantage currently up to version 6.3). But winner. Everything is based on queries and
Software Factory, and you can get now that I’ve found it, I’m a really good thing is that only
it free from http://www.next- absolutely pumped about it. This month, we are going to SELECT type queries are allowed.
reports.com/ . Not only that, but concentrate on the designer. This means that nothing in the
it’s open source and it runs under Now that I’ve stepped down Because of some constraints on my source database can be changed by
Windows and Linux! from my soap box, I can begin to time, I’m working on a Windows accident. You can enter your own
sing its praises. It is a suite of three machine, but everything that I queries or use a visual designer.
Before I start telling you about parts, a reports designer, a report show can be done in Linux (so
the product, let me get on my engine and a report server. All I please forgive me in advance). The screenshot shows how nice
soapbox and vent for a moment or have had a chance to play with is a UI it is. Things are pretty intuitive
two. For a long time, I’ve been and it won’t take you long to be
working with databases and productive at this. Let’s take a look
reports. One of the things that I’ve at the steps to get going.
had issues with is that while there
are free database solutions out Start with File | New | Data
there, like SQLite and MySql, there Source. Next, name your source
was precious little available that whatever you want to call it.
was free for report designer tools.
More times than not, any reports Now tell NextReports what kind
either had to be done with very of database it is in the dropdown
expensive software tools, or the called “Type:”. You can skip over
developer had to roll his own. the Driver section and go to the
Some tools were available, but URL: section. This is where you put
were lacking. When it came to the path to the database. If you are
charting, well, you pretty much had using, for example, a SQLite
no choice but to use the expensive database, this will be filled in for
stuff. Believe me, I’ve looked for you: “jdbc:sqlite:<dbfile-path>”.
years for really good free reporting Replace the <dbfile-path> with the
full circle magazine #81 9 contents ^
HOWTO - PYTHON PT51
path to your database. Other types visual query designer, just drag the
of databases have similar types of table(s) you want to deal with onto
information already populated to the designer canvas to the right.
help you. Next, click the “Test”
button to make sure you can Once you have all your tables
connect. If everything goes there, you can start making
correctly, then click “Save” and connections between the tables.
you’ll see it added to the
Connetions tree. The next thing In the example here, I have two
you need to do is make a tables, one with information about
connection to your database that kids in a confirmation class and the
you have just added. Now, right other with entries for worship
click on the database and then click notes taken. The worship note
on Connect. table doesn’t have the kid’s name
in it, just an id that points to the kid
information table. I did a drag and
drop to make that link between the
kidID field and the pkID of the kid
table. Then I selected each field I
wanted to have in the result set. In
Once you are connected, you’ll to the left of “%” which will open this case, the kid’s first and last
see that you have four possible up your database table display. name and an active (or not-
things to choose from. The “%” is Now you will have Tables, Views deleted) flag in the kids table and
the database tables. The next and Procedures in the tree. Once multiple fields from the notes
three are so you can create new again, click on the “+” sign next to table. The grid below shows each
queries, reports and charts. Simple “Tables”. This will show all your of the fields, which table it comes
enough. Now click on the “+” sign tables. Now if you want to use the from, and other information.

full circle magazine #81 10 contents ^


HOWTO - PYTHON PT51
As you can see, we can set
k1.fname || “ “ || k1.lname the tree and right click on the we have four rows, two header
criteria like “Active = 1 ”, choose to
as FullName,
query you just created. Select rows, one detail row and a footer
display a field or not, and set sort “New Report from Query”. The row. You can add or delete rows as
The “||” characters are query designer canvas goes away needed. This method is not quite as
type and sort order. Once you are concatenation characters so we
satisfied with this, you can click on and is replaced by the report free-form as some other report
will have the two fields with a designer. designers, but makes for a very
the tab below and see your actual space between in a field named
SQL query. nice and clean report.
“FullName”. Don’t forget the On the left is the properties
comma at the end. Once you have window for any given field or the The two header rows hold our
your query the way you want it, entire report. On the right is the report title and column headers.
click on the save button to save the report designer itself. Notice that The detail row has each field we
query. You will be asked what you it looks like a spreadsheet. Each will be reporting on and the footer
want to call it. row is considered a “band” and row is the report footer. Let’s take
holds information for that report a look at how the report looks as a
Next, click on the Query item in row. In the case of this example, default. Click on the button at the

To test your query, simply click


on the “running man” and you will
(hopefully if you did it correctly)
get the query results in a grid
below the editor. If you want to
add manual lines you can. For
example, I want to combine the
kids first and last names (fname
and lname) into a full name. We can
do that by putting a line after the
“k1 .lname,” line like this:

full circle magazine #81 11 contents ^


HOWTO - PYTHON PT51
top of the bar marked “To Html” to we have a grouping break. We can with a check for Yes (or 1 ) and an character you want, double-click
see the report. (I blurred the kids also get rid of the three fields empty box for No (or 0). It’s really the character to copy it to the
last names, that’s not an issue in (fname, lname and FullName) in easy to do, but makes your report “Text to copy:” box, then click the
the generator.) the detail section, since we’ll be look like you spent days on it. By “Copy” and then paste it into your
displaying the name in the group using the Wingdings font from document. The unicode characters
For a report with almost no band. SImply right-click on them Windows, the two characters we for them are 261 0 (empty box) and
work, that’s really nice. But let’s and select “Delete Cell”. Now you want are 0x6F(01 68) for an empty 261 1 (checked box) using the
pretty it up a bit. Let’s create a can resize the three empty cells on box and 0xFE (0254) for a checked WingDings 2 font. I’m sure there
group that puts all of the data for the left to make the gap less box. are many other easier ways to deal
any given kid under the kid’s name. obvious. with this, but I’m shy on time. (Be
Before I go on, the one thing sure you have Common selected in
Right click on the first column Taking a quick peek at what the that Windows does better than the Script list.)
of the data row. Select Group and report looks like now will show you Linux (that I have found) is the use
then Add. that the information for each kid is of the Alt+NumPad entry of special We’ll start with the
all nicely grouped together. characters. Linux doesn’t allow WorshipNotes field. On the detail
that. There was a work around that row, right click on the field you
That’s nicer, but now let’s do used Ctrl+Shift+U then the unicode want to do. In this case it’s marked
something kind of fun. All the 1 s value for the character you $C{WorshipNote}. Choose Insert,
and 0s obviously stand for yes and wanted. However, that doesn’t then Expression. Yet another
no. That’s rather boring for a work on all machines. The easiest wonderful thing that NextReports
report, so let’s add an advanced way I’ve found to do this on Linux, gives us it the ability to do pretty
conditional statement for each of is to open Character Map, use the much everything with as little
those fields that will show a box search function to find the unicode typing as possible. Look in the
center of window where it says
Operators. Double click on the
“if..else..” selection, and it will fill
that into the editor for you as a
template so you don’t make a
mistake.
Now, we want to put the
You will be presented with a WorshipNotes field in the
new window asking which of the parentheses of the editor. Simply
fields you want to create the group click in between the two
upon. In this case, I select FullName parentheses to place the cursor
and then click the Ok button. Now and then double-click on the field
full circle magazine #81 12 contents ^
HOWTO - PYTHON PT51
like.
There’s our pretty little boxes.
Doing this to the other fields is just
as simple.
It only took me about 3 hours of
playing with the package to get to
this point and a whole lot further. I
can truly say that I have a great
amount more to learn but that’s
for another day. You can use
templates to color your report, you
can add images, and much more.
you want to go in there. BAM! It’s empty box and 0254 for the
filled in for you. Now click after the checked box. So now our Next time, I’ll talk about how we
field name in the editor and then expression is (at least in Windows): might go about embedding these
double-click on the “== (eq)” reports into a Python program.
operator. Then add a “1 ”, so the if ( $C_WorshipNote == 1 ) {
"þ"; } else { "o"; } Until then, have fun playing with
editor line reads this wonder FREE software. Greg Walters is owner of RainyDay
Solutions, LLC, a consulting company
if ( $C_WorshipNote == 1 ) { Name the expression ( I used in Aurora, Colorado, and has been
; } else { ; } WNotes ) and save it. Under programming since 1 972. He enjoys
properties for that field, select the cooking, hiking, music, and spending
We are almost finished with our font (WingDings is what I used time with his family. His website is
www.thedesignatedgeek.net.
expression The first set of curly here) and this is what it will look
brackets define what to do if the
expression is True and the second
is what to do if it’s false. In this
case, we’ll use the CharMap (in
windows, Linux has one as well, for
example gucharmap if you are
using Gnome) to copy the
characters into our editor string.
Or, under windows, you can hold
the {Alt} key and press 01 68 for the
full circle magazine #81 13 contents ^
H O W-TO
Written by Greg Walters P ro g ra m m i n g I n P yt h o n - P a rt 5 2
SELECT pkgs, Count(DOW) as CountOfDOW FROM study
WHERE (Holiday <> 1)
AND DayName in ("Monday","Tuesday","Wednesday","Thursday","Friday")
GROUP BY pkgs

Python-Quick-Syntax- time ago, so I thought I'd share the Assume we have a database
Reference/dp/1 430264780) as well information with you. It is the that has multiple tables in it. One
as others. It is, as the title suggests, CREATE TABLE AS SELECT of the tables is named "study" that
a syntax reference that will help command, which allows us to pull a holds data from a receiving
those of us who program in other query from one table (or joined operation. There are six fields
languages as well as Python, to tables) and create another table on which are shown below.
remember how a certain command the fly. The general syntax is:
works and the requirements for One of the datasets that we will
that command. Please help a poor CREATE TABLE [IF NOT EXISTS]
{New Table Name} AS SELECT need to produce from this raw data
old programmer make a living by {query} is a grouping of package count and
buying the book, if you can.

B
the number of days within the
efore we get started on this The part in square brackets (IF study that quantity of packages
month’s actual python subject, Now on to bigger and better NOT EXISTS) is totally optional, came in on, assuming that the days
let me toot my own horn for just a things. which will create the table only if it are weekdays (Monday thru Friday)
minute. In late December and early doesn’t exist already. The part in and that the day is not a holiday,
January, my first book on Python While I was working on my curly brackets, however, is not. The since holidays have less than
was published by Apress. It is latest book for Apress, I first is the new table name and the normal number of packages. Our
named "The Python Quick Syntax rediscovered a SQL command that I second is the query that you want query is shown above.
Reference", and is available from a didn't discuss when we were to use to pull data and create the
number of places. You can find it working with SQL databases a long new table. This then provides us with data
on the Apress site
(http://www.apress.com/9781 4302 pkID - Integer, Primary Key, AutoIncrement
64781 ), Springer.com DOM - Integer - Day of the month (1-31)
(http://www.springer.com/comput DOW - Integer - Day of week (1-7 (Sunday = 1, Monday = 2, etc))
pkgs - Integer - Number of packages received that day
er/book/978-1 -4302-6478-1 ) and DayName - TEXT - "Sunday","Monday", etc
Amazon Holiday - Integer 0 or 1 (Is this day considered a holiday or not) 1 means yes
(http://www.amazon.com/The-
full circle magazine #82 11 contents ^
HOWTO - PYTHON PT52
that would look something like
this: CREATE TABLE IF NOT EXISTS weekdays AS
SELECT pkgs, Count(DOW) as CountOfDOW FROM study
WHERE (Holiday <> 1)
pkgs CountOfDow AND DayName in ("Monday","Tuesday","Wednesday","Thursday","Friday")
31 1 GROUP BY pkgs
32 2
33 1
... can begin our code. Assuming we def OpenDB():
48 3
already have the study table global connection
global cursor
created and populated, we can use
So the data is showing that Python to then create our new
connection = apsw.Connection("labpackagestudy.db3")
cursor = connection.cursor()
during the study of 65 days, only table in the main database. Just as
one weekday had 31 packages but an FYI, I am using the APSW SQLite
3 weekdays had 48 packages and calculations. on the “study” table.
library to do the database work.
so on. Similar queries could be
created that would cover holidays As you can see, we want to Now we create three more
We, of course, have to open a create a second cursor, so that we columns (shown below) within the
and weekends. connection (right) and create a don’t run any risk of the first cursor weekdays table named
cursor to the SQLite database. We having data we need to maintain. “probability”, “lower” and “upper”.
While having the data simply as have covered this in a number of
a returned dataset from the query, We will be using it in the final part We do this by using the “ALTER
past articles. of the code. We then drop the TABLE” SQL command.
we might want to do further
analysis on the data, so we want to table if it exists and run our query
Now we need to create
put the resulting data from the the routine that will actually addcolquery = 'ALTER TABLE weekdays ADD COLUMN probability REAL'
query into a table. That's why we create the table with the cursor.execute(addcolquery)
would create a table from the returned dataset from the
addcolquery = 'ALTER TABLE weekdays ADD COLUMN lower REAL'
cursor.execute(addcolquery)
query. So in the following example, query, shown below, then addcolquery = 'ALTER TABLE weekdays ADD COLUMN upper REAL'
shown above right, we create a alter it and run some
cursor.execute(addcolquery)
table named "weekdays" using the
same query we just showed above. def DoWeekDays():
# Create a second cursor for updating the new table
Now anytime we need the data cursor2 = connection.cursor()
for that weekday result set, we can q1 = "DROP TABLE IF EXISTS weekdays"
cursor.execute(q1)
just run a query on the weekdays query = '''CREATE TABLE IF NOT EXISTS weekdays AS SELECT pkgs,
table. Count(DOW) as CountOfDOW FROM study WHERE (Holiday <> 1)
AND DayName in
("Monday","Tuesday","Wednesday","Thursday","Friday")
Once we know what we need, GROUP BY pkgs'''
and have tested the query, then we cursor.execute(query)

full circle magazine #82 12 contents ^


HOWTO - PYTHON PT52
The next step (top right) will be database and calculate an upper sumquery = "SELECT Sum(CountOfDOW) as Sm FROM weekdays"
to sum the data in the and lower value that will be used in tmp = cursor.execute(sumquery)
CountOfDOW field. another process later on. Notice for t in tmp:
that we check to see if the DaySum = t[0]
There is only one record LastUpper variable contains ‘.0’. If
returned, but we do the for loop it does, we set it to the probability prob = cod / float(DaySum)
thing anyway. Remember from the value, otherwise we set it to the if LastUpper != .0:
lower = LastUpper
above discussion that the lower plus the probability value. LastUpper = (lower + prob)
“CountOfDow” field holds the else:
lower = .0
number of days during the study Finally we use an update SQL LastUpper = prob
that a particular number of statement to put the new
packages came in. This gives us a computed values into the
value that contains the sum of all database. nquery = 'UPDATE weekdays SET probability = %f, \
lower = %f, upper = %f WHERE pkgs = %d' \
of the “CountOfDow” entries. Just % (prob,lower,LastUpper,pkg)
so you have a reference as we go What we end up with is a u = cursor2.execute(nquery)
forward, the number I got from all package count (pkgs), a count of #====================================
# End of DoWeekDays
my dummy data is 44. the number of days that package #====================================
count came in, a probability of that
upquery = "SELECT * FROM
weekdays"
occurring within the whole of the analysis of this data. A “normal http://pastebin.com/kMc9EXes
study (31 packages on 1 day out of real-world” example would be to
c1 = cursor.execute(upquery) a total of 44 (weekdays in that 60+ predict the number of cars that Until next time.
day study), will have a probability arrive at a carwash based on
Here we have done a ‘SELECT of 0.02.). observational data done in the
all’ query so every record in the field. If you want to understand
datatable is in the ‘c1 ’ cursor. We’ll If we add up all the probability more, you could look at
walk through each row of the values in the table it should add up http://www.algebra.com/algebra/h
dataset, pulling the pkgs (row[0]) to 1 .0 . omework/Probability-and-
and CountOfDow (row[1 ]) data statistics/Probability-and-
into variables. The upper and lower values statistics.faq.question.3091 1 0.html
then reflect a number between to see an example of this. All we Greg Walters is owner of RainyDay
LastUpper = .0
for row in c1:
floating point number 0 and 1 that did is generate (the hard part) Solutions, LLC, a consulting company
cod = row[1] will mirror the possibility of any easily with Python. in Aurora, Colorado, and has been
pkg = row[0] random number within that range programming since 1 972. He enjoys
that will give us a randomized cooking, hiking, music, and spending
The code for the two routines time with his family. His website is
Now we will create a probability number of packages. This number that we presented this time is at: www.thedesignatedgeek.net.
of each daily package count in the can then be used for a statistics
full circle magazine #82 13 contents ^
H O W-TO
Written by Greg D. Walters P ro g ra m I n P yt h o n - P a rt 5 3
T his month, I thought I would
create a routine that makes a
license key from an email. We all
• special characters (!#$%&'*+-
/=?^_` {|}~.)
• period characters are allowed, but
localvalid1 = "abcdefghijklmnopqrstuvwxyz"
localvalid2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
localvalid3 = "!#$%&'*+-/=?^_`{|}~."
Offset = 0
know the reason for having a may not be repeated next to each
license key, and if you ever need to other (..., etc)
make things a bit harder to decode, Now (as shown above right) we
have a quick and dirty set of
Once we have validated the we put the length (with offset) as will create a string that will include
routines to do it, you can use this.
email, we then will create a character position 2 and the all of our “legal” characters for the
Remember, Python is a scripting
“checksum character” which is checksum as character position 4. IsValidEmail function. I’ve split it
language, so the source is always
readable. There are ways around based on the ascii value of each into 3 strings so it fits nicely for the
character in the entire email So for the email magazine. We combine them in the
this; we’ll discuss them in another
address, and then divide it by the fredjones@someplace.com we get IsValidEmail routine. We also set a
article. Let’s take a look at the
number of characters in the email a license key of: global variable ‘Offset’ to 0. This
“gross” logic behind the code,
before we actually dive into the address. For example, let’s use a j[vHihnsriwDwsqitpegi2gsq will be the value that we add (later
code. mythical email address of on) to each character when we
fredjones@someplace.com. If we Lets get started with the code. create the encoded string.
First, we will ask for an email walk through the email address, we Since this is the 53rd article in the
address and then break it into two can get the ascii value of each series, I won’t be quite as verbose Now for our first function. This
parts, the local part (the part character by using the ord() from here on out. (below) is the IsValidEmail routine.
before the “@” character) and the function. When we add up each of Basically we pass the email in the
domain part (the part after the “@” the ascii values, we get a sum of First our imports. variable s, and an optional debug
character). There are very specific 1 670, then we divide that by the flag. We use the debug flag, as we
rules for email address validity, and length of the email address (23); import sys have done in the past, to provide
it can get very complicated. For our we get 72. Remember we are using
purposes, we will only use some of integer division here, so our result def IsValidEmail(s,debug=0):
the rules and only on the local part. will be an integer. email = s
You can do a web search on the pos = email.rfind("@")
local = email[:pos]
actual rule set. In our code, we will Now that we have our checksum domain = email[pos+1:]
only look at: value, we subtract 68 from that if debug == 1:
• lowercase characters (ascii ‘D’) to create an offset. We print local
print domain
• upper case characters use this offset when we encode isgood = False
• numbers between 0 and 9 each character in the email. Just to localvalid = localvalid1 + localvalid2 + localvalid3

full circle magazine #84 14 contents ^


HOWTO - PYTHON PART 53
some print statements to see how that works for anything more.
things are going. Usually we would # Check Local Part
for cntr in range(0,len(local)):
simply pass a 1 as the second r = email.find("..")
if r > -1:
if local[cntr] in localvalid:
parameter if we want to see the isgood = False
if debug == 1:
print local[cntr],ord(local[cntr]),"True"
progress verbosely. isgood = True
The last thing we do in the else:
First we assign the passed in routine is return the value of the
if debug == 1:
print local[cntr],ord(local[cntr]),"False"
email address to the variable ‘isgood’ flag. isgood = False
‘email’ and find the ‘@’ character break
that separates the local from the return isgood
domain portions of the email. We def CheckSum(s,debug = 0):
then assign the local portion of the The next routine (bottom right) sum = 0
email to (I think it’s appropriate) is the CheckSum routine which is email = s.upper()
‘local’, and the domain portion to fairly short. We walk each for cntr in range(0,len(email)):
if debug == 1:
‘domain’. We then set the boolean character in the email and create a print email[cntr],ord(email[cntr])
isgood flag to False and finally running sum of the ascii value of sum += ord(email[cntr])
create the ‘localvalid’ string from each using the built-in ‘ord’ type cs = sum/len(email)
if debug == 1:
the 3 shorter strings we set up conversion. As I stated earlier, we print('Sum = %d' % sum)
earlier. take that sum and divide it by the print('ChkSum = %d' % cs)
length of the email address. We print('ChkSum = %s' % chr(cs))
return cs,chr(cs)
Next (top right) we simply walk return the checksum value and the
through each character in the local character represented by that step through each character of the value of 1 (‘r’), we insert the
portion of the email against the list checksum. email address adding the offset to character for the length of the
of valid characters using the in the ascii value of that character. email + 68 and then the offset
keyword. If any character in the Now for the EncodeKey routine.
While it looks simple, it requires For the ‘f’ in ‘fredjones’, it would be character, which using our example
local portion of the email fails the 1 02 + 4 or 1 06 which equates to ‘i’. would be iYt. The next time we go
test, we break out of the for loop, some concentration so pay Using the counter variable ‘cntr’, through the loop, cntr will equal 2,
setting the ‘isgood’ flag to False. attention! We assign the Offset
variable to global status so we can we then determine what we add to but we already have 3 characters in
change it within the function and the ‘NewEmail’ string we build up the email. That’s where we want to
Finally, we look for any set of character by character. Notice in insert the checksum character (‘F’)
period characters that are so it can be used in other functions.
the code that we go from 0 to the and then the third character offset.
contiguous. We use the string.find We then set the Offset variable to length of the email, so character 0 From there, we simply add each
routine that will match anything the checksum minus 68. As in the
example presented at the is ‘f’, character 1 is ‘r’ and so on. offset character to the string, and
that is like ‘..’ or ‘...’ and so on. Now comes the part that might when the loop is done, we return
Being a lazy programmer, I used beginning of the article, it would
be 72-68 which equals 4. We then confuse some of you. If cntr is a the key (top right).
only a single “double dot” check
full circle magazine #84 15 contents ^
HOWTO - PYTHON PART 53
The DecodeKey routine (bottom that you could simply modify the def EncodeKey(s, csum, debug = 0):
right) basically reverses the code to make it much harder to global Offset
process we used in the EncodeKey break. You could, for example, use email = s

routine. One thing you might a random number rather than the Offset = csum - 68
if debug == 1:
notice here is that in the first ‘if ‘D’ (68). If you do that, set a seed in print("Offset is %d" % Offset)
debug’ statement of this function, I the code so that it will always NewEmail = ""

used ‘!= 0’ rather than ‘== 1 ’, simply generate the same random for cntr in range(0,len(email)):
ch = ord(email[cntr]) + Offset
to remind you that the two can be number. You could also go a bit if cntr == 1:
interchangeable. deeper and put the offset value chr(ch)
NewEmail = NewEmail + (chr(len(email)+68)) +
somewhere into the license key, elif cntr == 2:
The DoIt function (below) asks maybe the last character so you NewEmail = NewEmail + chr(csum) + chr(ch)
for an email address using could use that as the decryption else:
NewEmail = NewEmail + chr(ch)
‘raw_input’, then calls the offset. if debug == 1:
print cntr, NewEmail
functions in order to create the
license key. As always, the full source is return NewEmail
available at
Lastly, we call the DoIt routine. http://pastebin.com/MH9nVTNK. def DecodeKey(s,debug = 0):
Until next time, enjoy. global Offset
eml = ""
if __name__ == "__main__": for cntr in range(0,len(s)):
DoIt() if debug != 0:
print cntr,s[cntr],ord(s[cntr])-
Now, obviously the output is Offset,chr(ord(s[cntr])-Offset)
if cntr == 0:
not super-encrypted, and if Greg Walters is owner of RainyDay eml = eml + chr(ord(s[cntr])-Offset)
someone were to put in a fair Solutions, LLC, a consulting company elif cntr == 1:
in Aurora, Colorado, and has been
amount of time, they could figure programming since 1 972. He enjoys
emllen = ord(s[cntr])-Offset
elif cntr == 3:
out what we used to create the key cooking, hiking, music, and spending csumchr=s[cntr]
fairly easily. However, it should time with his family. His website is else:
give you enough of a starting point www.thedesignatedgeek.net. eml = eml + chr(ord(s[cntr])-Offset)
if debug == 1:
print eml
return eml
def DoIt():
email = raw_input("Please enter email address -> ")
isok = IsValidEmail(email,0)
if isok == True:
csum,csumchr = CheckSum(email)
ke = EncodeKey(email,csum,0)
print("License Key = %s" % ke)
print("Original email = %s" % DecodeKey(ke,0))

full circle magazine #84 16 contents ^

You might also like