Python使用笔记

Posted by wsxq2 on 2018-11-19
TAGS:  Python编程语言

本文最后一次编辑时间:2020-06-04 19:14:13 +0800

编程规范

PEP8

Google

语言特性

三元运算符

1
2
#如果条件为真,返回真 否则返回假
condition_is_true if condition else condition_is_false

例如:

1
2
is_fat = True
state = "fat" if is_fat else "not fat"

强制类型转换

如将 3.5 强制转换为 3:

1
2
>>> int(3.5)
3

Python 中常用的类型转换的函数有:

  • int(x): 将 x 转换为一个整数
  • float(x): 将 x 转换到一个浮点数
  • str(x): 将对象 x 转换为字符串
  • tuple(s): 将序列 s 转换为一个元组
  • list(s): 将序列 s 转换为一个列表
  • set(s): 将序列 s 转换为一个集合

格式化字符串

本节包含str.format()语法的示例以及与旧式%格式化的比较。

该语法在大多数情况下与旧式的%格式化类似,只是增加了{}:来取代%。例如,,'%03.2f'可以被改写为'{:03.2f}'

新的格式语法还支持新增的不同选项,将在以下示例中说明。

按位置访问参数:

1
2
3
4
5
6
7
8
9
10
11
>>>
>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{}, {}, {}'.format('a', 'b', 'c')  # 3.1+ only
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>> '{2}, {1}, {0}'.format(*'abc')      # unpacking argument sequence
'c, b, a'
>>> '{0}{1}{0}'.format('abra', 'cad')   # arguments' indices can be repeated
'abracadabra'

按名称访问参数:

1
2
3
4
5
6
>>>
>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
>>> 'Coordinates: {latitude}, {longitude}'.format(**coord)
'Coordinates: 37.24N, -115.81W'

访问参数的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>>
>>> c = 3-5j
>>> ('The complex number {0} is formed from the real part {0.real} '
...  'and the imaginary part {0.imag}.').format(c)
'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.'
>>> class Point:
...     def __init__(self, x, y):
...         self.x, self.y = x, y
...     def __str__(self):
...         return 'Point({self.x}, {self.y})'.format(self=self)
...
>>> str(Point(4, 2))
'Point(4, 2)'

访问参数的项:

1
2
3
4
>>>
>>> coord = (3, 5)
>>> 'X: {0[0]};  Y: {0[1]}'.format(coord)
'X: 3;  Y: 5'

替代 %s 和 %r:

1
2
3
>>>
>>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2')
"repr() shows quotes: 'test1'; str() doesn't: test2"

对齐文本以及指定宽度:

1
2
3
4
5
6
7
8
9
>>>
>>> '{:<30}'.format('left aligned')
'left aligned                  '
>>> '{:>30}'.format('right aligned')
'                 right aligned'
>>> '{:^30}'.format('centered')
'           centered           '
>>> '{:*^30}'.format('centered')  # use '*' as a fill char
'***********centered***********'

替代 %+f, %-f 和 % f 以及指定正负号:

1
2
3
4
5
6
7
>>>
>>> '{:+f}; {:+f}'.format(3.14, -3.14)  # show it always
'+3.140000; -3.140000'
>>> '{: f}; {: f}'.format(3.14, -3.14)  # show a space for positive numbers
' 3.140000; -3.140000'
>>> '{:-f}; {:-f}'.format(3.14, -3.14)  # show only the minus -- same as '{:f}; {:f}'
'3.140000; -3.140000'

替代 %x 和 %o 以及转换基于不同进位制的值:

1
2
3
4
5
6
7
>>>
>>> # format also supports binary numbers
>>> "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}".format(42)
'int: 42;  hex: 2a;  oct: 52;  bin: 101010'
>>> # with 0x, 0o, or 0b as prefix:
>>> "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42)
'int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010'

使用逗号作为千位分隔符:

1
2
3
>>>
>>> '{:,}'.format(1234567890)
'1,234,567,890'

表示为百分数:

1
2
3
4
5
>>>
>>> points = 19
>>> total = 22
>>> 'Correct answers: {:.2%}'.format(points/total)
'Correct answers: 86.36%'

使用特定类型的专属格式化:

1
2
3
4
5
>>>
>>> import datetime
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
>>> '{:%Y-%m-%d %H:%M:%S}'.format(d)
'2010-07-04 12:15:58'

嵌套参数以及更复杂的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>>
>>> for align, text in zip('<^>', ['left', 'center', 'right']):
...     '{0:{fill}{align}16}'.format(text, fill=align, align=align)
...
'left<<<<<<<<<<<<'
'^^^^^center^^^^^'
'>>>>>>>>>>>right'
>>>
>>> octets = [192, 168, 0, 1]
>>> '{:02X}{:02X}{:02X}{:02X}'.format(*octets)
'C0A80001'
>>> int(_, 16)
3232235521
>>>
>>> width = 5
>>> for num in range(5,12):
...     for base in 'dXob':
...         print('{0:{width}{base}}'.format(num, base=base, width=width), end=' ')
...     print()
...
    5     5     5   101
    6     6     6   110
    7     7     7   111
    8     8    10  1000
    9     9    11  1001
   10     A    12  1010
   11     B    13  1011

——引用自string — 常见的字符串操作 — Python 3.8.2 文档

pip

pip 是 Python 的包管理工具,类似于 Ubuntu 中的 apt,CentOS 中的 yum

index-url

Python 包默认的源在国外,下载很慢,因此建议切换到国内源,如清华的。

  1. 临时修改:使用 -i 参数( --index-url)。例如:
    1
    
    $ pip install --index-url https://pypi.tuna.tsinghua.edu.cn/simple/ SomePackage
    
  2. 永久修改:修改 %APPDATA%\pip\pip.ini 内容如下(以 Windows 为例,其它平台的配置文件的位置参见 https://pip.pypa.io/en/stable/user_guide/#config-file ):
    1
    2
    3
    
    [global]
    timeout = 60
    index-url = https://pypi.tuna.tsinghua.edu.cn/simple/
    

    常用国内源:

    • 阿里云: http://mirrors.aliyun.com/pypi/simple/
    • 中国科技大学: https://pypi.mirrors.ustc.edu.cn/simple/
    • 豆瓣(douban): http://pypi.douban.com/simple/
    • 清华大学: https://pypi.tuna.tsinghua.edu.cn/simple/
    • 中国科学技术大学: http://pypi.mirrors.ustc.edu.cn/simple/

详情可参考 https://yq.aliyun.com/articles/652884

virtualenv

建议使用 virtualenv 以避免将系统的 Python 库弄乱。

下面简单介绍virtualenv的安装与使用(以 Windows 平台为例)。这里使用 Powershell,事实上更推荐微软最新开发的跨平台的 powershell。CMD 亲测不可行,在.\venv\Scripts\activate这一步会失败,虽然看起来成功了。

  1. 切换下载源:默认的源在国外,下载很慢,因此建议切换到国内源,如清华的。Windows 中编辑 %APPDATA%\pip\pip.ini 文件如下即可(没有该文件及父目录就手动创建):
    1
    2
    3
    
    [global]
    timeout = 60
    index-url = https://pypi.tuna.tsinghua.edu.cn/simple
    

    详情参见 前文 pip 中的 index-url 的设置方法

  2. 安装 virtualenv:
    1
    
    pip3 install virtualenv
    
  3. 在当前目录创建一个 virtualenv 环境(环境信息保存在.\venv文件夹中):
    1
    
    virtualenv venv
    
  4. 进入该环境:
    1
    
    .\venv\Scripts\activate
    
  5. 安装依赖(包会放在.\venv中):
    1
    
    pip3 install -r requirements.txt
    
  6. 运行脚本(会使用当前环境中的 Python):
    1
    
    python3 main.py
    

日志

参见 logging — Logging facility for Python — Python 3.7.4 documentation

注意其中给出的三个链接:

其它常用的链接:

常见用法

简单使用

1
2
3
4
5
6
7
import logging
logging.basicConfig(filename='example.log', filemode='w', format='[%(asctime)s]-[%(name)s](%(filename)s:%(lineno)d)-[%(levelname)s]>>> %(message)s', datefmt='%Y-%m-%d %H:%M:%S',level=logging.DEBUG)

logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
logging.error('And this, too too')

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
import logging
import logging.config
import logging.handlers

import yaml

def prepare():
		logging.config.dictConfig(yaml.safe_load(open("conf/logging.yaml", "r")))
		global logger
		logger = logging.getLogger("dream")
		logger.info("logger.handlers: %s", logger.handlers)
...

其中conf/logging.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version: 1
formatters:
  brief:
    format: "%(funcName)s(%(lineno)d):%(levelname)s: %(message)s"
  precise:
    format: "[%(asctime)s]-[%(name)s](%(filename)s:%(lineno)d)-[%(levelname)s]>>> %(message)s"
handlers:
  console:
    class: logging.StreamHandler
    level: INFO
    formatter: brief
    stream: ext://sys.stdout
  file:
    class: logging.handlers.RotatingFileHandler
    level: DEBUG
    formatter: precise
    filename: logs/main.log
    mode: a
    encoding: "utf-8"
    maxBytes: 4194304
    backupCount: 2
loggers:
  dream:
    level: DEBUG
    handlers: [file,console]
    propagate: no
root:
  level: DEBUG
  handlers: [console]

调试

温馨提示:本部分使用的 Python 版本为 Python2.7)

详情参考: IBM-Python 代码调试技巧

使用 pdb

.bashrc文件中定义函数pdb,方便使用:

1
2
3
function pdb(){
	python -m pdb $1
}

使用方法:

1
pdb test.py

常用命令:

命令 解释
break 或 b 设置断点 设置断点
continue 或 c 继续执行程序
list 或 l 查看当前行的代码段
step 或 s 进入函数
return 或 r 执行代码直到从当前函数返回
exit 或 q 中止并退出
next 或 n 执行下一行
pp 打印变量的值
help 帮助

详情参考: 26.2. pdb — The Python Debugger

IDE

PyCharm

Python2 vs Python3

遇到过的问题

How to get an absolute file path?

1
2
3
>>> import os
>>> os.path.abspath("mydir/myfile.txt")
'C:/example/cwd/mydir/myfile.txt'

详情参见 https://stackoverflow.com/a/51523

捕获 CTRL+C 信号?

温馨提示:本部分使用的 Python 版本为 Python2.7)

  1. 使用 python 的异常KeyboardInterrupt:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    import time
    import sys
    import signal
    
    signal.signal(signal.SIGINT, signal.default_int_handler)
    x = 1
    try:
        while True:
            print x
            time.sleep(.3)
            x += 1
    except KeyboardInterrupt:
        print "Bye"
        sys.exit()
    
  2. 使用signal模块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     #!/usr/bin/env python
     import signal
     import sys
     def signal_handler(sig, frame):
             print('You pressed Ctrl+C!')
             sys.exit(0)
     signal.signal(signal.SIGINT, signal_handler)
     print('Press Ctrl+C')
     signal.pause()
    

详情参考: How do I capture SIGINT in Python?

UnicodeEncodeError?

温馨提示:本部分使用的 Python 版本为 Python2.7)

执行代码:

1
2
3
4
5
6
def save_html(content):
    with open('a.html', 'w') as f:
        f.write(content)

r=requests.get('https://www.baidu.com')
save_html(r.text)

报错:

1
2
3
4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in save_html
UnicodeEncodeError: 'ascii' codec can't encode characters in position 317-343: ordinal not in range(128)

解决办法:在使用前先调用encode函数将其编码为相应的编码(通常为UTF8)即可。如下所示

1
2
3
4
def save_html(content):
    with open('a.html', 'w') as f:
        f.write(content.encode('utf8'))

详情参考: UnicodeEncodeError: ‘ascii’ codec can’t encode character u’\xa0’ in position 20: ordinal not in range(128)

List user defined variables?

使用dir()函数然后再过滤即可。例如:

1
2
3
>>> x = 3
>>> set(dir()) - set(dir(__builtins__))
set(['__builtins__', 'x'])

又如:

1
2
3
4
5
6
7
8
9
10
#!/us/bin/python                                                                                    
foo1 = "Hello world"
foo2 = "bar"
foo3 = {"1":"a", "2":"b"}
foo4 = "1+1"

for name in dir():
    if not name.startswith('__'):
        myvalue = eval(name)
        print name, "is", type(myvalue), "and is equal to ", myvalue

详情参见 List user defined variables, python - Stack Overflow

How to read a file line-by-line into a list?

参见python - How to read a file line-by-line into a list? - Stack Overflow

Getting exception details?

参见Getting exception details in Python - Stack Overflow

Trace Python imports?

使用-v参数:

1
python -v -m /usr/lib/python2.6/timeit.py

详情参见 debugging - Trace Python imports - Stack Overflow

参考资料