'''
内置序列类型
    容器序列 : 能存放不同类型的数据
        list
        tuple
        collections.deque
    扁平序列 : 只能容纳一种类型
        str
        bytes
        bytearray  字节数组
        memoryview 内存镜像
        arrayarray

    可变序列: MutableSequence
        list bytearray array.array collections.deque memoryview
    不可变序列: Sequence
        tuple str bytes

    列表推导式 list comprehension: 快速生成一个列表
        [.....]

    生成器表达式 generator expression: 产生一个生成器
        (....)

    python解释器会忽略()[]{}中的换行符,所以可以省略续行符\

    python3中不会出现变量泄漏问题
        x = 1
        lis = [ x for x in 'ABC')
        x >>> 1 不会出现等于'C'的情况

        x 类似于 函数中的局部变量  适用于循环结构,列表推导式等
'''
# 把一个字符串变成unicode码的列表
'''eg1:
symbols = '!#$&?'
codes = []

for symbol in symbols:
    codes.append(ord(symbol))
print(codes)

codes2 = [ord(x) for x in symbols]
print(codes2)
'''


# 列表推导式和filter+map的比较
'''
symbols = '!#$&?你好吗'
beyond_ascii = [ord(x) for x in symbols if ord(x) > 127]  # 非ascii字符
print(beyond_ascii)

beyond_ascii2 = list(filter(lambda x : x > 127,map(ord,symbols)))
print(beyond_ascii2)
'''

# 笛卡尔积 不同颜色海加尔尺码的T恤
colors = ['white','black','yellow']
sizes = 'S M L'.split()

tshirts = [(color,size) for color in colors for size in sizes]
print(tshirts)

tshirts1 = [(color,size)  for size in sizes for color in colors] # 不同的顺序
print(tshirts1)
'''
生成器表达式
    (......)
    遵守迭代器协议,可以逐个地产出元素,而不是生成一个完整的列表,可以节约内存
'''

# 用生成器表达式建立元组和数组
'''
symbols = '!#$&?'
t = tuple(ord(x) for x in symbols) # 若生成器表达式是一个函数调用过程中的唯一参数,不用额外再加括号
print(t)

import array
a = array.array('I',(ord(x) for x in symbols)) # 两个参数,括号是必须的
print(a)
'''

# 用生成器表达式完全笛卡尔积
colors = ['white','black','yellow']
sizes = 'S M L'.split()

for tshirt in ('%s %s'%(c, s) for c in colors for s in sizes):
    print(tshirt)
'''
元组:
    1.元组其实是对数据的记录,元组中每个数据都是一条记录中一个字段的数据,外加这个字段的位置

拆包: a,b = 一个可迭代对象   也叫平行赋值
    要求可迭代对象的元素个数和前面的元组的空档数一致
    也可使用*来忽略不用的元素

    2.作为不可变列表的元组

'''

# 把元组用作记录
'''
lax_coordinates = (33.9425,-118.408056)
city, year,pop,chg,area = ('Tokyo',2003,32450,0.66,8014) # 拆包
traveler_ids = [('USA','31195855'),
                ('BRA','CE3423567'),
                ('ESP','XDA2544350')]
for passport in sorted(traveler_ids):
    print('%s %s'%(passport)) # 拆包
    '''
# 拆包
'''
t = divmod(123,7)
print(t)
res = divmod(*t) # 拆包作为函数的参数
print(res)

import os
# os.path.split 返回一个路径+文件名的元组
_,filename = os.path.split('E:\pythonProjects\pythonProject\读书笔记\流畅的Python\01第二章 数据结构\03元组.py')
print(filename)
'''

# # *在拆包中的应用
# a,b,*rest = range(5)
# print(a,b,rest)
#
# a,b,*rest = range(3)
# print(a,b,rest)
#
# a,b,*rest = range(2)
# print(a,b,rest)
#
# # *只能用在一个变量名前面,但这个变量可以用在拆包的任意位置
# a,*body,c,d= range(5)
# print(a,body,c,d)
#
# *head,a,c,d= range(5)
# print(head,a,c,d)

# 嵌套元组拆包 获取经度  要求嵌套的结构相同
# metro_areas = [('Tokyo','JP',36.933,(35.689722,139.691667)),
#                ('New Yory','US',20.104,(40.808611,-74.020386))]
# print('{:15} | {:^9} | {:^9}'.format('','lat.','long.'))
# fmt = '{:15} | {:9.4f} | {:9.4f}'
# for name,cc,pop,(latitude,longitude)  in metro_areas:
#     print(fmt.format(name,latitude,longitude))


# 具名元组 collections.namedtuple 用来构建一个带字段名的元组和一个有名字的类

# 定义和使用具名元组
'''
1.创建一个具名元组需要两个参数,一个是类名,另一个是各个字段的名字,后者可以是由字符串组成的可迭代对象
或者是空格分开的字符串
2.可以通过字段名或者位置来获取一个字段的信息
3.namedtuple的专有属性
    _fields : 类名._fields 或者对象名._fields都可以调用,返回所有字段名的元组
    _make(iterable) : 通过接受一个可迭代对象来生成一个类的实例,同City(*delhi_data)的效果相同
    _asdict:把具名元组用collections.OrderedDict的形式返回
'''
#
# from collections import namedtuple
# City = namedtuple('City','name country population coordinnates') # 定义一个具名元组
# tokyo = City('Tokyo','JP',36.933,(35.68972,139.691667)) # 创建了一个具名元组
#
# print(tokyo)
# print(tokyo.name)
# print(tokyo[1])
# print(tokyo._fields)
#
# LatLong = namedtuple('LatLong','lat long')
# delhi_data = ('Delhi Ncr','IN',21.935,LatLong(28.613889,77.208889))
# delhi = City._make(delhi_data)
# print(delhi._asdict())
#
# for key,value  in delhi._asdict().items():
#     print(key+":"+str(value))

t = (1,3,2,4,2)
lis = [1,2,2,4,2,3,5]
print(reversed(t))  # tuple没有__reversed__方法,但任然可以调用这个方法
r = reversed(lis)
print(r.__next__()) # reversed方法返回的是一个迭代器
print(t)
print(lis)
print(dir(t))
'''为什么切片会忽略最后一个元素
    1.快速看出切片里面由几个元素
        lis[:3],range(3),3个元素
    2.快速计算切片的长度 lis[1:5] end - start
    3.利用任意一个小标来把序列分割成不重复的两部分 lis[:4]和lis[4:]
'''
# s = slice(1, 10, 2)  # indexes 1,3,5,7,9
# print(type(s))
# print(s.__dir__())
# print(s.start)
# print(s.stop)
# print(s.step)
#
# s = slice(5)  # indexes 0,1,2,3,4
# print(s.start)
# print(s.stop)
# print(s.step)

# 建立包含三个列表的列表

# lis = [[0]*3 for _ in range(3)]
# print(lis)
# lis[1][1] = 1
# print(lis)
#
# # 错误示范
# lst = [[0]*3]*3
# print(lst)
# lst[1][1] = 100
# print(lst) # lst实质是对[0,0,0]列表的三次引用

# +=谜题
# t = (1,2,[30,40])
# t[2] += [50,60]
# print(t)

'''不要把可变对象放在元组里
增量赋值不是一个原子操作'''

# list.sort() 原地排序 函数的返回值是None
# sorted(sequence) 返回一个列表
# 两个参数 key 和 reverse
#     key = 函数名  排序的依据
#     reverse = True/ False
import bisect
import sys
import random

# 用bisect来管理以排序的序列
#     bisect.bisect()
#     bisect.insort()



# HAYSTACK = [1,4,5,6,8,12,15,20,21,23,23,26,29,30]
# NEEDLES = [0,1,2,55,8,10,22,23,29,30,31]
# ROW_FMT = '{0:2d}@{1:2d}    {2}{1:<2d}'
# def demo(bisect_fn):
#     for needle in reversed(NEEDLES):
#         pos = bisect_fn(HAYSTACK,needle)
#         offset = pos * "  |"
#         print(ROW_FMT.format(needle,pos,offset))
# if __name__ == '__main__':
#     if sys.argv[-1] == 'left':
#         bisect_fn = bisect.bisect_left
#     else:
#         bisect_fn = bisect.bisect
#     print('DEMO:',bisect_fn.__name__)
#     print('haystack->'," ".join('%2d'%n for n in HAYSTACK))
#     demo(bisect_fn)


# 根据一个分数找到对应的成绩
"""def grade(score,breakpoint = [60,70,80,90],grades = 'FDCBA'):
    return grades[i]
    i = bisect.bisect(breakpoint,score)

lis = [grade(score) for score in [33,45,65,73,83,99,55,77,90]]
print(lis)
"""

# 用bisect.insort插入新元素
# insort(seq,item) 把item插入到seq中 并保持seq有序
"""
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)"""
# 列表的替代array.array
# 除了支持.pop,.insert,.extend外还支持从文件读取和存入文件.tofile,.frombytes
# array.array('b')
#     第一个参数:'b' 类型符 8位正数 -128~127
#              'd' 双精度浮点型


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)"""

# 列表的替代 memoryview(内存视图)
# 在不复制内容的情况下操作同一个数组的不同切片

# 通过改变数组中的一个字节来更新数组里某个元素的值

numbers = array('h',[-2,-1,0,1,2])
memv = memoryview(numbers)
print(len(memv))
print(memv[0])
memv_oct = memv.cast('B')  # 转化为无符号类型
print(memv)
print(memv_oct)
print(memv_oct.tolist()) # 以列表的形式查看memv_oct
memv_oct[5] = 4 #  把位于5的字节赋值为4
print(numbers)

numpy的基本操作

import numpy

a = numpy.arange(12)
print(a)
print(type(a))
print(a.shape) # 形状
a.shape = 3,4
print(a)
print(a[2])
print(a[2,1])
print(a[:,1])
b = a.transpose() # 转置
print(b)
# 双向队列 collections.deque
from collections import deque

dq = deque(range(10),maxlen=10) # maxlen最大长度
print(dq)

dq.rotate(3)  # 最右边的3个元素移动到队列的左边
print(dq)

dq.rotate(-4) # 移动到右边
print(dq)

dq.appendleft(-1) #  队列满时,头部添加 尾部会被删除
print(dq)

dq.extend([11,22,33])
print(dq)

dq.extendleft([10,20,30])
print(dq)