编码
文件编码,why # coding=utf-8会起效
我们经常看到python文件开头会用声明python文件的编码,例如 # -*- coding: latin-1 -*-
或 # coding: latin-1
。这主要是因为python文件默认是ASCII编码,所有就有个老哥儿想办法用文件开头声明的方法来解决该文件的编码问题,具体可以参考:https://www.python.org/dev/peps/pep-0263/。
所以,看起来是个注释,但其实这是个有意义的注释。
字符串前加u
字符串前加u表示是一个Unicode编码的字符串,在python3中,字符串的存储方式都是按照Unicode字符来存储的,所以带不带u是一样的。
Python 3.7.3 (default, Sep 5 2019, 17:14:41)
>>> a = '我爱你'
>>> a
'我爱你'
>>> ua = u'我爱你'
>>> ua
'我爱你'
>>> print(len(a) == len(ua))
True
>>> print(a == ua)
True
# 下面可以看到,utf-8中一个汉字为3个16进制字符,gbk一个汉字为2个。
# 同时,encode实现了字符串到字节的编码
>>> a_utf8 = a.encode('utf-8')
>>> a_gbk = a.encode('gbk')
>>> print(type(a_utf8))
<class 'bytes'>
>>> print(type(a_gbk))
<class 'bytes'>
>>> print(len(a_utf8))
9
>>> print(len(a_gbk))
6
>>> a_utf8
b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0'
>>> a_gbk
b'\xce\xd2\xb0\xae\xc4\xe3'
字符串前加b
表示字符串是bytes类型。
# bytes不能编码非ASCII码
>>> a=b'我爱你'
File "<stdin>", line 1
SyntaxError: bytes can only contain ASCII literal characters.
>>> a_bytes = b'Hello World'
>>> a_str = 'Hello World'
>>> a_bytes
b'Hello World'
>>> type(a_bytes)
<class 'bytes'>
>>> a_str
'Hello World'
>>> type(a_str)
<class 'str'>
>>> len(a_bytes)
11
>>> len(a_str)
11
>>> a_bytes == a_str
False
# str <-> bytes 通过encode,decode
>>> a_bytes.decode('utf-8') == a_str
True
字符串前加r
字符串前面加r,表示字符串内的内容按照字符串解释,一些转义符之类的就无效了。
>>> a = r'\n\n'
>>> print(a)
\n\n
>>> a = '\n\n' # 表示打印两个换行
>>> print(a)
>>>
类型转换
string <-> bytes
# string to bytes
>>> s = "abc"
>>> s.encode()
b'abc'
# bytes to string
>>> b = s.encode()
>>> b.decode()
'abc'
# bytes类型的unicode(中文)输出
# 中文是:今天天气真不错
>>> s = '\\u4eca\\u5929\\u5929\\u6c14\\u4e0d\\u9519'
>>> s.encode()
b'\\u4eca\\u5929\\u5929\\u6c14\\u4e0d\\u9519'
>>> s.encode().decode('unicode_escape')
'今天天气不错'
json <-> string
import json
a = [{"span":"5"}, {"class":"PERSON"}]
b = json.dumps(a)
>>> type(b)
<type 'str'>
迭代器 generator
generator的使用场景:list大家都很熟悉,但是当list特别大时,我们肯定不希望占用太多的内存,此时,就可以用generator,他定义了一个产生数据的方法,在需要数据时,再生成数据。下面结合代码进行讲解。
# a是一个generator
# 如果使用[]代替(),这里就是生成了一个List
>>> a = (x for x in range(10))
>>> a
<generator object <genexpr> at 0x7f9e38b72200>
# 使用next()可以取下一个值,一般这种用法较少
>>> next(a)
0
# 注意,generator是一次性的,上面取完了0,因此这里从1开始了
# 同时,这里表明list()可以一次性取完generator
>>> list(a)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a = (x for x in range(10))
>>> a
<generator object <genexpr> at 0x7f9e38b722b0>
>>> tuple(a)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
# 当generator全部被取出以后,会抛异常
# 可以用这个异常来判断generator数据已经取完
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> a = (x for x in range(10))
# 这是最常使用generator的方法
>>> for i in a:
... print(i)
...
0
1
2
3
4
5
6
7
8
9
# 以斐波那契数列为例
# generator,在每次调用next()的时候执行,遇到yield语句返回。
# 再次执行的时候,从上次返回的yield语句处继续执行,执行到下一个yield返回
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print("before b, b={}".format(b))
yield b # 当函数里有yield,这个函数就是一个generator
print("a={}, b={}, n={}".format(a, b, n))
a, b = b, a+b
n += 1
return
a = fib(10)
print(a) # <generator object fib at 0x7fd476acbb48>
next(a) # before b, b=1
next(a) # a=0, b=1, n=0 before b, b=1
next(a) # a=1, b=1, n=1 before b, b=2
打印日志 logging
- 为啥不用print?
首先,print不够灵活,比如你在开发的时候写了print,但是正式环境想删掉,要么手动删掉,要么每个都加一句开发还是正式环境的判断。
其次,某些情况下,print是没地方显示的,只能通过logging打日志。
但是吧,logging本身也有BUG,所以print也是个不错的选择,对于第一个不够灵活的问题,你完全可以自定义一个函数,在里面设置一个flag判断环境,然后决定是否print,所以取舍都在自己了。
先来看一段代码:
import logging
# logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info('Start...')
logger.debug('I want to say: %s', "hello word")
logger.warning('Finish..')
-- 默认输出
Finish..
-- 设置为DEBUG级别
-- logging.basicConfig(level=logging.DEBUG)
INFO:__main__:Start...
DEBUG:__main__:I want to say: hello word
WARNING:__main__:Finish..
-- basicConfig 加入format
-- logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(message)s')
2021-01-25 17:29:08,766 - Start...
2021-01-25 17:29:08,766 - I want to say: hello word
2021-01-25 17:29:08,767 - Finish..
首先,logging是Python自带的模块,不用额外安装。
其次,logging总共有
- DEBUG
- INFO
- WARNING
- ERROR
- CRITICAL
- NOSET
6个日志级别,默认是WARNING,所以使用logging.debug()就可以实现在开发时打印日志,在正式环境,将日志级别设置到DBDUG以上,就不会输出debug日志。
上面通过logging.baseConfig对日志进行了设置,常用的还有其他参数,如: