The Python Tutorial_Python初学

小结

Python的基础, 简单小结

  1. 数据类型: 字符串,数值类型(float/decimal),布尔值(True/False), None,
    Mutation/Immutation, Enums
  2. 数据结构: tuple(元组), list(列表), dict(字典), set(集合), deque(队列), defaultdict, bisect, heapq…
  3. 流程控制: if, while, else(相当方便),break, continue, return, [:](切片), range, pass, comprehensions(推导式), in/not/and/or…
  4. 函数: def, 参数, 匿名函数(lambda), 内置函数,
  5. 类: class, 多继承, 实例变量/类变量, 属性(函数变量: local, global), 方法, 内置方法(new,init,slot… )
  6. 解释器: 模块(标准模块, 编译, 命名空间, 路径), 自定义模块, 包(引用), dir()
  7. 多线程: threading, 协程, 生成器
  8. 其他: 文件, 字符串格式化, Template, 异常, 迭代器, 日志, 弱引用…
    PS: Python作为一种脚本语言, 官方文档都有功能实现的源码!!!
    全篇有点长, 建议直接复制脚本自己跑一下或者取下git的源码文件

学习文档

  1. Git Hub Source Code
  2. The Python Tutorial 中文

Source Code

part 1

# 3 Python 简介
# 数字
# 除法(/)永远返回一个浮点数.
# // 整除; % 计算余数; ** 乘幂;  复数 j 或 J 表示虚数部分 3+5j
print(3+5j)
print('1e11',1e11)

# 字符串
# 字符串可以视作字符数组, 支持切片和索引, 但它是不可变的
# 用单引号 ('...') 或双引号 ("...") 标识.\ 可以用来转义引号
# "Isn't," she said.
print('"Isn\'t," she said.')  
# r raw 返回原是字符串
# "Isn't," she said.
print(r'"Isn\'t," she said.')  
# 字符串文本能够分成多行.一种方法是使用三引号:"""...""" 或者 '''...'''
# 行尾换行符会被自动包含到字符串中,但是可以在行尾加上 \ 来避免这个行为,没有第一行
print("""\
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
""")
# 字符串格式化操作 str.format(* args,** kwargs )
print('the sum of {} + {} = {}'.format(1, 2, 3))

# 列表
# 中括号之间的一列逗号分隔的值.列表的元素不必是同一类型
# 列表可以被索引和切片, 并且列表是可变的
# 切片操作都会返回一个包含请求的元素的新列表(浅拷贝:传递对象的引用,并非对象里的值)
squares = [1, 4, 9, 16, 25, 36]
print('squares[:], squares[1], squares[-1], squares[-3:], [-1, 0]+squares',
      squares[:], squares[1], squares[-1], squares[-3:], [-1, 0]+squares)



# 4 Python流程控制
# if
# x = int(input("please input an integer: "))
x = 0
if x < 0:
    print('{} is smaller than 0'.format(x))
elif x == 0:
    print('{} is equal to 0'.format(x))
elif x > 0:
    print('{} is bigger than 0'.format(x))
# for
words = ['cat', 'eat', 'fish', 'is so cute']
# [:]: 返回原数组的浅拷贝对象
for w in words[:]:  
    if len(w) > 6:
        words.insert(-1, 'insert')
print(words)
# range() 函数
# range: 返回从0开始的可迭代对象, 能够像期望的序列返回连续项的对象
# -1 2: [-1, 5)
for i in range(-1, 5, 3):
    print(i)
# break, for..else
for n in range(2, 10):
    for i in range(2, n):
        if n % i == 0:
            print(n, '=', i, '*', n//i)
            break
    else:
        print(n, 'is a prime number')
# continue
for num in range(2,10):
    if num % 2 == 0:
        print('even number: ', num)
        continue
    print('odd number:', num)
# pass
# pass 可以在创建新代码时用来做函数或控制体的占位符
# pass 可以默默的被忽视
i=0
while i<10:
    print(i, end='... ')
    pass
    i+=1
print()


# 函数 def
# 关键字 def 引入了一个函数 定义.在其后必须跟有函数名和包括形式参数的圆括号.
# 函数体语句从下一行开始,必须是缩进的
def fib(n):
    """print a fibonacci series up to n"""
    a, b = 0,1# tuple
    while a < n:
        print(a, end='... ')
        a,b=b, a+b
    n = n+1
    print()
# 函数 调用 会为函数局部变量生成一个新的符号表.
# 所有函数中的变量赋值都是将值存储在局部符号表.
# 变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表.
# 因此,全局变量不能在函数中直接赋值(除非用 global 语句命名),尽管他们可以被引用.
fib(10)
# 函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 
# 这里的 值 总是一个对象 引用 ,而不是该对象的值. 基本值类型传入的是值, 不会影响实参原来的值
class SimpleClass:
    name = 'simpleclass'
def SimpleClassFunction(sc):
    print(sc.name)
    sc.color='red'
simpleClass = SimpleClass()
SimpleClassFunction(simpleClass)
print(simpleClass.color) #red
# 一个函数定义会在当前符号表内引入函数名.
# 函数名指代的值(即函数体)有一个被 Python 解释器认定为 用户自定义函数 的类型. 
# 这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用
f = fib
f(5)
# return 语句从函数中返回一个值,不带表达式的 return 返回 None
print(fib(0))
# 默认参数
# 为一个或多个参数指定默认值.这会创建一个可以使用比定义时允许的参数更少的参数调用的函数
# 默认值在函数 定义 作用域被解析, 默认值的赋值发生在函数定义时期.默认值只被赋值一次
# 调用时传入的实参值会覆盖掉默认值.
# 这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例
i = 5
def f_default_para(a=i, L=[]):
    L.append(a)
    return L
i = 6
print(f_default_para())# [5]    ! no 6
print(f_default_para())# [5, 5] 
print(f_default_para(i))# [5, 5, 6] # 实参为6
  
# 可选参数
# 使用:函数装饰器,猴子补丁(程序运行时(runtime)修改某些代码)
# *name 必须在 **name 之前出现
# 可选参数打印出来的参数的顺序是未定义
# 可选参数应该是是参数列表中的最后一个,因为它们将把所有的剩余输入参数传递给函数
def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    keys = sorted(keywords.keys())
    for kw in keys:
        print(kw, ":", keywords[kw])
cheeseshop("Limburger", "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")
# 元组参数 *args
def test_asterisk(f_arg, *arg_vars):
    print('f_arg', f_arg)
    for arg in arg_vars:
        print('arg in arg_vars', arg)

test_asterisk('yasoob', 'python', 'eggs', 'test')
# 字典参数 **dargs
def test_kvps(**arg_vars):
    for (key, v) in arg_vars.items():
        print("{0} == {1}".format(key, v))

test_kvps(**{'name': 'yasoob'})
# 使用时的顺序不能改变
def test_args(arg1, *arg2, **arg3):
    print('f_arg', arg1)
    for arg in arg2:
        print('arg in arg_vars', arg)
    for (key, v) in arg3.items():
        print("{0} == {1}".format(key, v))
test_args('yasoob', 'python', 'eggs', 'test', 123123, name = 'yasoob')
# * 操作符来自动把参数列表拆开
# ** 操作符分拆关键字参数为字典
args = [3, 6]
# 等价于list(range(3,6))
list(range(*args))  
# 关键字参数 keyword = value
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("action, state, type: ", action, state,type, end=' .. ')
    print("voltage: ", voltage)
parrot(action='VOOOOOM', voltage=1000000)
parrot('a million', 'bereft of life', 'jump')
"""
parrot()                     # required argument missing
parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
parrot(110, voltage=220)     # duplicate value for the same argument
parrot(actor='John Cleese')  # unknown keyword argument
"""    


# Lambda 匿名函数
# 通过 lambda 关键字,可以创建短小的匿名函数 lambda a, b: a+b
# 语义上讲,它们只是普通函数定义中的一个语法技巧.类似于嵌套函数定义,
# lambda 形式可以从外部作用域引用变量
def add(n):
    return lambda x:x+n
# add(5) 不是简单的单入参函数, <function add.<locals>.<lambda> at 0x003194B0>    
add(5) 
f=add(10)
# 等价于f(x=2) x是lambda中引用的x
f(2) 
# 匿名函数可以作为参数传递
pairs = [(1,'one'),(2,'two'),(3,'three'),(4,'four')]
# pair[1]: pairs的组成元组的第二个元素: one ,  two , three , four
pairs.sort(key=lambda pair: pair[1])  
print('pairs',pairs)


# 文档字符串
#第一行应该是关于对象用途的简介.不用明确的陈述对象名或类型, 应该以大写字母开头,以句号结尾.
#如果文档字符串有多行,第二行应该空出来,与接下来的详细描述明确分隔
def doc_string():
    """    Just document.

    this is just document detail
    """
print(doc_string.__doc__)


# 函数注释
# 函数的额外注释, 是关于用户自定义的函数的完全可选的、随意的元数据信息
# funcdef ::=  [decorators] "def" funcname "(" [parameter_list] ")" 
# ["->" expression] ":" suite
"""
def mysum(a, b: int, c: 'the default is 5' = 5)-> 'Nothing to see here':
    '''    Return a+b+c.
    __annotations__ 是函数的一个属性,类型为 dict.可以在程序运行时动态地修改注释
    '''
    result = a+b+c 
    mysum.__annotations__['return'] += result
    return result
print(mysum(1,'3',2))  
#{'b': <class 'int'>, 'c': 'the default is 5', 'return': 'Nothing to see here132'}
print(mysum.__annotations__)  
"""

# 编码风格
# 代码的易读性对大型复杂程序的多人协作, 代码维护至关重要,可以有效的缩短时间
'''
使用 4 空格缩进,而非 TAB
折行以确保其不会超过 79 个字符
使用空行分隔函数和类,以及函数中的大块代码
可能的话,注释独占一行
使用文档字符串
把空格放到操作符两边,以及逗号后面,但是括号里侧不加空格:a = f(1, 2) + g(3, 4)
统一函数和类命名,推荐类名用 驼峰命名, 函数和方法名用 小写_和_下划线.总是用 self 作为方法的第一个参数
不要使用花哨的编码,如果你的代码的目的是要在国际化环境.Python 的默认情况下,UTF-8,甚至普通的 ASCII 总是工作的最好
#!/usr/bin/python  
# -*- coding: utf-8 -*- 
'''



# 5 数据结构
# 列表
#list.append(x) 把一个元素添加到列表的结尾 a[len(a):] = [x]
l = [1,2,3,4,5]
l.append(6)
print("l.append(6)",l)
#list.extend(L) 将一个给定列表中的所有元素追加到另一个列表中,a[len(a):] = L
le = [10,11,11,4,4,1,1]
l.extend(le)
print("l.extend(le)",l)
#list.insert(i, x) 在指定位置插入一个元素
l.insert(0,0)
print("l.insert(0,0)",l)
#list.remove(x) 删除列表中值为 x 的第一个元素, 没有则返回报错:list.remove(x): x not in list
l.remove(3)
# l.remove(3)
print("l.remove(3)",l)
#list.pop([i])  删除指定索引的元素,并将其返回.如果没有指定索引,a.pop() 返回最后一个元素
l.pop()
print("l.pop()",l)
l.pop(1)
print("l.pop(1)",l)
#list.index(x) 返回列表中第一个值为 x 的元素的索引.如果没有匹配的元素就会返回一个错误
print("l.index(4)",l.index(4))
#list.count(x) 返回 x 在列表中出现的次数.
print("l.count(4)",l.count(4))
#list.sort() 对列表中的元素就地进行排序.
# 不同类型的元素返回报错: TypeError: '<' not supported between instances of 'int' and 'str'
l.sort()
print("l.sort()",l)
#list.reverse() 就地倒排列表中的元素.
l.reverse()
print("l.reverse()",l)
#list.copy() 返回列表的一个浅拷贝, s[:]
# 深拷贝和浅拷贝的区别: 只是在拷贝符合对象(包含其他对象的对象,像列表或类实例)时有区别
# https://docs.python.org/3.6/library/copy.html#module-copy
#浅拷贝在新的内存中构建一个新的复合对象然后插入原对象的引用地址, 原来的复合对象值有变动也就会反映到新拷贝的对象
#深拷贝同样在新的内存中构建一个新的复合对象,然后会递归的将原对象的值拷贝到新对象里
lc = l.copy()
ld = l
print("l.copy()",lc)
# list.clear() 从列表中删除所有元素.相当于 del a[:]
l.clear()
print("ld",ld)

# 把列表当作堆栈使用 
# 堆栈作为特定的数据结构,最先进入的元素最后一个被释放(后进先出).
# 用 append() 方法可以把一个元素添加到堆栈顶.用不指定索引的 pop() 方法可以把一个元素从堆栈顶释放出来
stack = [3,4,5]
stack.append(6)
stack.append(7)
print('stack.append(7)', stack)
stack.pop()
print('stack.pop()', stack)
# 把列表当作队列使用 
# 队列作为特定的数据结构,最先进入的元素最先释放(先进先出).不过,列表这样用效率不高.
# 在头部插入和弹出很慢(因为,为了一个元素,要移动整个列表中的所有元素).
# 要实现队列,使用 collections.deque,它为在首尾两端快速插入和删除而设计
from collections import deque
queue = deque(['Eric','P','J'])
queue.append('Han')
queue.append('L')
print('queue', queue)
print('queue.popleft()', queue.popleft())
print('queue', queue)

# 列表推导式 
# 列表推导式由包含一个表达式的括号组成,表达式后面跟随一个 for 子句,之后可以有零或多个 for 或 if 子句.结果是一个列表
squares = [x**2 for x in range(10)]
print('[x**2 for x in range(10)]', squares)
# 等价于
squares = list(map(lambda x: x**2, range(10)))
print('list(map(lambda x: x**2, range(10)))', squares)
# 结果要求是元组, 必须加(x,y)
print('[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]: ',
    [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y])
# 嵌套的列表推导式
matrix = [[1,2,3,4], [5,6,7,8],[9,10,11,12]]
print('[row[i] for row in matrix for i in range(4)]', [[row[i] for row in matrix] for i in range(4)])
# 等价于
transposed_matrix= []
for i in range(4):
    transposed_row = []
    for row in matrix:
        transposed_row.append(row[i])
    transposed_matrix.append(transposed_row)
print('transposed_matrix', transposed_matrix)
print( *matrix ) #[1, 2, 3, 4] [5, 6, 7, 8] [9, 10, 11, 12]
print('list(zip(*matrix))',list(zip(*matrix)))

# del
# 从列表中按给定的索引而不是值来删除一个子项  
# del 还可以从列表中删除切片或清空整个列表
del transposed_matrix[0]
print('del transposed_matrix[0]', transposed_matrix)
del transposed_matrix[0:2]
print('del transposed_matrix[0:2]',transposed_matrix)
del transposed_matrix # transposed_matrix' is not defined

# tuple 元组
# 序列类型 https://docs.python.org/3/library/stdtypes.html#typesseq
# 一个元组由数个逗号分隔的值组成, 可以没有括号
# 元组就像元素是不同类型的字符串, 不可变的.通常包含不同种类的元素并通过分拆 或索引访问(如果是 namedtuples,甚至可以通过属性).
# 列表是 可变的 ,它们的元素通常是相同类型的并通过迭代访问.
# 空元组 () 和单元素 (ele, )
# 元组封装和元组拆封
t = 123,32,'test'
print(t)
x,y,z = t
print('x,y,z',x,y,z)

# set 集合 
# 集合是一个无序不重复元素的集.基本功能包括关系测试和消除重复元素.
# 集合对象还支持 union(|),intersection(&),difference(-)和 sysmmetric difference(^)等数学运算.
# 大括号或 set() 函数可以用来创建集合.注意:想要创建空集合,你必须使用 set() 而不是 {}.后者用于创建空字典
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket) #{'apple', 'pear', 'banana', 'orange'}
# sysmmetric difference 对称差集 letters in a or b but not both
a=set('1234')
b=set('3456')
print('a^b', a^b)
# 集合推导式
print("{x for x in '123456789' if x not in '3456'}",{x for x in '123456789' if x not in '3456'})

# dict 字典 
# 无序的键: 值对 (key:value 对)集合
# 序列是以连续的整数为索引,与此不同的是,字典以 关键字 为索引,关键字可以是任意不可变类型,通常用字符串或数值.
# 如果元组中只包含字符串和数字,它可以做为关键字,如果它直接或间接的包含了可变对象,就不能当做关键字
# 字典的主要操作是依据键来存储和析取值.也可以用 del 来删除键:值对(key:value).
# 一个已经存在的关键字存储值,以前为该关键字分配的值就会被遗忘.试图从一个不存在的键中取值会导致错误
# list(d.keys())返回一个字典中所有关键字组成的无序列表,  sorted(d.keys())返回有序列表
d=dict(sape=4139, guido=4127, jack=4098)
print(d, sorted(d.keys()), sorted(d.values()))
for k,v in d.items():
    print(k,v)

# 循环
#序列循环 使用enumerate() 同时得到索引和值
for i,v in enumerate(['one','two','three']):
    print(i,v)
# zip整体打包多个序列 
# https://docs.python.org/3/library/functions.html#zip
# 返回元组的迭代器,其中第i个元组包含来自每个参数序列或迭代的第i个元素.当最短输入可迭代用尽时,迭代器停止
qs = ['name','sex','old','color']
ans = ['benji','man',28,'black']
for q,a in zip(qs,ans):
    print('what is your {0}? It is {1}.'.format(q,a))
# 逆向循环
for i in reversed(range(3)):
    print(i)
# 顺序排序 
# sorted() 函数,它不改动原序列,而是生成一个新的已排序的序列:
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for e in sorted(set(basket)):
    print(e)
print(basket)
# 循环内部修改正在遍历的序列, 切片可以方便的制作副本
words = ['cat', 'dog', 'gollria']
for w in words[:]:
    if len(w)>6: words.insert(0, w)
print(words)

# 深入条件控制
# while 和 if 语句中使用的条件不仅可以使用比较,而且可以包含任意的操作
# 比较操作符 in 和 not in 审核值是否在一个区间之内.操作符 is 和 is not 比较两个对象是否相同
# 比较操作符具有相同的优先级,低于所有的数值操作
# 比较操作可以传递, a < b == c 审核是否 a 小于 b 并且 b 等于 c
# 比较操作可以通过逻辑操作符 and 和 or 组合,比较的结果可以用 not 来取反义 
# A and not B or C 等于 (A and (notB)) or C
# 在表达式内部不能赋值
# 逻辑操作符 and 和 or 也称作短路操作符:它们的参数从左向右解析,一旦结果可以确定就停止 
string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
st = string1 or not string2 or string3
print(st)

part 2

# 6 模块
# 模块的目的是 更好的复用文件中的函数
# Python 提供了一个方法可以从文件中获取定义,在脚本或者解释器的一个交互式实例中使用.这样的文件被称为 模块
# 模块是包括 Python 定义和声明的文件.文件名就是模块名加上 .py 后缀.
# 模块的模块名(做为一个字符串)可以由全局变量 __name__ 得到 
import fibo
print('fibo.fib(10)', end=' ')
fibo.fib(10)
print('fibo.fib_ary(20)', fibo.fib_ary(20))
localfib = fibo.fib
localfib(55)    
# 每个模块都有自己私有的符号表,被模块内所有的函数定义作为全局符号表使用.
# 因此,模块的作者可以在模块内部使用全局变量,而无需担心它与某个用户的全局变量意外冲突
# 模块可以导入其他的模块 import 语句的一个变体直接从被导入的模块中导入命名到本模块的语义表
from fibo import fib, fib_ary
fib(56)

# 作为脚本来执行模块
# 通常用来为模块提供一个便于测试的用户接口(将模块作为脚本执行测试需求)
'''
python fibo.py 123
fib. __name__ __main__
1 1 2 3 5 8 13 21 34 55 89
'''
# 模块中的代码会被执行,就像导入它一样,不过此时 __name__ 被设置为 "__main__", 
# 通过import导入后调用__name__ 被设置为 模块名称 fibo
'''
# 在脚本的最后加上 
 if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))
'''

# 模块的搜索路径 
# 导入fibo模块时, 解释器会到sys.path指定的路径下搜索模块
#    解释器会先在当前目录下搜索名为fibo.py的文件
#    没有找到的话,会到环境变量PythonPath的目录列表中搜索
#    仍没有找到的话, 会到Python默认安装路径中搜索
import sys
print('sys.path',sys.path)

# 编译的python文件
# 为了加快加载模块的速度,Python 会在 __pycache__ 目录下以 module.version.pyc 名字缓存每个模块编译后的版本,
# 这里的版本编制了编译后文件的格式,这种命名约定允许由不同发布和不同版本的 Python 编译的模块同时存在.
#   为了减少一个编译模块的大小,你可以在 Python 命令行中使用 -O 或者 -OO.
#   -O 参数删除了断言语句,-OO 参数删除了断言语句和 __doc__ 字符串.
#   "优化的" 模块有一个 .pyo 后缀而不是 .pyc 后缀.未来的版本可能会改变优化的效果.
#   .pyc 文件或 .pyo 文件中的程序不会比来自 .py 文件的运行更快;.pyc 或 .pyo 文件只是在它们加载的时候更快一些.
#   compileall 模块可以为指定目录中的所有模块创建 .pyc 文件
#   https://docs.python.org/3/library/compileall.html#module-compileall 
'''
import compileall
compileall.compile_dir('../Python_Base_3_6/', force=True)
# Perform same compilation, excluding files in .svn directories.
import re
compileall.compile_dir('../Python_Base_3_6/', rx=re.compile(r'[/\\][.]svn'), force=True)
# pathlib.Path objects can also be used.
import pathlib
compileall.compile_dir(pathlib.Path('../Python_Base_3_6/'), force=True)
'''
# 标准模块
# Python 带有一个标准模块库,并发布有独立的文档,名为 Python 库参考手册(此后称其为"库参考手册") 
# sys ,这个模块内置于所有的 Python 解释器
# 交互模式下定义主提示符sys.ps1 和辅助提示符字符串 sys.ps2

# dir
# 内置函数 dir() 用于按模块名搜索模块定义,它返回一个字符串类型的存储列表
print('dir(fibo)',dir(fibo))
print('dir()',dir())

# Package 包
# 包通常是使用用"圆点模块名"的结构化模块命名空间, 可以避免全局变量之间的相互冲突
# 名为 A.B 的模块表示了名为 A 的包中名为 B 的子模块
# 为了让 Python 将目录当做内容包,目录中必须包含 __init__.py 文件.
# 这是为了避免一个含有烂俗名字的目录无意中隐藏了稍后在模块搜索路径中出现的有效模块,比如 string.
# 最简单的情况下,只需要一个空的 __init__.py 文件即可

# 包内引用
from subpack import effects
effects.echo()
from subpack.effects_1 import echo
echo()
'''
#  文件夹被python解释器视作package需要满足两个条件:
#  1、文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件.
#  2、不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口).
#       使用相对导入的时候一定要注意包路径和包的查找路径.要在最顶层的目录添加到 sys.path 中,或者 在最顶层运行脚本
#   ValueError: attempted relative import beyond top-level package
from ..Python_Advanced import PythonAdvanced_1
PythonAdvanced_1.test_asterisk('yasoob', 'python', 'eggs', 'test') 
''' 
# 多重目录中的包
# 包支持一个更为特殊的特性, __path__: https://docs.python.org/3/reference/import.html#__path__
# 在包的 __init__.py 文件代码执行之前,该变量初始化一个目录名列表.该变量可以修改,它作用于包中的子包和模块的搜索功能



# 字符串 
# Python 有办法将任意值转为字符串:将它传入 repr() 或 str() 函数.
# 函数 str() 用于将值转化为适于人阅读的形式,而 repr() 转化为供解释器读取的形式
s = 'Hello, world.'
print('str(s)',str(s))
print('repr(s)',repr(s))
#'!a' (应用 ascii()),'!s' (应用 str() )和 '!r' (应用 repr() 
import math
print('The value of PI is approximately {!r}.'.format(math.pi))
print('The value of PI is approximately {0:.3f}.'.format(math.pi))
#命名来引用被格式化的变量 传入一个字典,用中括号( '[]' )访问它的键
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
          'Dcab: {0[Dcab]:d}'.format(table))
#‘**’ 将这个字典转换成关键字参数
print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))         



# Class 类 
# 像模块一样,Python 的类并没有在用户和定义之间设立绝对的屏障,而是依赖于用户不去"强行闯入定义"的优雅.
# 另一方面,类的大多数重要特性都被完整的保留下来:
# 类继承机制允许多重继承,派生类可以覆盖(override)基类中的任何方法或类,可以使用相同的方法名称调用基类的方法.
# 对象可以包含任意数量的私有数据
# Python 作用域和命名空间 
# 命名空间 是从命名到实例对象的映射. 通过python字典实现 
# 不同的命名空间在不同的时刻创建,有不同的生存期:  
#   包含内置命名的命名空间在 Python 解释器启动时创建,会一直保留.模块的全局命名空间在模块定义被读入时创建
#   调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理的异常时被删除 
# 作用域 就是一个 Python 程序可以直接访问命名空间的正文区域 
# python引用变量的顺序: 当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量 
# 尽管作用域被静态的定义, 但他们使用时是动态的
#   首先搜索最内层的作用域,它包含局部命名任意函数包含的作用域,
#       是内层嵌套作用域搜索起点,包含非局部,但是也非全局的命名
#   接下来的作用域包含当前模块的全局命名
#   最外层的作用域(最后搜索)是包含内置命名的命名空间 
# nolocal, global
# nolocal: https://docs.python.org/3/reference/simple_stmts.html#nonlocal
# 使用当前函数或块级作用域的外层作用域(非全局)中的变量;可以取多次嵌套后的外层变量 
# global: https://docs.python.org/3/reference/simple_stmts.html#global
# 全局变量在函数或块级作用域内有读权限没有写权限, global用来赋予写权限
# !!! nolocal只是引用, 不能引用在外层作用域中未声明的变量; global可以直接声明
def scope_test():
    def fun_local():
        #1 spam作用域只局限于fun_local内部
        spam = 'local spam'
    def fun_nolocal():
        #2 nonlocal将spam提升到scope_test函数的作用域
        nonlocal spam
        spam = 'nolocal spam'
        def fun_localInlocal():
            nonlocal spam
            spam = 'fun_localInlocal spam'
            print('IN fun_localInlocal', spam)
        fun_localInlocal()
    def fun_global():
        #3 global将spam提升到scope_test函数所在模块的作用域
        global spam
        spam = 'global spam'
    #4 spam作用域为scope_test内部
    spam = 'test spam'
    #test spam: fun_local里的spam未被访问, 下方spam实际为#4
    fun_local()
    print('after local assignment:', spam)
    #nolocal spam: fun_nolocal.spam被提升到scope_test作用域, spam从test spam重新赋值为nolocal spam
    fun_nolocal()
    print('after nolocal assignment:', spam)
    #nolocal spam: fun_global.spam被提升出scope_test作用域,等同于#5
    # 所以下方的spam仍然指向#4, fun_global内改变的是#5
    fun_global()
    print('after global assignment:', spam)
#5 
spam1 = 'global out'
scope_test()
# global spam: fun_global函数内被重新赋值
print('In global scope:', spam)
# 类定义
'''
class ClassName:
    <statement-1>
    ...
    <statement-N>
'''
class MyClass:
    """A simple example class"""
    i = 123
    def func(self):
        return 'hello world: ' + str(self.i)
# 类对象支持两种操作:属性引用和实例化
# 实例化 使用函数符号() 将类对象看作是一个返回新的类实例的无参数函数
myClass = MyClass()
# 属性引用 obj.name 类对象创建后,类命名空间中所有的命名都是有效属性名
# 123 <function MyClass.func at 0x01EE9618> 123 hello world: 123
print('MyClass.i, MyClass.func, myClass.i, myClass.func(): ',
    MyClass.i, MyClass.func, myClass.i, myClass.func())

# __new__(): 在创建类实例时发生调用. https://docs.python.org/3/reference/datamodel.html#object.__new__
# __init__(self[, ...]): 在类实例创建(__new__())后但还未返回给调用者时调用
# 多用来初始化对象的属性, 视作构造函数; 返回None将抛出TypeError错误
class Complex():
    def __init__(self, real =0, imag=0):
        self.r = real
        self.i = imag
x = Complex(1,2)
print('x, x.i, x.r',x, x.i, x.r)

# 实例对象
# 实例对象唯一可用的操作是属性引用, 包括数据引用和方法引用
# 数据对象是类实例的属性, Python是动态语言,根据类创建的实例可以任意绑定属性
# 这意味着不仅可以引用类中定义的属性, 实例自身可以再绑定, 但会增加性能成本, 
# __slot__可以限制这种任意绑定的行为, 删除属性 del x.counter
x.counter = 1
x.counter = x.counter + 1
print('x.counter, x.i', x.counter, x.i)
del x.counter
del x.i 
# AttributeError: 'Complex' object has no attribute 'i'
# print('x, x.i, x.r',x, x.i, x.r)
# 方法对象 myClass.func()
# 工作原理: 引用非数据属性的实例属性时,会搜索它的类.
#   如果这是有效的函数对象类属性,就会将实例对象和函数对象封装进一个抽象对象:这就是方法对象 
#   以一个参数列表调用方法对象时,它被重新拆封,
#   用实例对象和原始的参数列表构造一个新的参数列表,然后函数对象调用这个新的参数列表 
# myClass.func 是一个方法对象,它可以存储起来以后调用
myFunc = myClass.func()
print('myFunc',myFunc)
# 类实例.fun() = 类.fun(类实例)
print('myClass.func(), MyClass.func(myClass)', 
    myClass.func(), MyClass.func(myClass))

# 类变量和实例变量
# 实例变量用于对每一个实例都是唯一的数据,类变量用于类的所有实例共享的属性和方法
# 可变对象, 例如列表和字典, 作为类变量声明时, 即使作为实例变量初始化也会被所有类实例共享
#       可变对象不应该作为类变量, 若不想被共享, 应该作为实例变量被声明
class Dog:
    classList = []
    def __init__(self, name):
        self.name = name
        # 不会被所有类实例共享
        self.insList = []
    def add_classList(self, tricks):
        self.classList.append(tricks)
        self.insList.append(tricks)
d = Dog('Fido')
e = Dog('Buddy')
d.add_classList('roll over')
e.add_classList('play dead')
# d.classList, d.insList:  ['roll over', 'play dead'] ['roll over']
print('d.classList, d.insList: ',d.classList, d.insList)

# Note
# 数据属性会覆盖同名的方法属性.为了避免意外的名称冲突, 做一些约定 
#   大写方法名称的首字母,使用一个唯一的小字符串(也许只是一个下划线)作为数据属性名称的前缀,或者方法使用动词而数据属性使用名词
# 数据属性可以被方法引用,也可以由一个对象的普通用户(客户)使用.
#   客户应该谨慎的使用数据属性, 客户可以向一个实例对象添加他们自己的数据属性,而不会影响方法的正确性
# 类不能用来实现纯净的数据类型
# 从方法内部引用数据属性(或其他方法)并没有快捷方式, nolocal, global 
# 方法的第一个参数被命名为 self.这仅仅是一个约定:
#   对 Python 而言,名称 self 绝对没有任何特殊含义, 但有些 类查看器 程序也可能是遵循此约定编写
# 类属性的任何函数对象都为那个类的实例定义了一个方法.
#   函数定义代码不一定非得定义在类中:也可以将一个函数对象赋值给类中的一个局部变量 
def f1(self, x, y):
    return min(x,y)
class C:
    f = f1
    def g(self):
        return 'hello world'
    # h 严格等于g
    h = g
c = C()
print('c.f(1,-1), c.h()',c.f(1,-1), c.h())
# 通过 self 参数的方法属性,方法可以调用其它的方法
class Bag:
    def __init__(self):
        self.data = []
    def add(self, x):
        self.data.append(x)
    def add2(self, x):
        self.add(x)
        self.add(x)
b = Bag()
b.add2('this is going to be added twice')
print(b.data)
# 每个值都是一个对象,因此每个值都有一个 类( class ) (也称为它的 类型( type ) ),它存储为 object.__class__
# 全局作用域确有很多合法的用途:其一是方法可以调用导入全局作用域的函数和方法,也可以调用定义在其中的类和函数

# 类继承
'''
# 基类与派生类定义在一个作用域内
class DerivedClassName(BaseClassName):
    <statement-1>
    ...
    <statement-N>
# 基类定义在另一个模块
class DerivedClassName(modname.BaseClassName):
    <statement-1>
    ...
    <statement-N>    
'''
# 派生类定义的执行过程和基类是一样的.
#   构造派生类对象时,就记住了基类.这在解析属性引用的时候尤其有用:如果在类中找不到请求调用的属性,就搜索基类.
#   如果基类是由别的类派生而来,这个规则会递归的应用上去.
# 派生类可能会覆盖其基类的方法,Python 中的所有方法本质上都是 虚 方法
# 派生类中的覆盖方法扩充基类中的重名方法, 调用基类方法然后拓展,
#   调用方式:BaseClassName.methodname(self, arguments)
# Python中两个用于继承的函数
#   函数 isinstance() 用于检查实例类型: isinstance(obj, int)
#   函数 issubclass() 用于检查类继承: issubclass(bool, int) 为 True

# 多继承
'''
# 动态的线性化算法,super()调用方法的优先级为从左到右的, 有高到低 
# 父类的父类优先级比父类更低: Base1 > Base2 > Base
class DerivedClassName(Base1, Base2):
    <statement-1>
    ...
    <statement-N>
'''
class Base(object):
    def echo(self):
        print('Base')
    def echoBase(self):
        print('Base')
class Base1(Base):
    def echo(self):
        print('Base--1')
class Base2(Base):
    def echo(self):
        print('Base--2')
class Derived(Base1, Base2):
    def echo(self):
        super().echo()
        print('Derived')
d = Derived()
# Base--1 Derived
d.echo() 
# Base
d.echoBase()

# 私有变量
# 只能从对像内部访问的"私有"实例变量,在 Python 中不存在.
# 变通的方法:以一个下划线开头的命名(包括属性和函数),例如 _spam会被处理为 API 的非公开部分 
class Mapping:
    __test = 'test'
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)
    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)
    # __update是基类方法私有的, 不会被子类重写
    __update = update
m = Mapping(['iter1','iter2'])
# m.__test # 'Mapping' object has no attribute '__test'
print(m.items_list)
class MappingSub(Mapping):
    # def __init__(self):self.items_list = []
    # 子类重写了基类的update(), 但无法修改__update, 
    # 不能重写__init__, 会破坏基类中调用__init__
    def update(self, keys, values):
        for item in zip(keys, values):
            self.items_list.append(item)
msub = MappingSub('BASE')
msub.update('qwe','1234')
# ['B', 'A', 'S', 'E', ('q', '1'), ('w', '2'), ('e', '3')]
print(msub.items_list)     

# 结构体
# 通过创建空的类,作为结构体类型
class Employee:
    __slots__ = ["name","dept","salary"]
john = Employee() 
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
print('john.name,john.dept,john.salary',john.name,john.dept,john.salary)

# 用户自定义异常
# 用户自定义异常类要继承Exception或其派生类
# 抛出异常 raise Class/Class()
#raise B # __main__.B: B ErrorInfo
#raise B() #__main__.B: B ErrorInfo
class B(Exception):
    def __init__(self):
        super().__init__(self) #初始化父类
        self.errorinfo='B ErrorInfo'
    def __str__(self):
        return self.errorinfo 
class CC(B):
    pass
class D(CC):
    pass
# 异常的抛出顺序: 抛出第一个相符的异常. 这就是说, 如果将异常的基类放在第一个匹配的位置, 它的子类异常就没有机会匹配
# 如果B在最前会打印: B B B 
for cls in [B, CC, D]:
    try:
        raise cls()
    except D:
        print("D", end=' ')
    except CC:
        print("CC", end=' ')
    except B:
        print("B", end=' ')

# 迭代器
# for语句在容器类中会调用__iter__(), 该函数返回一个定义了 __next__() 方法的迭代器对象,它在容器中逐一访问元素.
# 没有后续的元素时, __next__() 抛出一个 StopIteration 异常通知 for 语句循环结束
# 实现迭代器机制: 定义一个返回__next__()方法返回值的__iter__()函数, 如果已经定义了__next__(), 只要返回self
class Reverse:
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __next__(self):
        if self.index <=0 : raise StopIteration
        self.index -= 1
        return self.data[self.index]
    def __iter__(self):
        return self
#f d s a        
for item in Reverse('asdf'):
    print(item, end=' ')
# 生成器
# 生成器(Generators): 生成器是只迭代一次的迭代器.这是因为它们并没有把所有的值存在内存中,而是在运行时生成值.
#    通过yield每次返回一个单次运行的值, 而不是直接返回占用大量空间的一个值
#    调用:用for循环,或可进行迭代的函数或结构
#    next(): 它允许我们获取一个序列的下一个元素. yield所有值后会触发 StopIteration exception 
#       next() 被调用时,生成器回复它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
#    生成器是数据的生产者 协程则是数据的消费者. yield可获得一个协程.协程会消费掉发送给它的值
# 生成器表达式 range, zip
#set(word  for line in page  for word in line.split())
#max((student.gpa, student.name) for student in graduates)
from math import pi, sin
sine_table = {x: sin(x*pi/180) for x in range(0, 91)}
print('sine_table ',sine_table)
xvec = [10, 20, 30]
yvec = [7, 5, 3]
print(sum(x*y for x,y in zip(xvec, yvec)) )

part 3

# 10 Python 标准库概览
# 1. 操作系统接口, os 模块提供与操作系统交互的函数
# OS routines for NT or Posix depending on what system we're on
# 应该使用import os 风格而非 from os import *。
# 这样可以保证随操作系统不同而有所变化的 os.open() 不会覆盖内置函数 open()
import os
path = r"C:\_Git\LabSourceCode\Python\Python_Base_3_6"
todaypath = "C:\\_Git\\LabSourceCode\\Python\\Python_Base_3_6\\today\\"
# get current working directory
print('os.getcwd()', os.getcwd())
# Change current working directory
os.chdir(path)
# Run the command mkdir in the system shell
newfolder = "if not exist " + todaypath + " ( mkdir today )"
os.system(newfolder)
#print('dir(os), help(os)',dir(os), help(os))
# shutil 高层面的文件操作接口
import shutil
print(shutil.copyfile('fibo.py', r'today\fibo_copy.py'))
#shutil.move('/build/executables', 'installdir')

# 2 文件通配符
import glob 
print(glob.glob('*.py'))
print(glob.glob('fibo.*'))

# 3 命令行参数
# 通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv 变量: sys.argv
# python demo.py one two three

# 4 错误输出重定向和程序终止
# sys 还有 stdin, stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示警告和错误信息
# 大多脚本的直接终止都使用 sys.exit()
import sys
sys.stderr.write('Warning, log file not found starting a new one\n')
# sys.exit()
sys.stdout.write('Stdout, log file not found starting a new one\n')

# 5 字符串正则匹配
import re
# *: >=0; +:>=1; ?:0/1
# *?, =?, ?? 非贪婪匹配
# re.findall(pattern,string,flags = 0 )
# ['foot', 'fell', 'fastest']
print(re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest'))
# re.sub(pattern,repl,string,count = 0,flags = 0 )
# 返回通过替换repl替换字符串中最左边的非重叠模式而获得的字符串
# ??? \number 匹配相同编号的组的内容 组从1开始编号
# cat in the hat
print(re.sub(r'(\b[a-z]+) \1', r'\1', 'cat cat in the the hat'))

# 6 数学 
import math
#不是0, 非常接近0 6.123233995736766e-17
print('math.cos(math.pi/2)',math.cos(math.pi/2))
#10.0
print(math.log(1024, 2))
import random
# 从非空序列seq返回一个随机元素
print("random.choice('asdfghjkl')",random.choice('asdfghjkl'))
# 返回从序列或集合中选择的k长度的元素列表。用于随机抽样而无需更换
print(random.sample(range(100),10))
print(random.randrange(0,111,11))

# 7 互联网访问
url=r'https://blog.csdn.net/sgs595595/article/details/81747397'
'''
# 简单的 pip install requests
import requests
session = requests.session()
html = session.get(url).content
print('requests', len(html))
# 简单的 pip install urllib3
import urllib3, certifi
http = urllib3.PoolManager()
html = http.request('GET', url)
print(len(html.data))

# 邮件
import smtplib
server = smtplib.SMTP('smtp.live.com') 
server.sendmail('[email protected]', '[email protected]',
" to '[email protected]' from '[email protected]': send via python smtplib")
'''

# 8 日期和时间 
# https://docs.python.org/3/library/datetime.html#module-datetime 
# https://docs.python.org/3/library/time.html#module-time
# https://docs.python.org/3/library/calendar.html#module-calendar
# 支持日期和时间算法的同时,实现的重点放在更有效的处理和格式化输出。该模块还支持时区处理 
from datetime import date
now = date.today()
print('date.today()', now)
# stringformattime: Return a string representing the date, controlled by an explicit format string
print('now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")', 
    now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B."))
MyBirthday = date(1992,4,20)
age = now - MyBirthday
print('age.days ',age.days)

# 9. 数据压缩
# https://docs.python.org/3/library/zlib.html#module-zlib 
import zlib
s = b'this is a zlib sample string, this is a zlib sample string2'
print("len(s)",len(s))
t = zlib.compress(s, level=9)
print("len(t) ,t",len(t), t)
print('zlib.decompress(t)', zlib.decompress(t))
# zlib.crc32(data[, value]): computes a CRC (Cyclic Redundancy Check) checksum of data
print("zlib.crc32(s), zlib.crc32(zlib.decompress(t))",zlib.crc32(s), zlib.crc32(zlib.decompress(t)))

# 10 性能度量
# [timeit: small bits of Python code](https://docs.python.org/3/library/timeit.html#module-timeit)
import timeit
from timeit import Timer
print("Timer('t=a; a=b; b=t', 'a=1;b=2').timeit(number=1000000)",
      Timer('t=a; a=b; b=t', 'a=1;b=2').timeit(number=1000000))
print("timeit.timeit('t=a; a=b; b=t', 'a=1;b=2', number=1000000)",
      timeit.timeit('t=a; a=b; b=t', 'a=1;b=2', number=1000000))
print("Timer('a,b = b,a', 'a=1;b=2').timeit(number=1000000)",
      Timer('a,b = b,a', 'a=1;b=2').timeit(number=1000000))
print("timeit.timeit('a,b = b,a', 'a=1;b=2', number=1000000)",
      timeit.timeit('a,b = b,a', 'a=1;b=2', number=1000000))
# 对大代码块的时间度量工具
# [profile](https://docs.python.org/3/library/profile.html#module-profile)
# [pstats](https://docs.python.org/3/library/profile.html#module-pstats)
# calibrate: 该方法直接在分析器下执行参数给出的Python调用次数,测量两者的时间。然后,它计算每个探查器事件的隐藏开销,并将其作为浮点数返回
import profile
pr = profile.Profile()
for i in range(3):
    print('pr.calibrate(int(1e4)) ',pr.calibrate(int(1e4)))

# 11 质量控制
# doctest 模块提供了一个工具,扫描模块并根据程序中内嵌的文档字符串执行测试 
# https://docs.python.org/3/library/doctest.html#module-doctest
# python PythonBase_3.py -v
def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """ 
    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result
if __name__ == "__main__":
    import doctest
    doctest.testmod()

# unittest 模块不像 doctest 模块那么容易使用,不过它可以在一个独立的文件里提供一个更全面的测试集
# https://docs.python.org/3/library/unittest.html#module-unittest
# python PythonBase_3.py
# after run unittest.main(), script will exit
import unittest
class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')
    def test_isUpper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())
    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hellos','world'])
        with self.assertRaises(TypeError):
            s.split(2)
#if __name__ == '__main__':
#    unittest.main()
 


# 标准库 Part 2
# 支持专业编程工作所需的更高级的模块
# 1. 输出格式
# reprlib https://docs.python.org/3/library/reprlib.html#module-reprlib
# reprlib 模块为大型的或深度嵌套的容器缩写显示提供了repr()函数的一个定制版本 
import reprlib
print("reprlib.repr(set('https://docs.python.org/3/library/reprlib.html#module-reprlib'))", 
    reprlib.repr(set('https://docs.python.org/3/library/reprlib.html#module-reprlib')))
# pprint data pretty printer:一种解释器可读的方式深入控制内置和用户自定义对象的打印
# https://docs.python.org/3/library/pprint.html#module-pprint
import pprint 
t = [[['black', 'cyan'], 'white', ['green','red']],[['blue','yellow','red']] ]
pprint.pprint(t,width=50)
# textwrap 模块格式化文本段落以适应设定的屏宽
# https://docs.python.org/3/library/textwrap.html#module-textwrap
import textwrap
doc = '''When you are old and grey and full of sleep, and nodding by the fire, take down this book,
and slowly read, and dream of the soft book '''
print(textwrap.fill(doc, width=60))
# locale 模块按访问预定好的国家信息数据库
# https://docs.python.org/3/library/locale.html#module-locale
import locale
print("locale.setlocale(locale.LC_ALL, 'English_United States.1252') ",
    locale.setlocale(locale.LC_ALL, 'English_United States.1252'))
conv = locale.localeconv()
x = 1234567489.1
print('locale.format_string("%d", x, grouping=True) ', 
    locale.format_string("%d", x, grouping=True))
print ("locale.format_string('%s%.*f', (conv['currency_symbol'], conv['frac_digits'], x), grouping=True)", 
    locale.format_string('%s%.*f', (conv['currency_symbol'], conv['frac_digits'], x), grouping=True))

# 2. Template 模板
# class string.Template(template) https://docs.python.org/3/library/string.html#string.Template
# string 提供了一个灵活多变的模版类 Template ,使用它最终用户可以用简单的进行编辑
# 格式使用 $ 为开头的 Python 合法标识(数字、字母和下划线)作为占位符。
#   占位符外面的大括号使它可以和其它的字符不加空格混在一起。 $$ 创建一个单独的 $
from string import Template
t = Template('${village}folk send $$10 to $cause')
print("t.substitute(village='Shanghai', cause='the dich fund')",
    t.substitute(village='Shanghai', cause='the dich fund'))
# safe_substitute()如果数据不完整,它就不会改变占位符
print("t.safe_substitute(village='Shanghai')", t.safe_substitute(village='Shanghai'))
# 模板子类可以指定一个自定义分隔符
# 实例: 图像查看器的批量重命名工具;  把多样的输出格式细节从程序逻辑中分类
import time
photofiles = ['img_1074.jpg','img_1075.jpg','img_1077.jpg']
class BatchRename(Template):
    delimiter = '%'
fmt = 'BEN_%d%n%f'
t = BatchRename(fmt)
date = time.strftime('%d%b%y_')
for i, filename in enumerate(photofiles):
    newname = t.safe_substitute(d=date, n=i, f='.ext')
    # BEN_04Dec18_0.ext
    print('newname', newname)

# 3. 使用二进制数据记录布局
# struct 模块为使用变长的二进制记录格式提供了 pack() 和 unpack() 函数
# [struct — Interpret bytes as packed binary data](https://docs.python.org/3/library/struct.html#struct.unpack)
# 压缩码 "H" 和 "I" 分别表示2和4字节无符号数字,"<" 表明它们都是标准大小并且按照 little-endian 字节排序
import struct
with open('demo.zip', 'rb') as f:
    data=f.read()
start = 0
for i in range(3):
    start += 14
    fields = struct.unpack('<IIIHH',data[start:start+16])
    crc32, comp_size, uncomp_size, filename_size, extra_size = fields
    start += 16
    filename=data[start:start+filename_size]
    start += filename_size
    extra = data[start:start+extra_size]
    print('filename, hex(crc32), comp_size, uncomp_size ',filename, hex(crc32), comp_size, uncomp_size)
    start += extra_size+comp_size

# 4. 多线程
# 线程是一个分离无顺序依赖关系任务的技术 
# [threading — Thread-based parallelism](https://docs.python.org/3/library/threading.html#module-threading)   
# 在某些任务运行于后台的时候应用程序会变得迟缓,线程可以提升其速度。
# 用途: I/O 的同时其它线程可以并行计算
# 主要挑战: 协调线程,诸如线程间共享数据或其它资源。
#   为了达到那个目的,线程模块提供了许多同步化的原生支持,包括:锁,事件,条件变量和信号灯 
#   任务协调的首选方法是把对一个资源的所有访问集中在一个单独的线程中,
#       然后使用 queue 模块用那个线程服务其他线程的请求。https://docs.python.org/3/library/queue.html#module-queue
#   为内部线程通信和协调而使用 Queue 对象的应用程序更易于设计,更可读,并且更可靠
import threading, zipfile, datetime
class AsyncZip(threading.Thread):
    def __init__(self, infile, outfile):
        threading.Thread.__init__(self)
        self.infile=infile
        self.outfile=outfile
    # run() 线程要做的活动或任务.多被重写
    def run(self):
        f= zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
        f.write(self.infile)
        f.close()
        print('Finished background zip of:', self.infile,' at current time ', datetime.datetime.now().strftime('%H:%M:%S.%f') )
        print('time.sleep(1)', time.sleep(1))
        print('run after sleep current time ', datetime.datetime.now().strftime('%H:%M:%S.%f'))
background = AsyncZip('fibo.py', 'fibo.zip')
print('AsyncZip current time ', datetime.datetime.now().strftime('%H:%M:%S.%f'))
# 开始线程, 一个线程对象至多运行一次. 将在一个可控的独立线程中运行run()
background.start()
print('background.start() current time ', datetime.datetime.now().strftime('%H:%M:%S.%f'))
# 等待线程, 等待直到线程结束. 这会阻塞调用线程, 直到调用join()的线程对象结束或返回异常,或者超时
background.join()
print('background.join() current time ', datetime.datetime.now().strftime('%H:%M:%S.%f'))

# 5. 日志
# logging 模块提供了完整和灵活的日志系统。
# [logging — Logging facility for Python](https://docs.python.org/3/library/logging.html#module-logging)
# 它最简单的用法是记录信息并发送到一个文件或 sys.stderr
# Logger对象提供应用程序可直接使用的接口,Handler保存日志到介质: 文件,字节流等,
# Filter提供了过滤日志信息的方法,Formatter指定日志显示格式
import logging 
logging.basicConfig(level=logging.DEBUG, 
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='test.log',
                    filemode='w')
logging.debug('logging debug info')
logging.info('logging info info')
logging.error('logging error info')
logging.warning('logging warning info')
logging.critical('logging critical info')

# 6. 弱引用
# Python 自动进行内存管理(对大多数的对象进行引用计数和垃圾回收—— 垃圾回收 ——以循环利用)
#   最后一个引用消失后,内存会很快释放. 但是为跟踪它们创建引用也会使其长期存在
# weakref 模块提供了不用创建引用的跟踪对象工具,一旦对象不再存在,它自动从弱引用表上删除并触发回调
import weakref, gc
class A:
    def __init__(self,value):
        self.value = value
    def __repr__(self):
        return str(self.value)
a = A(10)
a2 = A(10)
d = weakref.WeakValueDictionary()
ds = {}
d['primary'] = a
ds['primary'] = a2
print("d['primary'],ds['primary']",d['primary'],ds['primary'])
del a
del a2
gc.collect()
# 10
print("ds['primary']", ds['primary']) 
# has been removed, get KeyError: primary 
#print("d['primary']",d['primary'])

# 7. 用于列表工作的工具
# array 模块提供了一个类似列表的 array() 对象,它仅仅是存储数据,更为紧凑
from array import array
a = array('H', [4000, 10,12,555])
print('sum(a), a[1:3]',sum(a), a[1:3])
a = ['H', [4000, 10,12,555]]
print('a[1:3]', a[1:3])
# collections 模块提供了类似列表的 deque() 对象,
#   它从左边添加(append)和弹出(pop)更快,但是在内部查询更慢。
# 适用于队列实现和广度优先的树搜索
from collections import deque
d = deque(["task1","task2","task3"])
d.append('task4')
print('handling', d.popleft())
print('deque append, popleft ', d)
# 广度优先搜索 根结点开始沿着树的宽度, 横向搜索遍历
'''
# 实现思路
unsearched = deque([starting_node])
def breadth_first_search(unsearched):
    node = unsearched.popleft()
    for m in gen_moves(node):
        if is_goal(m):
            return m
        unsearched.append(m)
'''
# bisect 
# [bisect — Array bisection algorithm](https://docs.python.org/3/library/bisect.html#module-bisect) 
# 操作有序的存储链表, 采用简单的二分法对有序的数组进行插入,查询
import bisect
scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
bisect.insort(scores, (300, 'aaaa'))
print('scores',scores)
# heapq 
# [heapq — Heap queue algorithm¶](https://github.com/python/cpython/blob/3.7/Lib/heapq.py)
# 提供了基于优先队列的堆实现。priority_queue允许用户为队列中元素设置优先级,
#   放置元素的时候不是直接放到队尾,而是放置到比它优先级低的元素前面
# 最小的值总是保持在a[0]。适用于循环访问最小元素但是不想执行完整堆排序
from heapq import heapify, heappop, heappush
data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
heapify(data); print('data',data)
heappush(data, -5)
print('[heappop(data) for i in range(3)]', [heappop(data) for i in range(3)])
print('data',data)

# 8. 十进制浮点数算法
# decimal 模块提供了一个 Decimal 数据类型用于浮点数计算。
# [decimal — Decimal fixed point and floating point arithmetic](https://docs.python.org/3/library/decimal.html#module-decimal)
# 相比内置的二进制浮点数实现 float的优点
#   金融应用和其它需要精确十进制表达的场合,
from decimal import *
# 0.735 向上五入 得 0.74
print("round(Decimal('0.70')*Decimal('1.05'), 2)", 
    round(Decimal('0.70')*Decimal('1.05'), 2))
# 0.735 向下四舍 得 0.73
print("round(0.70*1.05, 2)", round(0.70*1.05, 2))
# 控制精度,控制舍入以适应法律或者规定要求,
print("Decimal('1.00')%Decimal('.10'), 1.00%.10: ", 
    Decimal('1.00')%Decimal('.10'), 1.00%.10)
print("sum([Decimal('0.1')]*10)==Decimal('1.0'), sum([0.1]*10) == 1.0:", 
    sum([Decimal('0.1')]*10)==Decimal('1.0'), sum([0.1]*10) == 1.0)
# 确保十进制数位精度
getcontext().prec = 36
print("Decimal(1)/Decimal(7)", Decimal(1)/Decimal(7))

参考

Python

Begin

Coursera
https://www.py4e.com/html3/01-intro

Python 3.7.1 documentation

https://www.python.org/
https://docs.python.org/3/index.html
https://docs.python.org/3/contents.html
https://docs.python.org/3/reference/index.html
The Python Tutorial
The Python Tutorial 中文
Installing Python Modules

Python Advanced

Python 进阶
Python Tips
Glossary
Generators
Python3 datamodel
CPython Sourcecode
oauth2
sqlitebrowser.org
python-garbage-collector

Library

library
Built-in Functions
struct — Interpret bytes as packed binary data
The Python Debugger
Regular expression operations
Sequence Types — list, tuple, range
compileall — Byte-compile Python libraries
datetime — Basic date and time types
timeit: small bits of Python code
profile
pstats
doctest — Test interactive Python examples
unittest
pprint data pretty printer
string.Template(template)
threading — Thread-based parallelism
logging — Logging facility for Python
bisect — Array bisection algorithm
heapq — Heap queue algorithm¶
decimal — Decimal fixed point and floating point arithmetic

猜你喜欢

转载自blog.csdn.net/sgs595595/article/details/84842245