Python之import关键字探索

简介: Java和Python玩家对import关键字一点都不陌生,本文以python为例,试着理解一下。 ##1. 环境变量 可以猜到,在import模块时,python会从环境变量中搜索需要加载的模块,这个列表就存放在sys.path变量中,可以进行修改。想要引入时,首先要将路径放到环境变量中。 对环境变量临时修改,将```/home/admin/git```添加进来,示例如下: ```b

Java和Python玩家对import关键字一点都不陌生,本文以python为例,试着理解一下。

1. 环境变量

可以猜到,在import模块时,python会从环境变量中搜索需要加载的模块,这个列表就存放在sys.path变量中,可以进行修改。想要引入时,首先要将路径放到环境变量中。
对环境变量临时修改,将/home/admin/git添加进来,示例如下:

>>> import sys
>>> '/home/admin/git' in sys.path
False
>>> sys.path.append('/home/admin/git')
>>> '/home/admin/git' in sys.path
True
>>> print sys.path
['', '/usr/lib64/python26.zip', '/usr/lib64/python2.6', '/usr/lib64/python2.6/plat-linux2', '/usr/lib64/python2.6/lib-tk', '/usr/lib64/python2.6/lib-old', '/usr/lib64/python2.6/lib-dynload', '/usr/lib64/python2.6/site-packages', '/usr/lib64/python2.6/site-packages/gtk-2.0', '/usr/lib/python2.6/site-packages', '/home/admin/git']

类似windows系统变量,在查询时,也是按照列表的顺序进行遍历

2. 模块查询和加载

参考python PEP302,详细讲解了如何导入钩子机制,简单分为了两步模块导入和模块加载

The protocol involves two objects: a finder and a loader . A finder object has a single method:

finder.find_module(fullname, path=None)
loader.load_module(fullname)

2.1 finder.find_module实现

这个很容易理解,文件查询而已,有的是.py文件,有的是带目录package的。

import sys
import os
class ModuleFinder:
    def find_on_path(self, fullname):
        fls = ['%s/__init__.py', '%s.py']
        # import xx.oo.tt package导入,和java导入一样
        dirpath = '/'.join(fullname.split("."))

        for path in sys.path:
            path = os.path.abspath(path)
            for fp in fls:
                composed_path = fp % ("%s/%s" %(path, dirpath))
                if os.path.exists(composed_path):
                    # print composed_path
                    return composed_path

    def find_module(self, fullname, path=None):
        path = self.find_on_path(fullname)
        if path:
            do_something_else()

测试代码和结果如下:

# test case
f = ModuleFinder()
f.find_module('os')
f.find_module('urllib')
f.find_module('json')
/usr/lib64/python2.6/os.py
/usr/lib64/python2.6/urllib.py
/usr/lib64/python2.6/json/__init__.py

2.2 loader.load_module的实现

PEP302中,给出了一个简单的模块加载器:

# Consider using importlib.util.module_for_loader() to handle
# most of these details for you.
def load_module(self, fullname):
    code = self.get_code(fullname)
    ispkg = self.is_package(fullname)
    mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
    mod.__file__ = "<%s>" % self.__class__.__name__
    mod.__loader__ = self
    if ispkg:
        mod.__path__ = []
        mod.__package__ = fullname
    else:
        mod.__package__ = fullname.rpartition('.')[0]
    exec(code, mod.__dict__)
    return mod

将这个函数补充完善一下, 其中import_file_to_module是将源码弄成Python模块对象并返回,还有,要将模块的各类属性给塞进去。以json为例,他的属性列表(两个'_'开头结尾的)如下:

>>> import json
>>> dir(json)
['JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__version__', '_default_decoder', '_default_encoder', 'decoder', 'dump', 'dumps', 'encoder', 'load', 'loads', 'scanner']
>>>

具体加载器实现如下:

class ModuleLoader(object):
    def __init__(self, path):
        self.path = path
    # package中包含文件__init__.py
    def is_package(self, fullname):
        dirpath = '/'.join(fullname.split("."))
        
        for path in sys.path:
            path = os.path.abspath(path)
            composed_path = '%s%s/__init__.py' % (path, dirpath)
            if os.path.exists(composed_path):
                return True
            return False
            
    def load_module(self, fullname):
        if fullname in sys.modules:
            return sys.modules(fullname)
        
        if not self.path:
            return
        sys.modules[fullname] = None
        # 读取源文件,编译成python代码,返回一个Python模块对象
        mod = import_file_to_module(fullname, self.path)
        
        ispkg = self.is_package(fullname)
        
        # 将模块的属性写上
        mod.__file__ = self.path
        mod.__loader__ = self
        mod=.__name__ = fullname
        
        # 如果引入的是一个package,还有其他属性
        if ispkg:
            mod.__path__ = []
            mod.__package__ = fullname
        else:
            mod.__package__ = fullname.rpartition('.')[0]
            
        sys.modules[fullname] = mod
        return mod

用的最多的东西反而最容易被忽视,比如C语言printf(),C++的cout,Ruby的Require等等。
拿来玩一玩,跟挖宝一样,蛮有意思的~~

参考内容

  1. PEP 302是什么?
  2. 书籍《Python高手之路》第二章 模块和库
  3. Experience of Python's “PEP-302 New Import Hooks”
目录
相关文章
|
5月前
|
算法 Java Docker
(Python基础)新时代语言!一起学习Python吧!(三):IF条件判断和match匹配;Python中的循环:for...in、while循环;循环操作关键字;Python函数使用方法
IF 条件判断 使用if语句,对条件进行判断 true则执行代码块缩进语句 false则不执行代码块缩进语句,如果有else 或 elif 则进入相应的规则中执行
799 1
|
6月前
|
缓存 供应链 监控
1688item_search_factory - 按关键字搜索工厂数据接口深度分析及 Python 实现
item_search_factory接口专为B2B电商供应链优化设计,支持通过关键词精准检索工厂信息,涵盖资质、产能、地理位置等核心数据,助力企业高效开发货源、分析产业集群与评估供应商。
|
6月前
|
JSON 监控 数据格式
1688 item_search_app 关键字搜索商品接口深度分析及 Python 实现
1688开放平台item_search_app接口专为移动端优化,支持关键词搜索、多维度筛选与排序,可获取商品详情及供应商信息,适用于货源采集、价格监控与竞品分析,助力采购决策。
|
6月前
|
缓存 监控 算法
唯品会item_search - 按关键字搜索 VIP 商品接口深度分析及 Python 实现
唯品会item_search接口支持通过关键词、分类、价格等条件检索商品,广泛应用于电商数据分析、竞品监控与市场调研。结合Python可实现搜索、分析、可视化及数据导出,助力精准决策。
|
6月前
|
JSON 缓存 供应链
电子元件 item_search - 按关键字搜索商品接口深度分析及 Python 实现
本文深入解析电子元件item_search接口的设计逻辑与Python实现,涵盖参数化筛选、技术指标匹配、供应链属性过滤及替代型号推荐等核心功能,助力高效精准的电子元器件搜索与采购决策。
|
6月前
|
缓存 自然语言处理 算法
item_search - Lazada 按关键字搜索商品接口深度分析及 Python 实现
Lazada的item_search接口是关键词搜索商品的核心工具,支持多语言、多站点,可获取商品价格、销量、评分等数据,适用于市场调研与竞品分析。
|
8月前
|
人工智能 JavaScript 前端开发
Python中常见的关键字
Python中常见的关键字是语言内置的特殊单词,具有特定功能,如控制逻辑、定义函数等。关键字不可作为变量名使用,否则会导致语法或类型错误。本文详细介绍了关键字的含义、分类及常见示例,并列举了常见报错原因与解决方法。
298 0
|
8月前
|
存储 人工智能 大数据
Python中的yield关键字
在Python中,`yield`关键字用于创建生成器函数,实现懒惰计算和状态保存。它能逐个生成值,节省内存,适用于处理大数据集或无限序列。通过生成器函数和表达式,可以高效地进行数据过滤与递增序列生成,提高代码效率与可维护性。
483 0
|
缓存 JSON 数据处理
Python进阶:深入理解import机制与importlib的妙用
本文深入解析了Python的`import`机制及其背后的原理,涵盖基本用法、模块缓存、导入搜索路径和导入钩子等内容。通过理解这些机制,开发者可以优化模块加载速度并确保代码的一致性。文章还介绍了`importlib`的强大功能,如动态模块导入、实现插件系统及重新加载模块,展示了如何利用这些特性编写更加灵活和高效的代码。掌握这些知识有助于提升编程技能,充分利用Python的强大功能。
915 4