模块1



1. MODULE

1.1 模块是什么

模块就是python程序

官方解释:

If you quit from the Python interpreter and enter it again, the definitions you have made (functions and variables) are lost. Therefore, if you want to write a somewhat longer program, you are better off using a text editor to prepare the input for the interpreter and running it with that file as input instead. This is known as creating a script. As your program gets longer, you may want to split it into several files for easier maintenance. You may also want to use a handy function that you've written in several programs without copying its definition into each program.

To support this, Python has a way to put definitions in a file and use them in a script or in an interactive instance of the interpreter. Such a file is called a module; definitions from a module can be imported into other modules or into the main module (the collection of variables that you have access to in a script executed at the top level and in calculator mode).

A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Within a module, the module's name (as a string) is available as the value of the global variable __name__.

1.2 怎么使用模块

>>> import math
>>> math.sqrt(16)
4.0
# 不可以直接使用math中的函数或变量
>>> sqrt(16)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'sqrt' is not defined
>>> from math import sqrt
>>> sqrt(16)
4.0
# 不可以用math.sqrt()的方式
>>> math.sqrt(16)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'math' is not defined

少用from module import *,会污染命名空间

1.3 怎么定义模块

1.3.1 一个文件就是一个模块

# 不要跟内置模块重名
# vi os.py
*****************************
def say():
    print 'hi'
*****************************

python解释器默认会寻找当前目录下的py文件,但会忽略和内置模块重名的文件

>>> import os
# 报错是因为现在的os是builtin的os模块,没有say()
>>> os.say()              
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'say'

让我们把此文件换个名字

mv os.py module_test.py

然后再尝试

>>> import module_test
>>> module_test.say()
hi

1.3.2 Python查找模块的过程: built in module --> sys.path(当前目录包含在sys.path中)

# 导入sys module,把/root/py加入到python环境变量里
>>> import sys
>>> sys.path     # sys.path是sys模块中的一个list,用于储存python路径变量
['', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/usr/lib64/python2.7/site-packages', '/usr/lib/python2.7/site-packages']
>>> sys.path.append("/root/py")
>>> sys.path[-1]
'/root/py'
# 在python环境变量path中/root/py和当前目录/root中放入统一名称的py文件os.py
# 当前目录下的os.py
cat /root/os.py
def say():
    print 'hi,this is /root/ !'

# path环境变量/root/py/中的os.py
cat /root/py/os.py
def say():
    print 'hi,this is /root/py !'

进入python解释器验证

>>> import sys
>>> sys.path.append("/root/py")
>>> import os
>>> os.say()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'say'

结论1:说明首先调用的是built in的module

接下来我们改掉os.py的名称

mv /root/os.py /root/so.py
mv /root/py/os.py /root/py/so.py

重新进入python解释器

>>> import sys
>>> sys.path.append("/root/py")
>>> import so
>>> so.say()
hi,this is /root/ !

结论2:说明第二调用的是当前目录的module

删掉当前目录下的py编译文件so.pyc和把当前目录下的so.py改名

mv /root/so.py /root/current_so.py
rm -f so.pyc

进入python解释器

>>> import sys
>>> sys.path.append("/root/py")
>>> import so
>>> so.say()
hi,this is /root/py !

结论3:由此说明,python调用模块的优先级是bulit in –》 当前目录 –》 sys.path

后来经老师指正:sys.path[0] = '',这个''就是当前目录

1.3.3 模块导入初始化 import only once

vi inital.py
******************************
def say():
    print 'hi,this is /root/ !'

say()
******************************
>>> import inital
hi,this is /root/ !                           # 初次导入时输出了say()
>>> import inital                             # 再次导入时并未执行say()
>>> reload(inital)
hi,this is /root/ !                           # reload时会再次say()
<module 'inital' from 'inital.pyc'>
# 模块的导入其实主要是初始化,用于定义一些变量、函数、类等,而且是import only once,如果再次import并不会再次初始化变量等信息

1.3.4 扩展、如何让模块导入的时候不执行say()?

cat inital.py
def say():
    print 'hi,this is /root/ !'

if __name__ == '__main__':
    say()

进入到python解释器

>>> import inital            # 再次导入,不会再输出say()的执行结果了

if __name__ == '__main__':这是用来判断name是不是主函数,如果不是直接执行此模块,此if代码块不会执行

1.4 使用dir查看模块内容

已多次演示,不再赘述

1.5 控制模块对外接口

__all__

vi exam1.py
*************************************
__all__ = ["print_func"]

def print_func():
    print "function 1 print() in module"

def say():
    print "function 2 say() in module"
***************************************

进入python解释器

>>> from exam1 import *
>>> say()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'say' is not defined
>>> print_func()
function 1 print() in module

重新进入python解释器

>>> import exam1
>>> exam1.say()
function 2 say() in module

重新进入python解释器

>>> from exam1 import say
>>> say()
function 2 say() in module

1.6 扩展、optparse使用

预留位置

2. 课后作业:

  1. 自己实现下炒菜的例子, 如果A这时想让B帮她买菜怎么办? 2.使用模块改造之前的缓存装饰器,把缓存装饰器放到一个模块中,另外的fib放在主模块中,主模块需要引入缓存装饰器,来达到缓存的目的。

1、答案 chaocai.py

"""we provide the service of make food"""

__all__ = ["zuocai", "buy"]

def zuocai(cai):
    print "get your %s, will finish later" % cai
    qiecai(cai)
    dianhuo()
    fanchao(cai)
    zhuangpan(cai)

def buy(cai):
    print "buy the %s for you, will fire later" %cai
    zuocai(cai)

def qiecai(cai):
    print "cut %s" % cai

def dianhuo():
    print "fire is ready"

def fanchao(cai):
    print "stir fry %s for 5 minutes" % cai

def zhuangpan(cai):
    print "transfer %s to a plate" % cai

hungry.py

"""feel hungry? we can make food for you"""

from chaocai import *

def maicai(cai):
    print "bought the %s" % cai
    return cai

def ask_to_buy(cai):
    print "pls buy %s for me" % cai
    return cai

if __name__ == "__main__":
    if raw_input("do you want buy vege yourself?(yes or no)") == "yes":
        cai = maicai("cabbage")
        zuocai(cai)
    else:
        cai = ask_to_buy("cabbage")
        buy(cai)

2、答案 fib_cache.py

'''decorator'''

__all__ = ["cache"]

def cache(func):
    cache_dic = dict()
    def inner(args):
        if args not in cache_dic:
            cache_dic[args] = func(args)
        else:
            print '\thit cache'
        return cache_dic[args]
    return inner

fib.py

'''recurision'''

from fib_cache import *

@cache
def fib(n):
    if n <= 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)

if __name__ == "__main__":
    while True:
        number = raw_input("input a number pls:")
        if number == 'quit':
            break
        try:
            number = int(number)
        except ValueError as e:
            print e
        print "\t============================\n\tthe %dth fib is %r" %(number, fib(number))