zoukankan      html  css  js  c++  java
  • python modules and packages

    https://realpython.com/python-modules-packages/

    在软件开发中,一个module是具有一些相关功能的软件集合,比如,当你在开发一个游戏时,可能会有一个模块负责game logic,而另一个module负责在屏幕上绘制对应的界面。每个module是一个不同的文件,可以单独编辑

    modules

    python中每一个单独的.py文件就是一个module,模块的名称就是文件的名称。一个module可以有一组函数,类或者变量。比如,上面说道的游戏开发中,可能会有两个文件组成的两个module:

    # game.py
    # import the draw module
    import draw
    
    def play_game():
        ...
    
    def main():
        result = play_game()
        draw.draw_game(result)
    
    # this means that if this script is executed, then 
    # main() will be executed
    if __name__ == '__main__':
        main()

    在上面的game模块中,我们定义了play_game函数,它将使用定义在draw模块中的draw_game函数。而draw模块中实现draw_game对应的逻辑。

    下面我们看看draw 模块长的样子:

    # draw.py
    
    def draw_game():
        ...
    
    def clear_screen(screen):
        ...

    在本例子中game module通过import draw来加载draw模块,而这将赋能game模块引用draw模块中实现的函数或者类。为了使用draw模块中的draw_game,我们需要通过dot点操作符告知game块draw_game是哪个模块中的实现。

    当import draw这个directive被执行时,python解释器将从game.py文件所在目录开始寻找draw.py文件,如果没有找到,python解释器将继续在built-in内置模块中寻找。

    你可能注意到当导入一个module时,将会有一个.pyc文件出现,这个文件是一个编译过的Python文件。python解释器将module文件编译成python的byte code以便不用每次Import时都需要重新解析他。如果已经有了.pyc文件存在,则直接加载draw.pyc文件,这个过程对于用户来说是透明的。

    importing module objects到当前的命名空间namespace

    我们可以通过from及import命令将对应模块的函数加载到主脚本所在的命名空间中:

    # game.py
    # import the draw module
    from draw import draw_game
    
    def main():
        result = play_game()
        draw_game(result)

    通过上面的from, import后我们就不用再使用prefixmodule.function的方式来引用,而只需要function了,因为function已经存在于主脚本的命名空间里面了!

    import all objects from module

    # game.py
    # import the draw module
    from draw import *
    
    def main():
        result = play_game()
        draw_game(result)

    自定义加载后的命名

    # game.py
    # import the draw module
    if visual_mode:
        # in visual mode, we draw using graphics
        import draw_visual as draw
    else:
        # in textual mode, we print out text
        import draw_textual as draw
    
    def main():
        result = play_game()
        # this can either be visual or textual depending on visual_mode
        draw.draw_game(result)

    上面的例子中,使用as关键字,以及条件加载使得不同的module中定义的函数使用同一个名称draw

    module initialization

    当一个module首次被加载时,对应module的代码将会执行一次以便初始化。如果其他的模块再次加载同一个module,则不会再重复加载!因此,module中的局部变量就像一个singleton一样,因为他们仅会初始化一次。

    # draw.py
    
    def draw_game():
        # when clearing the screen we can use the main screen object initialized in this module
        clear_screen(main_screen)
        ...
    
    def clear_screen(screen):
        ...
    
    class Screen():
        ...
    
    # initialize main_screen as a singleton
    main_screen = Screen()

    看上面的例子,main_screen就是首次加载draw模块式初始化的变量,不会重复初始化!

    扩展module的加载路径

    在加载module时,除了默认的寻找路径:主脚本目录以及内置module外,我们可以通过以下方法告知python解释器,哪里可以去寻找对应的module:

    • PYTHONPATH变量:
    • sys.path.append
    PYTHONPATH=/foo python game.py
    sys.path.append("/foo") #在执行import之前运行该代码

    built-in modules

    和每个python发行版伴随的有很多内置的Python库,这些built-in modules使用C语言编写,提供诸如访问系统功能比如文件I/O的功能,这些库也提供一些常见问题的通用解决方案供调用。还有部分builtin模块用于抽象Python应用程序,以便和平台无关。

    https://docs.python.org/3/library/

    比如,我们向使用urllib这个内置库:

    # import the library
    import urllib
    
    # use it
    urllib.urlopen(...)

    我们可以通过dir函数来列出一个module中定义的函数:

    >>> import urllib
    >>> dir(urllib)
    ['ContentTooShortError', 'FancyURLopener', 'MAXFTPCACHE', 'URLopener', '__all__', '__builtins__', 
    '__doc__', '__file__', '__name__', '__package__', '__version__', '_ftperrors', '_get_proxies', 
    '_get_proxy_settings', '_have_ssl', '_hexdig', '_hextochr', '_hostprog', '_is_unicode', '_localhost', 
    '_noheaders', '_nportprog', '_passwdprog', '_portprog', '_queryprog', '_safe_map', '_safe_quoters', 
    '_tagprog', '_thishost', '_typeprog', '_urlopener', '_userprog', '_valueprog', 'addbase', 'addclosehook', 
    'addinfo', 'addinfourl', 'always_safe', 'basejoin', 'c', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies', 
    'getproxies_environment', 'getproxies_macosx_sysconf', 'i', 'localhost', 'main', 'noheaders', 'os', 
    'pathname2url', 'proxy_bypass', 'proxy_bypass_environment', 'proxy_bypass_macosx_sysconf', 'quote', 
    'quote_plus', 'reporthook', 'socket', 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport', 
    'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'ssl', 'string', 'sys', 'test', 'test1', 
    'thishost', 'time', 'toBytes', 'unquote', 'unquote_plus', 'unwrap', 'url2pathname', 'urlcleanup', 'urlencode', 
    'urlopen', 'urlretrieve']

    当我们发现了我们希望使用的module中的某个function,还可以通过help命令来列出对应的帮助信息.

    help(urllib.urlopen)

    pypi第三方modules

    虽然python本身内置了非常丰富的package供程序员使用,但是依然有很多场景需要加载第三方的package,比如numpy, pandas等等。。

    https://pypi.org/

    开发package

    packages是包含了多个package和module的命名空间。简单来说,package就是一些目录,仅此而已。只要目录中包含了一个命名为__init__.py的特殊文件,我们就称该目录为一个package。这个文件本身可以是空的,这个文件的存在标识了该目录为一个python package.

    比如,如果我们创建一个目录:foo,那么foo作为package名称,然后我们创建一个模块并命名为bar.py,我们不要忘记在foo目录下增加一个__init__.py的文件。那么要使用这个bar模块,我们可以这样做:

    import foo.bar 
    # 或者:
    from foo import bar

    在__init__.py文件中,我们可以指定哪些模块作为暴露的api,而其他的模块作为私有的:

    __init__.py:
    
    __all__ = ["bar"]
  • 相关阅读:
    python测试开发django177.启动项目添加初始化数据(fixtures的使用) 上海
    python笔记70 Python中`__repr__`和`__str__`区别 上海
    python笔记69 什么是猴子补丁(Monkey Patch)? 上海
    pytest文档78 钩子函数pytest_runtest_makereport获取用例执行报错内容和print内容 上海
    python测试开发django176.数据库迁移数据(manage.py dumpdata) 上海
    python3面试题:如何用python实现栈(Stack)的操作? 上海
    python笔记71 traceback.print_exc()保存异常内容 上海
    测试驱动开发 Rss Reader Item Marker
    Rhino Mocks (RhinoMock)2
    继承的Singleton模式的实现
  • 原文地址:https://www.cnblogs.com/kidsitcn/p/9407166.html
Copyright © 2011-2022 走看看