命名
- 变量、函数、方法、包、模块小写,并使用下划线分隔单词(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
常见命令
- pipenv install:
- 若项目目录中虚拟环境未创建且无Pipfile文件,将安装虚拟环境并创建Pipfile文件
- 若项目目录中虚拟环境未创建且有Pipfile文件,将根据Pipfile文件来安装相应python版本和依赖包
- 若项目目录中虚拟环境已创建且有Pipfile文件,将根据Pipfile文件来安装依赖包
- pipenv shell:进入虚拟环境(项目目录下)
- pipenv install xx::安装python包
- pipenv uninstall xx::卸载python包
- pipenv graph:显示包依赖关系
- pipenv --venv:显示虚拟环境安装路径
- 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