0
点赞
收藏
分享

微信扫一扫

python文件、编译文件、包、软件开发目录规范

承蒙不弃 2023-05-15 阅读 50

目录

❤  Python文件的两种用途

❤  编译Python文件

❤  批量生成.pyc文件

❤  什么是包?

❤  为什么要有包?

❤  如何用包?

模块和包

扩展模块功能

修改__init__.py文件

导入包内包

导入包内包的模块

绝对导入和相对导入

❤  注意事项

❤  软件开发的目录规范


python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm=1001.2014.3001.5502

❤  Python文件的两种用途

python文件总共有两种用途,一种是执行文件;另一种是被当做模块导入。

编写好的一个python文件可以有两种用途:


# aaa.py

x = 1


def f1():
    print('from f1')


def f2():
    print('from f2')


f1()
f2()

# run.py

import aaa

如果直接运行run.py会直接运行aaa.py中的f1()f2(),但是如果我们在aaa.py中加上if \_\_name\_\_ == '\_\_main\_\_':这句话,则可以防止运行run.py时执行f1()f2()。因为当aaa.py被直接执行,即当做执行文件的时候\_\_name\_\_ == '\_\_main\_\_'; 在aaa.py被当做模块直接运行的时候\_\_name\_\_ == 'aaa'。由此可以让aaa.py在不同的场景下有着不同的用法。


# aaa.py

x = 1


def f1():
    print('from f1')


def f2():
    print('from f2')


if __name__ == '__main__':
    f1()
    f2()

❤  编译Python文件

为了提高加载模块的速度,强调强调强调:提高的是加载速度而绝非运行速度。python解释器会在__pycache__目录中下缓存每个模块编译后的版本,格式为:module.version.pyc。通常会包含python的版本号。例如,在CPython3.3版本下,spam.py模块会被缓存成__pycache__/spam.cpython-33.pyc。这种命名规范保证了编译后的结果多版本共存。

Python检查源文件的修改时间与编译的版本进行对比,如果过期就需要重新编译。这是完全自动的过程。并且编译的模块是平台独立的,所以相同的库可以在不同的架构的系统之间共享,即pyc使一种跨平台的字节码,类似于JAVA火.NET,是由python虚拟机来执行的,但是pyc的内容跟python的版本相关,不同的版本编译后的pyc文件不同,2.5编译的pyc文件不能到3.5上执行,并且pyc文件是可以反编译的,因而它的出现仅仅是用来提升模块的加载速度的,不是用来加密的。


# python解释器在以下两种情况下不检测缓存

1. 如果是在命令行中被直接导入模块,则按照这种方式,每次导入都会重新编译,并且不会存储编译后的结果(python3.3以前的版本应该是这样)
    python -m spam.py

2. 如果源文件不存在,那么缓存的结果也不会被使用,如果想在没有源文件的情况下来使用编译后的结果,则编译后的结果必须在源目录下

sh-3.2  # ls
__pycache__ spam.py
sh-3.2  # rm -rf spam.py 
sh-3.2  # mv __pycache__/spam.cpython-36.pyc ./spam.pyc
sh-3.2  # python3 spam.pyc 
spam
 

# 提示:

1. 模块名区分大小写,foo.py与FOO.py代表的是两个模块
2. 你可以使用-O或者-OO转换python命令来减少编译模块的大小
    -O转换会帮你去掉assert语句
    -OO转换会帮你去掉assert语句和__doc__文档字符串
    由于一些程序可能依赖于assert语句或文档字符串,你应该在在确认需要
    的情况下使用这些选项。
3. 在速度上从.pyc文件中读指令来执行不会比从.py文件中读指令执行更快,只有在模块被加载时,.pyc文件才是更快的
4. 只有使用import语句是才将文件自动编译为.pyc文件,在命令行或标准输入中指定运行脚本则不会生成这类文件,因而我们可以使用compieall模块为一个目录中的所有模块创建.pyc文件

模块可以作为一个脚本(使用python -m compileall)编译Python源  
python -m compileall /module_directory 递归着编译
如果使用python -O -m compileall /module_directory -l则只一层

命令行里使用compile()函数时,自动使用python -O -m compileall
  
详见:https://docs.python.org/3/library/compileall.html#module-compileall

❤  批量生成.pyc文件


import compileall
compileall.compile_dir('$dir')

其中,$dir 为Python源代码所在的目录。

❤  什么是包?

包是模块的一种形式,包的本质就是一个含有.py的文件的文件夹。

❤  为什么要有包?

模块的第一个版本只有10个功能,但是未来在扩展版本的时候,模块名和用法应该最好不要去修改,但是这只是对使用者友好,而由于版本扩展,文件越来越大,模块设计者对模块的管理、维护会越来越复杂,因此我们可以使用包来扩展模块的功能。

❤  如何用包?

模块和包

导入模块发生的三件事:

导入包发生的三件事:

导入包就是在导入包下的.py,并且可以使用以下两种方式导入:

扩展模块功能

如下我们如果需要扩展aaa.py模块,需要建立一个aaa的目录文件,并且删除aaa.py文件,将aaa.py修改成m1.py和m2.py两个文件,让模块的功能使用方法不改变。


# aaa.py

def func1():
    pass

def func2():
    pass

def func3():
    pass

def func4():
    pass

def func5():
    pass

def func6():
    pass

# m1.py

def func1():
    pass

def func2():
    pass

def func3():
    pass

# m2.py

def func4():
    pass

def func5():
    pass

def func6():
    pass

# run.py

import aaa

aaa.func1()
aaa.func2()
aaa.func3()
aaa.func4()
aaa.func5()
aaa.func6()

修改__init__.py文件


# aaa/.py

func1 = 111
func2 = 222
func3 = 333
func4 = 444
func5 = 555
func6 = 666

由于在\_\_init\_\_.py中定义了func1,因此我们可以在run.py文件中导入func1,但是这个func1并不是我们想要的func1,因此需要修改\_\_init\_\_.py文件,又由于执行文件run.py的环境变量不为aaa,因此直接使用import导入m1会报错,因此使用from导入。


# aaa/.py

from aaa.m1 import func1
from aaa.m2 import func2

# run.py

import aaa


print(aaa.func1())
print(aaa.func2())

导入包内包

aaa.bbb指向aaa内部的文件夹bbb包,如果我们需要导入bbb这个包。


# bbb/.py

from aaa import bbb

# run.py

import aaa


print(aaa.bbb)

导入包内包的模块

如果bbb包内部有m3.py,我们需要从run.py导入m3模块。


# bbb/.py

from aaa.bbb import m3

# run.py

import aaa


aaa.bbb.m3

绝对导入和相对导入

绝对导入:


# aaa/.py

from aaa.m1 import func1
from aaa.m2 import func2

相对导入:

  • .代表当前被导入文件所在的文件夹
  • ..代表当前被导入文件所在的文件夹的上一级
  • ...代表当前被导入文件所在的文件夹的上一级的上一级

from .m1 import func1
from .m2 import func2

❤  注意事项

❤  软件开发的目录规范

为了提高程序的可读性与可维护性,我们应该为软件设计良好的目录结构,这与规范的编码风格同等重要,简而言之就是把软件代码分文件目录。假设你要写一个ATM软件,你可以按照下面的目录结构管理你的软件代码:


ATM/
|-- core/
|   |-- src.py  # 业务核心逻辑代码
|
|-- api/
|   |-- api.py  # 接口文件
|
|-- db/
|   |-- db_handle.py  # 操作数据文件
|   |-- db.txt  # 存储数据文件
|
|-- lib/
|   |-- common.py  # 共享功能
|
|-- conf/
|   |-- settings.py  # 配置相关
|
|-- bin/
|   |-- run.py  # 程序的启动文件,一般放在项目的根目录下,因为在运行时会默认将运行文件所在的文件夹作为sys.path的第一个路径,这样就省去了处理环境变量的步骤
|
|-- log/
|   |-- log.log  # 日志文件
|
|-- requirements.txt # 存放软件依赖的外部Python包列表,详见https://pip.readthedocs.io/en/1.1/requirements.html
|-- README  # 项目说明文件

# run.py

import sys
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from core import src

if __name__ == '__main__':
    src.run()

# settings.py

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

DB_PATH = os.path.join(BASE_DIR, 'db', 'db.txt')
LOG_PATH = os.path.join(BASE_DIR, 'log', 'user.log')

# print(DB_PATH)
# print(LOG_PATH)

# src.py

from conf import settings
from lib import common


def login():
    print('登陆')


def register():
    print('注册')
    name = input('username>>: ')
    pwd = input('password>>: ')
    with open(settings.DB_PATH, mode='a', encoding='utf-8') as f:
        f.write('%s:%s\n' % (name, pwd))
        # 记录日志。。。。。。
        common.logger('%s注册成功' % name)
        print('注册成功')


def shopping():
    print('购物')


def pay():
    print('支付')


def transfer():
    print('转账')


func_dic = {
    '1': login,
    '2': register,
    '3': shopping,
    '4': pay,
    '5': transfer,
}


def run():
    while True:
        print("""
        1 登陆
        2 注册
        3 购物
        4 支付
        5 转账
        6 退出
        """)
        choice = input('>>>: ').strip()
        if choice == '6': break
        if choice not in func_dic:
            print('输入错误命令,傻叉')
            continue
        func_dic[choice]()

# common.py

import time
from conf import settings


def logger(msg):
    current_time = time.strftime('%Y-%m-%d %X')
    with open(settings.LOG_PATH, mode='a', encoding='utf-8') as f:
        f.write('%s %s' % (current_time, msg))

 

举报

相关推荐

0 条评论