模块的导入
python模块的导入
每一个以.py结尾的源文件都是一个模块。在python中不需要任何特殊代码或者语法来使文件成为模块。
其它模块也可以导入其它模块,导入的本质就是载入另一个文件,一个模块的内容都是通过其属性从而被外部世界所使用。
一个完整的python程序往往是由多个模块组成,其中一个模块文件被指定为主文件,或者称为顶层文件。
如果一个模块被好几个模块导入,只需要导入一次,而不需要将同一个模块导入多次。
模块的属性
在python中一切皆是对象,那么模块也应该是对象,底层也就是一个PyObject结构体。
typedef struct {
PyObject_HEAD
PyObject *md_dict; // 模块的字典(命名空间),存储所有变量
PyModuleDef *md_def; // 模块的定义(对于 C 扩展模块尤为重要)
void *md_state; // 模块的状态(用于多解释器隔离)
PyObject *md_weakreflist; // 弱引用列表
PyObject *md_name; // 模块名 (__name__)
} PyModuleObject;
在导入模块的时候,就是在初始化这个结构体中的每一个字段。
简而言之就是一个模块的顶层的所有属性(变量,函数,类)都会放在模块的字典当中。

代码如下:
# password.py
def hash_password(password):
return password
class Password:
def __init__(self, password):
self.password = password
title = "password"
from password import title
class User:
def __new__(cls, *args, **kwargs):
print("__new__")
instance = super().__new__(cls)
return instance
def __init__(self, name):
print("__init__")
self.name = name
self.phone = ""
self.email = ""
self.password = ""
def __str__(self):
return "name:"+self.name + "\n" + "phone:"+self.phone + "\n" + "email:"+self.email
def __getattr__(self, item):
print(item,"不存在")
def set_phone(self, phone):
self.phone = phone
def set_email(self, email):
self.email = email
def set_password(self, pwd):
self.password = title
# top level code
topUser =User("top")
topUser.set_phone("111111111")
topUser.set_email("top@top.com")
topUser = "topuser"
print(topUser)
这里需要注意的是import password和from password import title的区别:
import会生成password模块对象,并添加到模块字典中。
>>> dir(user)
['User', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'password', 'topUser']
>>> user.password
<module 'password' from 'Z:\\projects\\python\\base-concept\\core-programming\\chapter3\\password.py'>
from password import title,它只会将title对象赋值到模块字典中,至于password模块对象是不会被复制到字典当中的。但是这里需要注意的是,如果password模块对象没有被创建,那么这里会创建一个模块对象,然后放在sys.modules中。
python中的包和go中的包
go语言通过package指定一个文件属于某个包。
python把单个文件当作一个模块或者包,那么这个包的功能很多时,单个模块文件就很大。所以可以采用__init__.py文件构成类似于go的包的概念。
network/
├── __init__.py
├── protocol.py (存放协议逻辑)
├── client.py (存放客户端逻辑)
└── server.py (存放服务端逻辑)
在__init__.py中拉去内容。
# network/__init__.py
from .protocol import Protocol
from .client import HttpClient
from .server import HttpServer
然后就可以像使用模块中的属性那样使用该包中的内容。
import network
client = network.HttpClient() # 看起来就像 network 是一个大模块