python结构_Python 项目的结构

之前和朋友聊天,说到 Python 项目的结构问题,Python 确实是一门比较灵活的语言,你可以单独执行某个文件,把这些文件扔到一起看起来像个工程,但是外人来看其实就是一个个独立的小文件,小模块,对于小型项目来说可能并不会造成什么问题,但是对于大型项目,尤其是如果需要多人合作,有一个关于工程结构的基本认识是非常必要的。

Python 没有强制的结构规范,但是有一个大家的共识

README.rst

LICENSE

setup.py

requirements.txt

sample/__init__.py

sample/core.py

sample/helpers.py

docs/conf.py

docs/index.rst

tests/test_basic.py

tests/test_advanced.py

项目的结构是项目的门面,简单易懂的项目结构能够让介入的第三人快速的熟悉项目,Python 项目结构没有太多的约束和限制,Python 提供的导入和模块管理使得结构化 Python 相对简单,但也要注意一些比如循环依赖的问题。

模块

为了解决项目结构的问题就不得不提到模块(module),这是 Python 最主要的抽象层,模块允许将代码分为不同的部分,每个部分包含相关的数据和功能。

模块名尽量要短,使用小写,并且避免使用特殊符号,比如(.)或者 (?) 等。不推荐在模块名中使用下划线。

# ok

import library.plugin.foo

# not ok

import library.foo_plugin

import 的工作原理,比如 import modu 将会寻找合适的文件,调用目录下的 modu.py 文件,如果没有找到,Python 解释器会递归地在 PYTHONPATH 环境变量中查找该文件,如果没有则抛出 ImportError 异常。一旦找到 modu.py Python 解释器将在隔离的作用域内执行模块。所有顶层语句都会被执行,包括其他的引用。方法和类的定义会存储到模块字典中。这个模块的变量、方法和类通过命名空间暴露给调用方。

import 语句也可以为 from modu import * ,使用 from modu import func 能够精确定位想要导入的方法,并将其放入到全局命名空间。

# 较差的写法

[...]

from modu import *

[...]

x = sqrt(4) # sqrt 是模块 modu 的一部分么?或是内建函数么?上文定义了么?

# 稍好

from modu import sqrt

[...]

x = sqrt(4) # 如果在 import 语句与这条语句之间,sqrt 没有被重复定义,它也许是模块 modu 的一部分。

# 最好的做法

import modu

[...]

x = modu.sqrt(4) # sqrt 显然是属于模块 modu 的。

Python 提供非常简单的包管理系统,简单地将模块管理机制扩展到一个目录上,就是包。任意包含 __init__.py 文件的目录都被认为是一个 Python 包。如果包内的模块和子包没有代码共享的需求,使用空白 __init__.py 是正常的做法。

导入深层嵌套包可以使用 import very.very.deep.module as mod 可以简化导入冗长子包。

对象

使用无状态的函数是一种更好的编程范式。

把有隐式上下文和副作用的函数与仅包含逻辑的函数(纯函数)谨慎地区分开来,会带来 以下好处:

纯函数的结果是确定的:给定一个输入,输出总是固定相同。

当需要重构或优化时,纯函数更易于更改或替换。

纯函数更容易做单元测试:很少需要复杂的上下文配置和之后的数据清除工作。

纯函数更容易操作、修饰和分发。

装饰器

装饰器本质上是一个 Python 函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

def use_logging(func):

def wrapper():

logging.warn("%s is running" % func.__name__)

return func() # 把 foo 当做参数传递进来时,执行 func() 就相当于执行 foo()

return wrapper

def foo():

print('i am foo')

foo = use_logging(foo) # 因为装饰器 use_logging(foo) 返回的时函数对象 wrapper,这条语句相当于 foo = wrapper

foo() # 执行 foo() 就相当于执行 wrapper()

使用 @ 符号,装饰器的语法糖

def use_logging(func):

def wrapper():

logging.warn("%s is running" % func.__name__)

return func()

return wrapper

@use_logging

def foo():

print("i am foo")

foo()

这样就可以省略掉 foo = use_logging(foo) 这句赋值。

带参数的装饰器

def use_logging(level):

def decorator(func):

def wrapper(*args, **kwargs):

if level == "warn":

logging.warn("%s is running" % func.__name__)

elif level == "info":

logging.info("%s is running" % func.__name__)

return func(*args)

return wrapper

return decorator

@use_logging(level="warn")

def foo(name='foo'):

print("i am %s" % name)

foo()

类装饰器

class Foo(object):

def __init__(self, func):

self._func = func

def __call__(self):

print ('class decorator runing')

self._func()

print ('class decorator ending')

@Foo

def bar():

print ('bar')

bar()

通过 functools.wrap 来找回原函数的元信息

from functools import wraps

def logged(func):

@wraps(func)

def with_logging(*args, **kwargs):

print func.__name__ # 输出 'f'

print func.__doc__ # 输出 'does some math'

return func(*args, **kwargs)

return with_logging

@logged

def f(x):

"""does some math"""

return x + x * x

Python 类相关的内置装饰器

@staticmathod、@classmethod、@property

上下文管理器

上下文管理器是一个 Python 对象,为操作提供了额外的上下文信息。with 语句初始化上下文

with open('file.txt') as f:

contents = f.read()

实现这个功能有两种简单的方法:使用类或使用生成器。 让我们自己实现上面的功能,以使用类方式开始:

class CustomOpen(object):

def __init__(self, filename):

self.file = open(filename)

def __enter__(self):

return self.file

def __exit__(self, ctx_type, ctx_value, ctx_traceback):

self.file.close()

with CustomOpen('file') as f:

contents = f.read()

生成器使用 Python 自带的 contextlib

from contextlib import contextmanager

@contextmanager

def custom_open(filename):

f = open(filename)

try:

yield f

finally:

f.close()

with custom_open('file') as f:

contents = f.read()

由于这两种方法都是一样的,所以我们应该遵循 Python 之禅来决定何时使用哪种。 如果封装的逻辑量很大,则类的方法可能会更好。 而对于处理简单操作的情况,函数方法可能会更好。

reference

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Python项目结构,没有一个固定的标准,但是有一些常见的组织方式可以参考。下面是一个比较常见的Python项目结构: ``` project/ │ ├── src/ │ ├── __init__.py │ ├── module1.py │ ├── module2.py │ └── ... │ ├── tests/ │ ├── __init__.py │ ├── test_module1.py │ ├── test_module2.py │ └── ... │ ├── docs/ │ ├── conf.py │ ├── index.rst │ ├── ... │ └── _static/ │ ├── setup.py ├── requirements.txt └── README.md ``` 其中,`src/` 目录存放项目的源代码,`tests/` 目录存放项目的测试代码,`docs/` 目录存放项目的文档,`setup.py` 是项目的安装脚本,`requirements.txt` 是项目的依赖列表,`README.md` 是项目的说明文件。 在 `src/` 目录下,可以根据项目的功能将代码分为不同的模块,每个模块放在一个单独的 `.py` 文件中,同时需要在 `__init__.py` 文件中导入这些模块以便其他代码可以使用。 在 `tests/` 目录下,可以编写测试代码,一般使用 Python 的测试框架(如 unittest、pytest 等)进行测试。 在 `docs/` 目录下,可以编写项目的文档,一般使用 reStructuredText 或 Markdown 格式,使用 Sphinx 工具生成 HTML 或 PDF 格式的文档。 最后,在项目根目录下,需要编写 `setup.py` 文件以便其他人可以安装和使用你的项目。在 `requirements.txt` 文件中列出项目的依赖,以便其他人可以通过 `pip` 安装这些依赖。 以上是一个常见的Python项目结构,但实际上可以根据项目的具体情况进行调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值