2017年8月28日技术日记

  1. python 列表 * 的坑
board = [['_'] * 3 for i in range(3)]
board
Out[46]:
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
In [47]:

board
board[1][2] = 'X'
board
Out[47]:
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]

这个相当于

board = []
for i in range(3):
    row = ['_'] * 3
    board.append(row)
board
Out[57]:
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
In [58]:

board[1][2] = 'X'
board
Out[58]:
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]

但是

weird_board = [['_'] * 3]  * 3
weird_board
weird_board = [['_'] * 3]  * 3
weird_board
Out[59]:
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
In [60]:

weird_board[1][2] = 'X'
weird_board
Out[60]:
[['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']]

相当于

row = ['_'] * 3
weird_board = []
for i in range(3):
    weird_board.append(row)
weird_board[1][2] = 'X'
weird_board
Out[62]:
[['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']]
  1. python中 +=要注意的 首先 a+=b会调用a实现了的 __iadd__方法, 如果没有这个方法才会调用 __add__方法。而可变序列一般都实现了 __iadd__方法, 而不可变对象根本不支持这个操作。下面展示了 *=再不可变序列上的作用。
l = [1,2,3]
In [1]: l=[1,2,3]

In [2]: id(l)
Out[2]: 2396048446664

In [3]: l *= 2

In [4]: l
Out[4]: [1, 2, 3, 1, 2, 3]

In [5]: id(l)
Out[5]: 2396048446664

In [6]: t=(1,2,3)

In [7]: id(t)
Out[7]: 2396048383360

In [8]: t*=2

In [9]: t
Out[9]: (1, 2, 3, 1, 2, 3)

In [10]: id(t)
Out[10]: 2396048501448

出现这样的原因就是因为list的l调用了list里的 __iadd()__方法,而属于tuple的t由于不支持修改没有 __iadd()__方法而调用了 __add()__方法。

  1. 面试题选择
In [13]: t = (1, 2, [30, 40])

In [14]: t[2] += [50,60]

以上代码的输出是什么?

  1. t 变成 (1, 2, [30, 40, 50, 60])
  2. 因为tuple不支持对它的赋值操作,所以会抛出TypeError异常。
  3. 以上两个都不是
  4. a和b都是对的

答案是什么?你以为是b,其实是d,a和b都是对的。结果是

In [13]: t = (1, 2, [30, 40])
In [14]: t[2] += [50,60]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-fb586dd7f384> in <module>()
----> 1 t[2] += [50,60]
TypeError: 'tuple' object does not support item assignment
In [15]: t
Out[15]: (1, 2, [30, 40, 50, 60])

原因是+=不是原子操作,尽量不要再tuple里嵌套可变对象。可以查看字节码来真相了

In [11]: from dis import dis

In [12]: dis('s[a] += b')
  1           0 LOAD_NAME                0 (s)
              2 LOAD_NAME                1 (a)
              4 DUP_TOP_TWO
              6 BINARY_SUBSCR                   # 将s[a]的值压入栈顶TOS(Top of Stack)
              8 LOAD_NAME                2 (b)
             10 INPLACE_ADD                     # 计算TOS += b 这里能完成是因为TOS指向的是一个可变对象。
             12 ROT_THREE
             14 STORE_SUBSCR                    # 这一步失败,因为s是不可变元组
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE
  1. python:list.sort()会就地改变列表而返回None,sorted()不会就地改变列表会新生成一个列表而返回它。
  2. python: bisect.bisect(haystack,needle)haystack是干草垛的意思,needle是针的意思。会用二分查找法返回needle在haystack中之后的位置。 bisect.bisect_left(haystack,needle)返回的是needle在haystack中之前的位置。 bisect.insort(seq,item)可以插入元素。

bisect.bisect举例:

import bisect


def grade(score):
    breakpoints = [60, 70, 80, 90]
    grades = 'EDCBA'
    i = bisect.bisect(breakpoints, score)
    return grades[i]


print([grade(score) for score in [33, 99, 77, 70, 89, 90, 100]])
[Out] ['E', 'A', 'C', 'C', 'B', 'A', 'A']

bisect.insort举例:

import bisect
import random

SIZE = 7
random.seed(1729)
my_list = []
for i in range(SIZE):
    new_item = random.randrange(SIZE * 2)
    bisect.insort(my_list, new_item)
    print('%2d ->' % new_item, my_list)
[Out]
10 -> [10]
 0 -> [0, 10]
 6 -> [0, 6, 10]
 8 -> [0, 6, 8, 10]
 7 -> [0, 6, 7, 8, 10]
 2 -> [0, 2, 6, 7, 8, 10]
10 -> [0, 2, 6, 7, 8, 10, 10]
  1. 当列表不是首选时,可以使用数组(存放大量数据) set(频繁使用in判断,set对in进行了优化)。 数组除了支持.pop,.insert,.extend等可变序列上的操作外,还支持从文件读取或存入文件更快的方法。 如.frombytes和.tofile。数组存放的是C语言的数组而不是float对象,多以序列大的时候可以节省内存空间。
from array import array
from  random import random

floats = array('d', (random() for i in range(10 ** 7)))
print(floats[-1])
fp = open('floats.bin', 'wb')
floats.tofile(fp)
fp.close()
floats2 = array('d')
fp = open('floats.bin', 'rb')
floats2.fromfile(fp, 10 ** 7)
fp.close()
print(floats2[-1])
print(floats2 == floats)
[Out]
0.48178023314354956
0.48178023314354956
True

使用array.tofile和array.fromfile要比直接读取float对象要快很多。

  1. memoryview內存视图可以在不复制内容的情况下操作同一数组的不同切片,在数据结构之间共享内存。 memoryview.cast()会把同一块内存的内容打包成一个全新的memoryview对象给你。
from array import array

numbers = array('h', [-2, -1, 0, 1, 2])
memv = memoryview(numbers)
print(len(memv))
print(memv[0])
memv_dict = memv.cast('B')
print(memv_dict.tolist())
memv_dict[5] = 4
print(numbers)
[Out]
5
-2
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
array('h', [-2, -1, 1024, 1, 2])

h是2个字节的有符号整型,B是1个字节无符号整型。因为我们把占两个字节的整数的高位变成了4,所以这个有符号整数的值就变成了1024. 1.numpy是优秀的库,实现了多维同质数组。代码举例

import numpy

a = numpy.arange(12)
print(a)
# [ 0  1  2  3  4  5  6  7  8  9 10 11]
print(type(a))  # <class 'numpy.ndarray'>
print(a.shape)  # 结果是一个一维数组,元素有12个
a.shape = 3, 4  # 把数组变成二维的
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]
print(a[2])  # 打印第2行
# [ 8  9 10 11]
print(a[2, 1])  # 打印第2行第1列
# 9
print(a[:, 1])  # 打印第1列
# [1 5 9]
print(a.transpose())  # 行列交换
# [[ 0  4  8]
#  [ 1  5  9]
#  [ 2  6 10]
#  [ 3  7 11]]

原文发布于微信公众号 - python全栈布道师(gh_f7cbe2f9567b)

原文发表时间:2017-08-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏个人随笔

Java 关于集合框架那点事儿

 1.引入集合框架   采用数组存在的一些缺陷:    1.数组长度固定不变,不能很好地适应元素数量动态变化的情况。    2.可通过数组名.length获取数...

29210
来自专栏chenjx85的技术专栏

leetcode-49-字母异位词分组(神奇的哈希)

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

831
来自专栏猿人谷

C++ STL算法系列2---find ,find_first_of , find_if , adjacent_find的使用

一.find运算 假设有一个int型的vector对象,名为vec,我们想知道其中是否包含某个特定值。 解决这个问题最简单的方法时使用标准库提供的find运算:...

2587
来自专栏追不上乌龟的兔子

Python中最快的格式化字符串方式

第一种是传承自C语言printf函数的使用%占位符格式化字符串,如'%d' % 100,这种方式严格来说是使用%作为算数运算符进行的二元运算,而且有一个限制是只...

1084
来自专栏个人分享

Scala第一章学习笔记

  面向对象编程是一种自顶向下的程序设计方法。用面向对象方法构造软件时,我们将代码以名词(对象)做切割,每个对象有某种形式的表示服(self/this)、行为(...

1062
来自专栏python3

python 生成器

第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

981
来自专栏blackheart的专栏

[C#1] 8-数组

1.数组概述 声明数组: //每个元素初始化为0,虽然数组元素是值类型,但是却是分配在托管堆中的; int[] myArray=new int[100]; //...

1927
来自专栏Coding迪斯尼

使用普拉特分析法解析极为复杂的算术表达式

1093
来自专栏从流域到海域

《数据结构》 定长顺序串常用操作代码集合

代码来自老师上课使用的ppt或者课本 /*定长顺序串*/ #define MAXLEN 40 typedef struct { char ch[M...

1966
来自专栏有趣的Python

算法与数据结构(四)堆排序:优先队列实现

堆排序 排序次要的,接触新的数据结构;堆 堆和优先队列 Heap and Priority Queue 什么是优先队列? 普通队列:先进先出;后进后出 优先队...

4455

扫码关注云+社区

领取腾讯云代金券