Week 1.1

Python's Project Structure

How do you know you are reading a Java project?

I am making fun of Java developers.

Hint

Think of directories.

Use your eyes

Lots of empty directories.

Humor

I have a lot

How do you recongize Python's?

Python's Project Structure

Usual recommendation:

top-level-dir/
    bitbucket/
        __init__.py
        apis.py
    tests/
        __init__.py
        unittest/
            __init__.py
            test_apis.py
    LICENSE.txt
    MANIFEST.in
    README.rst
    setup.py

We will come back to this later.

A simple Python Script

print 'Hello World'

save this as hello.py and run python hello.py.

Every .py file is a script

Like Matlab's m file.

Every .py file is also a module

A python file is a module by definition. Just a fancy name.

So

If we have hello.py, we can say:

I am going to import the hello module.

You are saying, I want to import whatever craps you have in hello.py file.

Understand?

Try this exercise

print 'Hello World'
>>> import hello
Hello World
>>>

You see that?

What just happened?

You just imported a module named hello which is also the name of the file.

Module import triggers execution, so print statement is called.

Remember

When you import your module the first time (and only the first time any import is done), Python interpreter will execute all top-level statements (and functions and classes).

print 'Hello World'

def foo():
    print 'Will I see this statement?'

foo()

You will see two lines printed out. foo is a callable and is top-level.

Another exercise

Try this piece of code in your hello.py

print 'Hello World'

def foo():
    print 'Will I see this statement?'

foo()

def bar():
    print 'Will I see this statement as well!!!???'

Will you see the 3rd print statement?

Answer? No

The print statement from bar() is not executed. The declaration def is checked. But the function is not called as top-level statement.

Try this!

print 'Hello World'

def foo():
    print 'Will I see this statement?'

foo()

def bar():
    print 'Will I see this statement as well!!!???'

def foobar():
    print 'missing end quotation mark

If we run this, you will get SyntaxError. The def is a statement. But the block contains invalid code. The statement thus failed.

Next, package

Definition

Any directory with at least a __init__.py file is considered a Python package.

Think of package as a collection of .py files under a named directory.

Example

Example

xkcd

http://xkcd.com/353/

Browse Django's source code

Go to https://github.com/django/django/tree/master/django

import

Java has this. You can think of this as #include directive from C and C++.

import django
import django.http
from django import http
from django.http import utils
from django.http import *

import the whole package

django is the name of the project, and is also the name of the top-most package.

import django

You are importing the entire django library! We want to use Http404 from django/http/response.py.

import django.http
print django.http.response.Http404

You get <class 'django.http.response.Http404'>

import django....: No module named xxxx

Watch out. If you use import django.http.response.Http404, you are going to get

Traceback (most recent call last):
File "h.py", line 1, in <module>
  import django.http.response.Http404
ImportError: No module named Http404

The last item in the chain dot list must either be a package or a module.

import package
import package.module
import package.module.subpackage
import package.module.subpackage.module
.... etc

Long import is not optimal

Sometimes, get down to specific one

from django ...

You can do these:

from django import http     # now you can write http.response.Http404
from django.http import response    # now you can write response.Http404
from django.http.response import Http404    # now you can write Http404

wildcard *

Avoid this. Bad!

from django import *
from django.http.response import *

You can have name conflict!

# this is hello.py
#  Http404, HttpResponseNotFound and many are in the same namespace
from django.http.response import *

# My custom HttpResponseNotFound. Not the same one from Django
class HttpResponseNotFound(object):
    pass

import with abbreviation

import django.http.response
print django.http.response.Http404

import django.http.response as res
print res.Http404

The as makes an alias to the name.

conditional import with as

This is useful in the case of conditional import.

try:
    import unittest2 as unittest
except ImportError:
    import unittest

class TestMyAwesomeTest(unittest.TestCase):
    .....

If unittest2 is not there, I can fall back to unittest library!

Conclusion?

Avoid wildcard import!

from django import *
from django.http import *

OKAY with long name import

import django.http.response

BETTER with these

import django
from django.http.response import Http404

Use as when you want to make a short alias or for compatbililty (fall back).

Exercise

Assume you have a directory called "week11", I want to be able to import these, how would you structure your project?

import week11.plugins
from week11.plugins import core
from week11.plugins.core import converter

Before you launch a new interpreter, make sure you are at the same level as the directory week11.

>> import os
'/home/yeukhon'
# I have a directory called  '/home/yeukhon/week11'

Solution

Look at this repo: https://bitbucket.org/yeukhon/python-workshop-spring13/src

Finally, project structure

Usual recommendation:

top-level-dir/
    bitbucket/
        __init__.py
        apis.py
    tests/
        __init__.py
        unittest/
            __init__.py
            test_apis.py
    LICENSE.txt
    MANIFEST.in
    README.rst
    setup.py

Examples:

  1. django
  2. bitbucket-python-api

Are we okay?

We still have to cover packaging and how to use __init__.py efficently.

I will cover that in the future.

SpaceForward
Left, Down, Page DownNext slide
Right, Up, Page UpPrevious slide
POpen presenter console
HToggle this help