Quantcast
Channel: Sam的技术Blog
Viewing all articles
Browse latest Browse all 158

Python module相关知识

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

Sam学习使用Python不久,就Python module的理解有限。因为此原因,在工作中遇到一些疑惑。现把学习过程记录下来。


0. Python Module 的最初认识

模块让你能够有逻辑地组织你的Python代码段。

把相关的代码分配到一个 模块里能让你的代码更好用,更易懂。

模块也是Python对象,具有随机的名字属性用来绑定或引用。

简单地说,模块就是一个保存了Python代码的文件。模块能定义函数,类和变量。模块里也能包含可执行的代码。


Sam学习Python的过程,主要是跟着《Learn PYTHON the Hard WAY》,其中习题40中,明确指出,

A: 模块是包含函数和编来那个的Python文件。

B: 其它程序可以导入这个文件。

C: 然后可以使用  . 操作符访问模块中的函数和变量。


例1:

supports.py:

def apple():

print "I am an Apple!"

tangerine = "Living reflection of a dream"



接下来就可以import这个模块,并用 .操作符调用函数。


import  supports

supports.apple()

print supports.tangerine



1. 模块的导入

模块的导入方式有以下几种: 

A: import

B: from .... import

C: from .... import *


导入模式的异同:

A:import:

import  supports

supports.apple()

print supports.tangerine

在调用函数,变量和类时,需要使用模块名+.操作符调用。


B:from ModuleName import name

from语句让你从模块中导入一个指定的部分到当前命名空间中.

from supports import apple

这个声明不会把整个supports模块导入到当前的命名空间中,它只会将supports里的apple单个引入到执行这个声明的模块的全局符号表。


C: from ModuleName import *

把一个模块的所有内容全都导入到当前的命名空间也是可行的


B和C连个方式,在使用函数,变量和类时,不需要使用模块名+.操作符调用。 而是直接调用。

例如:

from  supports import *

apple()

print tangerine



2. 模块定位:

当使用import ,from... import...导入模块时, Python解析器对模块定位的搜索顺序为:

1. 当前目录。 (即input script所在目录)

2. shell 变量 PYTHONPATH下的每个目录。

3. 默认目录。Python安装目录。 如: /usr/local/lib/python



截至到现在,Python module还是很清晰的。Python由 modulename.py构成。内容放置在modulename.py中。modulename就是文件名。

文件名就是模块名加上后缀.py

导入方式有三种。看来没啥问题。


3. 模块导入的具体行为:

一个模块被导入,那些内容被执行,哪些不被执行呢?这就是模块导入的具体行为定义的:

每个module都包含对象定义和一些语句(statements),这些语句应该是意图要来初始化这个module的,这些语句会在这个module第一次被import的时候执行(多次import只会执行一次,不管是以上两种import的语句中那一种),当这个module被作为一个script来运行的时候也会被执行。


每个module都有自己的private symbol table,当使用第一种import语句import一个module的时候,引入者的local symbol table就加入了这个module,其名字如果没有使用as的话就是被引入的模块名本身。使用第二种import语句这会在引入者的local symbol table中加入具体引用的item,其名称若没使用as则就为item的名称。

这就是为何单纯import时,需要用modulename.item. 而是用from...import时, 直接调用item本身。


例:

fibo.py如下:


1 print ("__name__ :", __name__)
2 def fib(n):
3         a, b = 0, 1
4         result = []
5         print ("in fib():", __name__)
6         while (b<<span style="font-family: 'Courier New' !important;">n):
7                 result.append(b)
8                 a, b = b, a+b                                                                                                             9         print(result)

这个fibo.py就是一个module,它有一个函数定义fib(),和一个语句(statement),第一行的print语句,我们在当前文件目录运行Python Interpreter就可以去引入这个模块,并执行模块中定义的fib()函数。


>>> import fibo
('__name__ :', 'fibo')         #print语句执行
>>> fibo.fib(10)
('in fib() :', 'fibo')         #fib()函数执行
[1, 1, 2, 3, 5, 8]

可以看到,在import的时候,这个module的语句(statements)执行了,所定义的函数并未执行,在通过module名引用module中的函数定义时,函数才被执行。

同样可以在一个script file中引入module,我们在fibo.py所在的目录创建另一个文件calculat.py


1 from fibo import fib                                                                                                                      2 for n in range(10, 50, 5):
3         fib(n)

然后用Python解释器运行calcute.py得到结果。


4. Python标准库:

Python有一个标准库,其中定义了一系列的module,这些module中的一部分是直接集成在Interpreter中的,这些built-in module主要提供了很重要的但是Python语言又没有提供的功能,比如跟system call有关的sys module就集成在所有平台的Python Interpreter中,在Interpreter中集成哪些module是可以配置的,并且随平台不同而有差别。




遇到问题:

Sam在看一些例子代码时,首先遇到了:

import serial

import socket

等语句。

那按照以上认识,就应该有serial.py, socket.py等module存在。但Sam在当前目录,PYTHONPATH,/usr/local/lib/python等目录下均未能发现。这就有了疑问。



在疑问研究中,看到如下用法:

#pry

>>>import serial

>>>print serial.__file__

/usr/lib/python2.7/dist-packages/serial/__init__.pyc


>>>import socket

>>>print socket.__file__

/usr/lib/python2.7/socket.pyc

__file__指向该模块的导入文件名


Sam由此想到,是否除了  *.py, 还有类似 *.pyc的模块名呢?但__init__.py又是什么鬼?这就牵涉出Python中另一个概念---Pakcage。



5. python中的Package

Package是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的Python的应用环境。

package是一个directory,它包含sub-package或者是module,而module是.py文件,要让Python Interpreter把一个目录作为package,则该目录下必须有__init__.py文件,__init__.py可以为空,当然也可以有对象定义和语句,用来做初始化工作,__init__.py还有个作用就是设置__all__变量。

package本身就可以来作为一个module使用,只是它所包含的sub-module或module可以通过package name用package.module的名称形式去引用,这更有利于组织一系列相关的module,避免module间定义的名称的混乱。

package在实际工程中非常常用,__init__.py也常常不会为空,而会有对象定义和初始化代码来让这个包,也就是这个module,包含其该有的item定义。以后我们会对package做更多了解。




考虑一个在Phone目录下的pots.py文件。这个文件有如下源代码:


#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
def Pots():
   print "I'm Pots Phone"
   

同样地,我们有另外两个保存了不同函数的文件:

  • Phone/Isdn.py 含有函数Isdn()
  • Phone/G3.py 含有函数G3()

现在,在Phone目录下创建file __init__.py:

  • Phone/__init__.py

当你导入Phone时,为了能够使用所有函数,你需要在__init__.py里使用显式的导入语句,如下:


from Pots import Pots
from Isdn import Isdn
from G3 import G3

当你把这些代码添加到__init__.py之后,导入Phone包的时候这些类就全都是可用的了。


#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
# 导入 Phone 包
import Phone
 
Phone.Pots()
Phone.Isdn()
Phone.G3()

以上实例输出结果:


I'm Pots Phone
I'm 3G Phone
I'm ISDN Phone

如上,为了举例,我们只在每个文件里放置了一个函数,但其实你可以放置许多函数。你也可以在这些文件里定义Python的类,然后为这些类建一个包。



通过学习Pakcage,就可以完全解释:/usr/lib/python2.7/dist-packages/serial/__init__.pyc

即serial是一个pakcage.




具体举例分析:

port_publisher.py:


import os

import select

import socket

import sys

import time

import traceback


import serial

import serial.rfc2217

import slerialtools.list_ports


import dbus


其中,serial 就是一个Package.  在serial目录内,包含有__init__.py.














































/


 

Viewing all articles
Browse latest Browse all 158

Trending Articles