Python 笔记

记录一下 Python 的学习。

[TOC]

1. 格式化输出 str.format()

# https://www.runoob.com/python3/python3-inputoutput.html

table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}'.format(**table))
import math
print('常量 PI 的值近似为 {0:.3f}。'.format(math.pi))
Runoob: 2; Google: 1; Taobao: 3
常量 PI 的值近似为 3.142。

2. 交换两个数据的值

使用 x, y = y, x

import dis

def swap1():
    x = 2333
    y = 6666
    x, y = y, x

dis.dis(swap1)
4           0 LOAD_CONST               1 (2333)
              2 STORE_FAST               0 (x)

  5           4 LOAD_CONST               2 (6666)
              6 STORE_FAST               1 (y)

  6           8 LOAD_FAST                1 (y)
             10 LOAD_FAST                0 (x)
             12 ROT_TWO
             14 STORE_FAST               0 (x)
             16 STORE_FAST               1 (y)
             18 LOAD_CONST               0 (None)
             20 RETURN_VALUE


def swap2():
    x = 2333
    y = 6666
    temp = x
    x = y
    y = temp

dis.dis(swap2)
2           0 LOAD_CONST               1 (2333)
              2 STORE_FAST               0 (x)

  3           4 LOAD_CONST               2 (6666)
              6 STORE_FAST               1 (y)

  4           8 LOAD_FAST                0 (x)
             10 STORE_FAST               2 (temp)

  5          12 LOAD_FAST                1 (y)
             14 STORE_FAST               0 (x)

  6          16 LOAD_FAST                2 (temp)
             18 STORE_FAST               1 (y)
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE

显然更少指令的更快。

ROT_TWO 用于交换两个栈顶层的元素,比执行一个 LOAD_FAST+STORE_FAST 快。

3. 用 enumerate() 获取序列迭代的索引和值

li = [1, 2, 4, 6]
for i, v in enumerate(li):
    print(i, v)
0 1
1 2
2 4
3 6


def enumerate(sequence, start=0):
    n = start
    for elem in sequence:
        yield n, elem
        n += 1

字典的话用.iteritems()

4. is== 的使用场景

  • a is b: 判断的是 object identity(对象标识符),两个对象是否拥有同一块内存空间
  • a == b: 判断的是两个对象值是否相等
a = 'ohoh'
b = 'ohoh'
print('a is b:', a is b)
print(id(a), id(b))
c = '判断的是 object identity(对象标识符),两个对象是否拥有同一块内存空间'
d = '判断的是 object identity(对象标识符),两个对象是否拥有同一块内存空间'
print('d is c:', d is c)
print('d == c:', d == c)
print(id(c), id(d))
a is b: True
2765551413376 2765551413376
d is c: False
d == c: True
2765556343152 2765556343312

需要注意的是,Python 有string interning字符串保留机制,对于较小的字符串,为了提高性能,

5. 字符串驻留机制

阅读这个好了

以下来自Python的字符串驻留机制:

  1. 字符串长度为0或1时,默认采用驻留机制。
  2. 字符串长度大于1时,且字符串中只包含大小写字母、数字、下划线时,采用驻留机制。
  3. 字符串只在编译时进行驻留,而非运行时。Python是解释型语言,但是事实上,它的解释器也可以是理解为是一种编译器,它负责将Python代码翻译成字节码,也就是.pyc文件。c是几个字符串的拼装,字符串的 .join() 方法是在运行期间才知道结果。所以c不支持字符串驻留。
  4. 用乘法得到的字符串,如果结果长度 <=20且字符串只包含数字、字母大小写、下划线,支持驻留。长度>20,不支持驻留。这样的设计目的是为了保护.pcy文件不会被错误代码搞的过大。
  5. 对于[-5,256]之间的整数数字,Python默认驻留
  6. Pyhton提供intern方法强制2个字符串指向同一个对象。
a = 'nb'
b = 'n'+'b'
c = ''.join(['n', 'b'])
print(b is a)
print(c is a)
print(b is c)
True
False
False


import sys
a = '6%2=0'
b = '6%2=0'
print(a is b)
b = sys.intern(a)
print(a is b)
False
True

6. 没有自增

  1. ++i会被解释为+(+i)
  2. i++则是SyntaxError
  3. --同理

7. finally 执行的坑

无论try里是否有异常抛出,finally总是会执行。

class 老子抛出来了(Exception):
    pass

while(True):
    try:
        print('准备抛出')
        raise 老子抛出来了('其实它不会出来')
    except NameError as e:
        print('不会有滴', e)
    finally:
        print('嘿嘿嘿')
        break
准备抛出
嘿嘿嘿

try里发生异常,且except里没有对应的异常处理,异常会被临时存储,等finally执行完后再抛出,但在finally里用了breakreturn,那么临时存储的异常就会丢失,导致异常屏蔽。

def 返回():
    try:
        return -1
    except:
        return -2
    finally:
        return -3

返回()
-3


执行try里的return前,会先执行finally里的return

8. 大规模连接字符串优先用join而非+

Python 里的字符串为不可变对象。

每次执行+操作就要申请一块新的内存空间,然后进行复制操作,大概$$o(n^2)$$。

join大概$$O(n)$$

import timeit

test_time = [1, 3, 5, 7, 10, 50, 100, 1000, 10000, 100000, 1000000]
strlist = []
str_source = 'oh 我的老伙计,该洗洗睡了啊'

def join_test():
    return ''.join(strlist)

def plus_test():
    ret = ''
    for  v in strlist:
        ret += v
    return ret

for i, v in enumerate(test_time, 1):
    strlist = [str_source for x in range(v)]
    join_timer = timeit.Timer("join_test()", "from __main__ import join_test")
    print('join-{0}-{2}: {1}'.format(i, join_timer.timeit(10), v))
    
for i, v in enumerate(test_time, 1):
    strlist = [str_source for x in range(v)]
    plus_timer = timeit.Timer("plus_test()", "from __main__ import plus_test")
    print('plus-{0}-{2}: {1}'.format(i, plus_timer.timeit(10), v))
join-1-1: 0.00011280000001079316
join-2-3: 8.600000001024455e-06
join-3-5: 4.699999976764957e-06
join-4-7: 5.399999963628943e-06
join-5-10: 7.500000037907739e-06
join-6-50: 1.989999998386338e-05
join-7-100: 1.7800000023271423e-05
join-8-1000: 0.0003618000000642496
join-9-10000: 0.002106799999978648
join-10-100000: 0.029422100000033424
join-11-1000000: 0.34234780000008413
plus-1-1: 6.100000064179767e-06
plus-2-3: 8.999999977277184e-06
plus-3-5: 1.0900000006586197e-05
plus-4-7: 1.6200000004573667e-05
plus-5-10: 1.5800000028320937e-05
plus-6-50: 0.00022269999999480206
plus-7-100: 0.00026260000004185713
plus-8-1000: 0.0032113999999410225
plus-9-10000: 0.02999529999999595
plus-10-100000: 6.14744189999999


文章目录