<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Lesson 11
Python Basic, Lesson 6, v1.0.1, 2017.1 by David.Yi   
Python Basic, Lesson 6, v1.0.2, 2017.5 modified by Yimeng.Zhang  
v1.1, 2020.4. edit by David Yi
本次内容要点
集合库 collections 简介
namedtuple
Step1:  deque
使用 list 存储数据时，按索引访问元素很快，但是插入和删除元素就很慢了，因为 list 是线性存储，数据量大的时候，插入和删除效率很低。
deque 是为了高效实现插入和删除操作的双向列表，适合用于队列和栈。
deque 在插入数据时候速度比 list 快很多，当然这个是相对存在大量数据的 list 而言的。如果你的程序中需要对有百万级别的 list 频繁的在各个位置插入删除数据，那么用 deque 是值得的。
Step2:  defaultdict
我们都知道，在使用 Python 原生数据结构字典的时候，如果用 d[key] 这样的方式访问，当指定的key不存在时，是会抛出KeyError异常的，也就是发生错误。（可以用 get 方法来避免这样的错误）
如果使用 defaultdict，只要你传入一个默认的方法，那么请求一个不存在的 key 时，便会调用这个方法，使用其结果来作为这个key的默认值。
Step3:  OrderedDict
使用 dict 字典时，Key 是无序的。在对 dict 做迭代访问时，我们无法确定 Key 的顺序。
如果要保持 Key 的顺序，可以用 OrderedDict，这是一个 Key 值有序的字典数据类型。
2020.4.30 从 Python 3.7 开始，默认的 dict 是有顺序的，而不是之前版本是乱序的，也就是默认的 dict 就是记住插入的顺序的。所以本节内容意义已经不大了。反过来证明有序字典是一个多么重要的功能点，已经从包中的功能被移植到了主功能中。
Step4:  Counter
Counter是一个简单的计数器，例如，统计字符出现的个数：
Step5:  思考一下
回文数：判断一个整数是否是回文数。回文数是指正序（从左向右）和倒序（从右向左）读都是一样的整数，比如 121 就是一个回文数，201 就不是。
<ASSISTANT_TASK:>
Python Code:
# nametuple 举例
from collections import namedtuple
point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x, p.y)  
print(type(p))
i = p.x + p.y
print(i)
# nametuple 举例
from collections import namedtuple
Web = namedtuple('web', ['name', 'type', 'url'])
p1 = Web('google', 'search', 'www.google.com')
p2 = Web('sina', 'portal', 'www.sina.com.cn')
print(p1)
print(p1.name, p1.url)
print(p1.url, p2.url)
# 遍历 nametuple
for i in p2:
    print(i)
# 复杂的基于 namedtuple list demo
from collections import namedtuple
Web = namedtuple('web', ['name', 'type', 'url'])
p = []
p.append(Web('google', 'search', 'www.google.com'))
p.append(Web('sina', 'portal', 'www.sina.com.cn'))
print(p)
for i in p:
    print(i.name)
# 显示 namedtuple 的字段名称
print(Web._fields)
Explanation: Lesson 11
Python Basic, Lesson 6, v1.0.1, 2017.1 by David.Yi   
Python Basic, Lesson 6, v1.0.2, 2017.5 modified by Yimeng.Zhang  
v1.1, 2020.4. edit by David Yi
本次内容要点
集合库 collections 简介
namedtuple: 生成可以使用名字来访问元素内容的tuple子类
deque: 双端队列，可以快速的从另外一侧追加和推出对象
defaultdict: 带有默认值的字典
OrderedDict: 有序字典
Counter: 计数器
思考一下：回文数
collections
collections 是 Python 内建的一个集合模块，提供了许多有用的集合类。我们来完整的看看 collections 提供了哪些扩展功能。
python 内置了大量的功能函数，但是再多的函数和模块也不可能覆盖实际应用需要的所有功能，怎么扩展程序功能，怎么划分功能模块，python 自己所带的这些模块是最好的参考书！
namedtuple: 生成可以使用名字来访问元素内容的tuple子类
deque: 双端队列，可以快速的从另外一侧追加和推出对象
defaultdict: 带有默认值的字典
OrderedDict: 有序字典
Counter: 计数器
namedtuple 有名字的元组
namedtuple 主要用来产生可以使用名称来访问元素的数据对象，通常用来增强代码的可读性，在访问一些 tuple 类型的数据时尤其好用。
namedtuple 是一个函数，它用来创建一个自定义的 tuple 对象，并且规定了 tuple 元素的个数，可以用属性而不是索引来写入或者访问 tuple 的某个元素。
这样一来，我们用 namedtuple 可以很方便地定义一种数据类型，比如 XY 坐标，它具备 tuple 的内容不变性，又可以根据属性来引用，使用十分方便。
End of explanation
# deque 举例
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)
# 对比 list 和 deque 的速度
from collections import deque
import time
# list
q0 = [x*x for x in range(10000000)]
# list
a = time.time()
q0.insert(0,88888)
b = time.time()
print(b-a)
# 生成 deque
q1= deque(q0)
# deque
a = time.time()
q1.appendleft(88888)
b = time.time()
print('%2.16f' % (b-a))
from collections import deque
l = ['a','b','c','d']
l = deque(l)
print(l)
# deque rotation
l = ['a','b','c','d','e']
l = deque(l)
l.rotate(2)
print(l)
l.rotate(-2)
print(l)
# deque pop() 同样可以区分头尾
l = deque(['a','b','c'])
l.pop()
print(l)
# 删除左边的元素
l = deque(['a','b','c'])
l.popleft()
print(l)
Explanation: deque
使用 list 存储数据时，按索引访问元素很快，但是插入和删除元素就很慢了，因为 list 是线性存储，数据量大的时候，插入和删除效率很低。
deque 是为了高效实现插入和删除操作的双向列表，适合用于队列和栈。
deque 在插入数据时候速度比 list 快很多，当然这个是相对存在大量数据的 list 而言的。如果你的程序中需要对有百万级别的 list 频繁的在各个位置插入删除数据，那么用 deque 是值得的。
End of explanation
# 标准的字典用法
i = {'name':'David'}
print(i['name'])
# 不存在 key，则会报错
i = {'name':'David'}
print(i['score'])
# defaultdict 举例
from collections import defaultdict
d = defaultdict(lambda: 100)
d['name']='David'
print(d['name'])
# default 返回默认值，不会报错
print(d['score'])
print(d['best_score'])
from collections import defaultdict
d = defaultdict(lambda: '100')
d['name']='David'
print(d['name'])
print(d['score'])
Explanation: defaultdict
我们都知道，在使用 Python 原生数据结构字典的时候，如果用 d[key] 这样的方式访问，当指定的key不存在时，是会抛出KeyError异常的，也就是发生错误。（可以用 get 方法来避免这样的错误）
如果使用 defaultdict，只要你传入一个默认的方法，那么请求一个不存在的 key 时，便会调用这个方法，使用其结果来作为这个key的默认值。
End of explanation
# dict 是无序的
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)
# 传统dict 追加一对 key value
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)
d['d'] = 4
print(d)
# 使用 OrderedDict
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d)
# 使用 OrderedDict, 追加一对 key value
# OrderedDict 的 key 会按照插入的顺序排列，不是 key 本身排序
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d)
d['d'] = 4
print(d)
# OrderedDict可以实现一个FIFO（先进先出）的dict，当容量超出限制时，先删除最早添加的Key：
from collections import OrderedDict
class LastUpdatedOrderedDict(OrderedDict):
    def __init__(self, capacity):
        super(LastUpdatedOrderedDict, self).__init__()
        self._capacity = capacity
    def __setitem__(self, key, value):
        containsKey = 1 if key in self else 0
        if len(self) - containsKey >= self._capacity:
            last = self.popitem(last=False)
            print('remove:', last)
        if containsKey:
            del self[key]
            print('set:', (key, value))
        else:
            print('add:', (key, value))
        OrderedDict.__setitem__(self, key, value)
        
d = LastUpdatedOrderedDict(4)
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d)
d['d'] = 4
d['e'] = 5
d['f'] = 6
print(d)
# 简化的先进先出Dict
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d)
# 3个参数：原始有序字典，容量限制，待插入的key，待插入的value
def update_ordereddict(ordered_dict, len_limit ,key, value):
    if len(ordered_dict) >=0 and len(ordered_dict) < len_limit:
        ordered_dict[key]=value
        return ordered_dict
    else:
        ordered_dict.popitem(last=False)
        ordered_dict[key]=value
        return ordered_dict
# 插入一个新key-value
update_ordereddict(d, 3, 'new_key', 4)
Explanation: OrderedDict
使用 dict 字典时，Key 是无序的。在对 dict 做迭代访问时，我们无法确定 Key 的顺序。
如果要保持 Key 的顺序，可以用 OrderedDict，这是一个 Key 值有序的字典数据类型。
2020.4.30 从 Python 3.7 开始，默认的 dict 是有顺序的，而不是之前版本是乱序的，也就是默认的 dict 就是记住插入的顺序的。所以本节内容意义已经不大了。反过来证明有序字典是一个多么重要的功能点，已经从包中的功能被移植到了主功能中。
End of explanation
# Counter类的目的是用来跟踪值出现的次数,以字典的键值对形式存储，其中元素作为key，其计数作为value
# 下面这个例子就是使用 Counter 模块统计一段句子里面所有字符出现次数
from collections import Counter
s = 'A Counter is a dict subclass. '.lower()
c = Counter(s)
# 获取出现频率最高的5个字符
print(c.most_common(5))
# 是否可以统计中文呢？
s = '他会自己长大远去我们也各自远去'
c = Counter(s)
print(c.most_common(5))
# Counter 举例，用户输入内容
from collections import Counter
s = input('Please input:')
s = s.lower()
c = Counter(s)
# 获取出现频率最高的5个字符
print(c.most_common(5))
# 读出 Counter 对象中的key 和value
s = 'A Counter is a dict subclass. '.lower()
c = Counter(s)
# 用列表生成式获得 counter 中的 key
list1 = [k for k,v in c.most_common()]
# 用列表生成式获得 counter 中的 value
list2 = [v for k,v in c.most_common()]
print(list1)
print(list2)
# 我们在 notebook 中画个图
import matplotlib.pyplot as plt
 
plt.bar(range(len(list2)), list2,color='rgb',tick_label=list1)
plt.show()
Explanation: Counter
Counter是一个简单的计数器，例如，统计字符出现的个数：
End of explanation
# 回文数
# 参考 leetcode 用了类来表示
class Solution:
    def isPalindrome(self, x: int) -> bool:
        x = str(x)
        return x == x[::-1]
Solution().isPalindrome(x='121')
Explanation: 思考一下
回文数：判断一个整数是否是回文数。回文数是指正序（从左向右）和倒序（从右向左）读都是一样的整数，比如 121 就是一个回文数，201 就不是。
End of explanation
<END_TASK>