Halo
发布于 2022-05-06 / 101 阅读 / 0 评论 / 0 点赞

python最佳实践

命名

  • 变量、函数、方法、包、模块小写,并使用下划线分隔单词(lower_case_with_underscores)
  • 类、异常首字母大写(CapWords)
  • 受保护的方法和内部函数单下划线开头(_single_leading_underscore(self, …))
  • 私有的方法双下划线开头(__double_leading_underscore(self, …))
  • 常量字母全部大写,单词间用下划线分隔(ALL_CAPS_WITH_UNDERSCORES)

pipenv

尽管 pip 可以安装 Python 包, 但仍推荐使用 Pipenv,因为它是一种更高级的工具,可简化依赖关系管理的常见使用情况。

$ pip install --user pipenv
$ whereis pipenv
pipenv: /Users/xxx/Library/Python/3.9/bin/pipenv

$ vi ~/.zshrc
# append follow
export PATH="/Users/xxx/Library/Python/3.9/bin:$PATH"

$ source ~/.zshrc

常见命令

  1. pipenv install:
  • 若项目目录中虚拟环境未创建且无Pipfile文件,将安装虚拟环境并创建Pipfile文件
  • 若项目目录中虚拟环境未创建且有Pipfile文件,将根据Pipfile文件来安装相应python版本和依赖包
  • 若项目目录中虚拟环境已创建且有Pipfile文件,将根据Pipfile文件来安装依赖包
  1. pipenv shell:进入虚拟环境(项目目录下)
  2. pipenv install xx::安装python包
  3. pipenv uninstall xx::卸载python包
  4. pipenv graph:显示包依赖关系
  5. pipenv --venv:显示虚拟环境安装路径
  6. exit:退出虚拟环境

模块

任意一个py 文件都被认为是一个模块
最重要的是,不要使用下划线命名空间,而是使用子模块

# OK
import library.plugin.foo
# not OK
import library.foo_plugin

# 差
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的。

任意包含 init.py 文件的目录都被认为是一个Python包。
导入一个包里不同 模块的方式和普通的导入模块方式相似,特别的地方是 init.py 文件将集合 所有包范围内的定义。

装饰器

Python语言提供一个简单而强大的语法: ‘装饰器’。
装饰器是一个函数或类,它可以 包装(或装饰)一个函数或方法。被 ‘装饰’ 的函数或方法会替换原来的函数或方法。

def foo():
    # 实现语句

def decorator(func):
    # 操作func语句
    return func

foo = decorator(foo)  # 手动装饰

@decorator
def bar():
    # 实现语句
# bar()被装饰了

上下文管理器

上下文管理器是一个Python对象,为操作提供了额外的上下文信息。
这种额外的信息, 在使用 with 语句初始化上下文,以及完成 with 块中的所有代码时,采用可调用的形式。

  • 类方式
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()
  • 函数方式
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()

如果封装的逻辑量很大,则类的方法可能会更好。 而对于处理简单操作的情况,函数方法可能会更好。

块注释(#) 和文档字符串(“”“/”“”)

  • 块注释(#)通常用于解释一段代码是 做什么 ,或是算法的细节。
  • 文档字符串(“”“/”“”)更适合于向其他用户(或是写完代码6个月内的您)解释您代码中的特定功能是 如何 使用, 或是方法、类和模块的作用。
  • 文档字符串(“”“/”“”)内置于Python语言本身。与被优化掉的注释相比较, 这意味着您可以使用Python强大的内省功能以在运行时获得文档字符串。 对于几乎每个Python对象,可以通过其 __doc__ 属性或使用内置的“help()”函数访问文档字符串。

由于某种原因这个函数减慢程序执行。

def square_and_rooter(x):
“”“返回自己乘以自己的平方根。”“”

单元测试

import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
       self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
       self.assertTrue('FOO'.isupper())
       self.assertFalse('Foo'.isupper())

    def test_split(self):
       s = 'hello world'
       self.assertEqual(s.split(), ['hello', 'world'])
       # check that s.split fails when the separator is not a string
       with self.assertRaises(TypeError):
          s.split(2)

if __name__ == '__main__':
    unittest.main()

可变默认参数

def append_to(element, to=[]):
    to.append(element)
    return to

my_list = append_to(12)
print(my_list)

my_other_list = append_to(42)
print(my_other_list)

当函数被定义时,Python的默认参数就被创建 一次,而不是每次调用函数的时候创建。

正确输出是:

[12]
[12, 42]

闭包迟绑定

def create_multipliers():
    return [lambda x : i * x for i in range(5)]

for multiplier in create_multipliers():
   print(multiplier(2))

Python的闭包是 迟绑定 。 这意味着闭包中用到的变量的值,是在内部函数被调用时查询得到的。
这里,不论 任何 返回的函数是如何被调用的, i 的值是调用时在周围作用域中查询到的。 接着,循环完成, i 的值最终变成了4。

正确的输出是:

8
8
8
8
8

评论