Module II - Day 1

Python Foundation

Nov-Jan 2025 batch, Vikrant Patil

Date: 23 Dec 2025

Click here for All Notes

login to https://traininghub.vikrant.dev/ with your username and create a notebook with name module2-day1.ipynb

© Vikrant Patil

for loop

text = "Some text with some words/chars in it"
for c in text:
    print(c)
S
o
m
e
 
t
e
x
t
 
w
i
t
h
 
s
o
m
e
 
w
o
r
d
s
/
c
h
a
r
s
 
i
n
 
i
t
nums = [1, 2, 4, 5, 6, 6]
sqrs = []
for n in nums:
    sqrs.append(n*n)
sqrs
[1, 4, 16, 25, 36, 36]
text.split() 
['Some', 'text', 'with', 'some', 'words/chars', 'in', 'it']
upper = []
for w in text.split():
    upper.append(w.upper())
upper
['SOME', 'TEXT', 'WITH', 'SOME', 'WORDS/CHARS', 'IN', 'IT']
" ".join(upper)
'SOME TEXT WITH SOME WORDS/CHARS IN IT'
if cond:
    pass 
elif cond1:
    pass
elif cond2:
    pass
else:
    pass
import random
random.random()
0.0987564977463411
random.choice(text)
's'
random.choice(text.split())
'Some'
import datetime
date1 = datetime.datetime(year=2025, month=3, day=12)
date1
datetime.datetime(2025, 3, 12, 0, 0)
fivedays = datetime.timedelta(days=5)
date1 + fivedays
datetime.datetime(2025, 3, 17, 0, 0)
date2 = date1 + fivedays
date1 > date2
False
date2 > date1
True
datetime.datetime.now()
datetime.datetime(2025, 12, 23, 6, 50, 59, 941738)

Writing your own modules

%%file fibs.py


def fib(n):
    if n == 1 or n == 0:
        return 1
    else:
        fib(n-1) + fib(n-2)


def fibefficient(n):
    print("efficinet fib")
Overwriting fibs.py
import fibs
fibs.fib(5)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[30], line 1
----> 1 fibs.fib(5)

File ~/programming/work/github/vikrant.dev/python-foundation-professionals/fibs.py:7, in fib(n)
      5     return 1
      6 else:
----> 7     fib(n-1) + fib(n-2)

File ~/programming/work/github/vikrant.dev/python-foundation-professionals/fibs.py:7, in fib(n)
      5     return 1
      6 else:
----> 7     fib(n-1) + fib(n-2)

File ~/programming/work/github/vikrant.dev/python-foundation-professionals/fibs.py:7, in fib(n)
      5     return 1
      6 else:
----> 7     fib(n-1) + fib(n-2)

TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
%%file fibs1.py


def fib(n):
    if n == 1 or n == 0:
        return 1
    else:
        return fib(n-1) + fib(n-2)


def fibefficient(n):
    print("efficinet fib")
Overwriting fibs1.py
import fibs1
fibs1.fib(10)
89
fibs1.fibefficient(45)
efficinet fib

scripts

%%file command_fib.py

def fib(n):
    if n == 1 or n == 0:
        return 1
    else:
        return fib(n-1) + fib(n-2)


print(fib(10))
Writing command_fib.py
!ls
about.qmd   index.qmd~      module2-day1.ipynb  _site
command_fib.py  Makefile        notes.qmd       styles.css
day4.org    Makefile~       notes.qmd~      topics.qmd
day4.org~   module1-day1.ipynb  push        topics.qmd~
fibs1.py    module1-day2.ipynb  __pycache__     trainer.qmd
fibs.py     module1-day3.ipynb  _quarto.yml
index.qmd   module1-day4.ipynb  _quarto.yml~
!python command_fib.py
89
%%file hello.py

print("Hello Python!")
Writing hello.py
!python hello.py
Hello Python!
%%file empty.py

Writing empty.py
import empty
import hello
Hello Python!
!ls
about.qmd   index.qmd~      module2-day1.ipynb  site_libs
command_fib.py  Makefile        notes.html      styles.css
day4.org    Makefile~       notes.qmd       topics.html
day4.org~   module1-day1_files  notes.qmd~      topics.qmd
empty.py    module1-day1.ipynb  push        topics.qmd~
fibs1.py    module1-day2.ipynb  __pycache__     trainer.qmd
fibs.py     module1-day3.ipynb  _quarto.yml
hello.py    module1-day4.ipynb  _quarto.yml~
index.qmd   module2-day1.html   _site
!ls -a
.       .gitignore      module1-day3.ipynb  _quarto.yml~
..      hello.py        module1-day4.ipynb  _site
about.qmd   index.qmd       module2-day1.ipynb  styles.css
command_fib.py  index.qmd~      notes.qmd       topics.qmd
day4.org    .ipynb_checkpoints  notes.qmd~      topics.qmd~
day4.org~   Makefile        push        trainer.qmd
empty.py    Makefile~       __pycache__
fibs1.py    module1-day1.ipynb  .quarto
fibs.py     module1-day2.ipynb  _quarto.yml
!ls
about.html  index.qmd~      module2-day1.html   site_libs
about.qmd   Makefile        module2-day1.ipynb  styles.css
command_fib.py  Makefile~       notes.html      test
day4.org    module1-day1.html   notes.qmd       topics.html
day4.org~   module1-day1.ipynb  notes.qmd~      topics.qmd
empty.py    module1-day2.html   push        topics.qmd~
fibs1.py    module1-day2.ipynb  __pycache__     trainer.qmd
fibs.py     module1-day3.ipynb  _quarto.yml
hello.py    module1-day4_files  _quarto.yml~
index.qmd   module1-day4.ipynb  _site
!ls test/
untitled1.txt  untitled2.txt  untitled3.txt  untitled.txt
!python --help
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options (and corresponding environment variables):
-b     : issue warnings about converting bytes/bytearray to str and comparing
         bytes/bytearray with str or bytes with int. (-bb: issue errors)
-B     : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x
-c cmd : program passed in as string (terminates option list)
-d     : turn on parser debugging output (for experts only, only works on
         debug builds); also PYTHONDEBUG=x
-E     : ignore PYTHON* environment variables (such as PYTHONPATH)
-h     : print this help message and exit (also -? or --help)
-i     : inspect interactively after running script; forces a prompt even
         if stdin does not appear to be a terminal; also PYTHONINSPECT=x
-I     : isolate Python from the user's environment (implies -E, -P and -s)
-m mod : run library module as a script (terminates option list)
-O     : remove assert and __debug__-dependent statements; add .opt-1 before
         .pyc extension; also PYTHONOPTIMIZE=x
-OO    : do -O changes and also discard docstrings; add .opt-2 before
         .pyc extension
-P     : don't prepend a potentially unsafe path to sys.path; also
         PYTHONSAFEPATH
-q     : don't print version and copyright messages on interactive startup
-s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE=x
-S     : don't imply 'import site' on initialization
-u     : force the stdout and stderr streams to be unbuffered;
         this option has no effect on stdin; also PYTHONUNBUFFERED=x
-v     : verbose (trace import statements); also PYTHONVERBOSE=x
         can be supplied multiple times to increase verbosity
-V     : print the Python version number and exit (also --version)
         when given twice, print more information about the build
-W arg : warning control; arg is action:message:category:module:lineno
         also PYTHONWARNINGS=arg
-x     : skip first line of source, allowing use of non-Unix forms of #!cmd
-X opt : set implementation-specific option
--check-hash-based-pycs always|default|never:
         control how Python invalidates hash-based .pyc files
--help-env: print help about Python environment variables and exit
--help-xoptions: print help about implementation-specific -X options and exit
--help-all: print complete help information and exit

Arguments:
file   : program read from script file
-      : program read from stdin (default; interactive mode if a tty)
arg ...: arguments passed to program in sys.argv[1:]
!ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.

Mandatory arguments to long options are mandatory for short options too.
  -a, --all                  do not ignore entries starting with .
  -A, --almost-all           do not list implied . and ..
      --author               with -l, print the author of each file
  -b, --escape               print C-style escapes for nongraphic characters
      --block-size=SIZE      with -l, scale sizes by SIZE when printing them;
                             e.g., '--block-size=M'; see SIZE format below

  -B, --ignore-backups       do not list implied entries ending with ~
  -c                         with -lt: sort by, and show, ctime (time of last
                             change of file status information);
                             with -l: show ctime and sort by name;
                             otherwise: sort by ctime, newest first

  -C                         list entries by columns
      --color[=WHEN]         color the output WHEN; more info below
  -d, --directory            list directories themselves, not their contents
  -D, --dired                generate output designed for Emacs' dired mode
  -f                         same as -a -U
  -F, --classify[=WHEN]      append indicator (one of */=>@|) to entries WHEN
      --file-type            likewise, except do not append '*'
      --format=WORD          across,horizontal (-x), commas (-m), long (-l),
                             single-column (-1), verbose (-l), vertical (-C)

      --full-time            like -l --time-style=full-iso
  -g                         like -l, but do not list owner
      --group-directories-first
                             group directories before files
  -G, --no-group             in a long listing, don't print group names
  -h, --human-readable       with -l and -s, print sizes like 1K 234M 2G etc.
      --si                   likewise, but use powers of 1000 not 1024
  -H, --dereference-command-line
                             follow symbolic links listed on the command line
      --dereference-command-line-symlink-to-dir
                             follow each command line symbolic link
                             that points to a directory

      --hide=PATTERN         do not list implied entries matching shell PATTERN
                             (overridden by -a or -A)

      --hyperlink[=WHEN]     hyperlink file names WHEN
      --indicator-style=WORD
                             append indicator with style WORD to entry names:
                             none (default), slash (-p),
                             file-type (--file-type), classify (-F)

  -i, --inode                print the index number of each file
  -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN
  -k, --kibibytes            default to 1024-byte blocks for file system usage;
                             used only with -s and per directory totals

  -l                         use a long listing format
  -L, --dereference          when showing file information for a symbolic
                             link, show information for the file the link
                             references rather than for the link itself

  -m                         fill width with a comma separated list of entries
  -n, --numeric-uid-gid      like -l, but list numeric user and group IDs
  -N, --literal              print entry names without quoting
  -o                         like -l, but do not list group information
  -p, --indicator-style=slash
                             append / indicator to directories
  -q, --hide-control-chars   print ? instead of nongraphic characters
      --show-control-chars   show nongraphic characters as-is (the default,
                             unless program is 'ls' and output is a terminal)

  -Q, --quote-name           enclose entry names in double quotes
      --quoting-style=WORD   use quoting style WORD for entry names:
                             literal, locale, shell, shell-always,
                             shell-escape, shell-escape-always, c, escape
                             (overrides QUOTING_STYLE environment variable)

  -r, --reverse              reverse order while sorting
  -R, --recursive            list subdirectories recursively
  -s, --size                 print the allocated size of each file, in blocks
  -S                         sort by file size, largest first
      --sort=WORD            change default 'name' sort to WORD:
                               none (-U), size (-S), time (-t),
                               version (-v), extension (-X), name, width

      --time=WORD            select which timestamp used to display or sort;
                               access time (-u): atime, access, use;
                               metadata change time (-c): ctime, status;
                               modified time (default): mtime, modification;
                               birth time: birth, creation;
                             with -l, WORD determines which time to show;
                             with --sort=time, sort by WORD (newest first)

      --time-style=TIME_STYLE
                             time/date format with -l; see TIME_STYLE below
  -t                         sort by time, newest first; see --time
  -T, --tabsize=COLS         assume tab stops at each COLS instead of 8
  -u                         with -lt: sort by, and show, access time;
                             with -l: show access time and sort by name;
                             otherwise: sort by access time, newest first

  -U                         do not sort directory entries
  -v                         natural sort of (version) numbers within text
  -w, --width=COLS           set output width to COLS.  0 means no limit
  -x                         list entries by lines instead of by columns
  -X                         sort alphabetically by entry extension
  -Z, --context              print any security context of each file
      --zero                 end each output line with NUL, not newline
  -1                         list one file per line
      --help        display this help and exit
      --version     output version information and exit

The SIZE argument is an integer and optional unit (example: 10K is 10*1024).
Units are K,M,G,T,P,E,Z,Y,R,Q (powers of 1024) or KB,MB,... (powers of 1000).
Binary prefixes can be used, too: KiB=K, MiB=M, and so on.

The TIME_STYLE argument can be full-iso, long-iso, iso, locale, or +FORMAT.
FORMAT is interpreted like in date(1).  If FORMAT is FORMAT1<newline>FORMAT2,
then FORMAT1 applies to non-recent files and FORMAT2 to recent files.
TIME_STYLE prefixed with 'posix-' takes effect only outside the POSIX locale.
Also the TIME_STYLE environment variable sets the default style to use.

The WHEN argument defaults to 'always' and can also be 'auto' or 'never'.

Using color to distinguish file types is disabled both by default and
with --color=never.  With --color=auto, ls emits color codes only when
standard output is connected to a terminal.  The LS_COLORS environment
variable can change the settings.  Use the dircolors(1) command to set it.

Exit status:
 0  if OK,
 1  if minor problems (e.g., cannot access subdirectory),
 2  if serious trouble (e.g., cannot access command-line argument).

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Full documentation <https://www.gnu.org/software/coreutils/ls>
or available locally via: info '(coreutils) ls invocation'
!python -c "print('hello')"
hello
%%file args.py
import sys

print(sys.argv)
Writing args.py
!python args.py
['args.py']
!python args.py hello awewew qwewqe lkj fsdfjkh 
['args.py', 'hello', 'awewew', 'qwewqe', 'lkj', 'fsdfjkh']
!python args.py vikrant python
['args.py', 'vikrant', 'python']
%%file say_hello.py
import sys

name = sys.argv[1]
print("Hello", name)
Writing say_hello.py
!python say_hello.py vikrant
Hello vikrant
!python say_hello.py python
Hello python
!python say_hello.py Tushar
Hello Tushar
%%file add.py
"""This command adds all numbers given from command line
"""
import sys

nums = sys.argv[1:] # drop first element and take rest
print(nums)
Writing add.py
!python add.py 23 34 54 1 4
['23', '34', '54', '1', '4']
"23" + "34"
'2334'
int("23") + int("24")
47
%%file add.py
"""This command adds all numbers given from command line
"""
import sys

def to_numeric(text_values):

    nums = []
    for textn in text_values:
        nums.append(int(textn))
    return nums

text_nums = sys.argv[1:] # drop first element and take rest
nums = to_numeric(text_nums)
print(nums)
Overwriting add.py
!python add.py 1 2 3 45 6
[1, 2, 3, 45, 6]
%%file add.py
"""This command adds all numbers given from command line
"""
import sys

def to_numeric(text_values):
    nums = []
    for textn in text_values:
        nums.append(int(textn))
    return nums

text_nums = sys.argv[1:] # drop first element and take rest
nums = to_numeric(text_nums)
print(sum(nums))
Overwriting add.py
!python add.py 1 2 3 4 5 6 7 8 9 10
55
!python add.py 1 2
3
!dir 
about.qmd   fibs1.py    module1-day1.ipynb  push          test
add.py      fibs.py     module1-day2.ipynb  __pycache__   topics.qmd
args.py     hello.py    module1-day3.ipynb  _quarto.yml   topics.qmd~
command_fib.py  index.qmd   module1-day4.ipynb  _quarto.yml~  trainer.qmd
day4.org    index.qmd~  module2-day1.ipynb  say_hello.py
day4.org~   Makefile    notes.qmd       _site
empty.py    Makefile~   notes.qmd~      styles.css
import importlib
importlib.reload(fibs)
<module 'fibs' from '/home/vikrant/programming/work/github/vikrant.dev/python-foundation-professionals/fibs.py'>
import datetime
%%file todays_date.py
import datetime

print(datetime.datetime.now())
Writing todays_date.py
!python todays_date.py
2025-12-23 08:16:18.831535
import add # this import is happening in this jupyter instance
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[86], line 1
----> 1 import add # this import is happening in this jupyter instance

File ~/programming/work/github/vikrant.dev/python-foundation-professionals/add.py:12
      9     return nums
     11 text_nums = sys.argv[1:] # drop first element and take rest
---> 12 nums = to_numeric(text_nums)
     13 print(sum(nums))

File ~/programming/work/github/vikrant.dev/python-foundation-professionals/add.py:8, in to_numeric(text_values)
      6 nums = []
      7 for textn in text_values:
----> 8     nums.append(int(textn))
      9 return nums

ValueError: invalid literal for int() with base 10: '-f'
import sys
sys.argv
['/home/vikrant/usr/local/default/lib/python3.13/site-packages/ipykernel_launcher.py',
 '-f',
 '/home/vikrant/.local/share/jupyter/runtime/kernel-31cfd2d4-f205-4040-92a3-1a52b149e7b8.json']
int("-f")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[89], line 1
----> 1 int("-f")

ValueError: invalid literal for int() with base 10: '-f'
%%file add.py
"""This command adds all numbers given from command line
"""
import sys

def to_numeric(text_values):
    nums = []
    for textn in text_values:
        nums.append(int(textn))
    return nums


if __name__ == "__main__":
    text_nums = sys.argv[1:] # drop first element and take rest
    nums = to_numeric(text_nums)
    print(sum(nums))
Overwriting add.py
import add
!python add.py 1 2 3 4 5
15
%%file checkname.py

print(__name__)
Writing checkname.py
!python checkname.py
__main__
import checkname
checkname
!python checkname.py
__main__
add.to_numeric(["1", "2", "3"])
[1, 2, 3]
%%file tax_computation.py
import sys

slab1 = 500000
slab2 = 750000
slab3 = 1000000

def compute_tax(income):
    if income < slab1:
        return 0
    elif income < slab2:
        return (income - slab1)*5/100
    elif income < slab3:
        return (income - slab2)*8/100
    else:
        return (income- slab3)*10/100

if __name__ == "__main__":
    income = float(sys.argv[1])
    print(compute_tax(income))
Overwriting tax_computation.py
import tax_computation
tax_computation.slab1
500000
tax_computation.compute_tax(100000)
0
import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Reading files

%%file poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Writing poem.txt
with open("poem.txt") as file:
    print(file.read())
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
with open("poem.txt") as f:
    contents = f.read()

lines = contents.split("\n")
for line in lines:
    print(line)
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
contents
"The Zen of Python, by Tim Peters\n\nBeautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!\n"
print(contents)
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
with open("poem.txt") as f:
    print(f.readline())
The Zen of Python, by Tim Peters
with open("poem.txt") as f:
    for line in f: # this will give me line by line ..but line will have \n
        print(line)
The Zen of Python, by Tim Peters



Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren't special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one-- and preferably only one --obvious way to do it.

Although that way may not be obvious at first unless you're Dutch.

Now is better than never.

Although never is often better than *right* now.

If the implementation is hard to explain, it's a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea -- let's do more of those!
with open("poem.txt") as f:
    for line in f: # this will give me line by line ..but line will have \n
        print(line.strip())
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!