Loading

python_learn Ⅰ

基于 廖雪峰python3教程 学习。


目录:

  • 01_输入输出.py
  • 02_list、tuple.py
  • 03_条件判断.py
  • 04_循环.py
  • 05_利用循环排序.py
  • 06_自定义3元2次方程的根求解函数.py
  • 07_函数的参数.py
  • 08_递归函数.py
  • 09_切片.py
  • 10_迭代、索引.py
  • 11_列表生成式.py
  • 12_元组循环迭代列表生成式输出天干地支.py
  • 13_将列表大小写字符全部小写输出.py
  • 14_生成器.py
  • 15_生成器生成斐波拉契数列.py
  • 16_生成器生成杨辉三角.py
  • 17_迭代器.py
  • 18_高阶函数_map、reduce.py
  • 19_filter.py
  • 20_sorted.py
  • 21_返回函数.py
  • 22_匿名函数.py
  • 23_偏函数.py
  • 24_类和实例.py
  • 25_访问限制.py
  • 26_继承和多态.py
  • 27_获取对象信息.py
  • 28_实例属性和类属性.py
  • 29_限制实例属性__slots__.py
  • 30_使用@property.py
  • 31_多重继承.py
  • 32_枚举类.py
  • 33_文件读写.py
  • 34_StringIO_BytesIO.py
  • 35_操作文件和目录.py
  • 36_代码实现dir -l功能.py
  • 37_序列化_pickle模块.py
  • 38_JSON.py
  • 39_多进程.py
  • 40_多线程.py
  • 41_正则表达式.py
  • 42_datetime模块.py
  • 43_collections模块.py
  • 44_base64模块.py
  • 45_hashlib模块.py
  • 46_hmac模块.py
  • 47_itertools模块.py
  • 48_contextlib模块.py
  • 49_urllib模块.py
  • 50_XML解析.py
  • 51_HTMLParser模块.py
  • 52_pillow模块.py
  • 53_requests模块.py
  • 54_chardet模块.py
  • 55_psutil模块.py
  • 56_TCP编程.py
  • 57_UDP编程.py
  • 58_SMTP发送邮件.py
  • 59_POP3收取邮件.py
  • 60_使用SQLite.py
  • 61_使用MySQL.py
  • 62_使用SQLAIchemy.py
  • 63_WSGI接口.py

条件判断

#!/usr/bin/env python
# -*- coding: utf-8 -*-
h = float(input('请输入你的身高: '))
w = float(input('请输入你的体重: '))
bmi =float('%.1f' % (w//(h*h)))

if bmi<18.5:
    print('您的体重过轻')
elif bmi<25:
    print('您的处于正常范围')
elif bmi<28:
    print('您体重过重')
elif bmi<32:
    print('您处于肥胖状态')
else:
    print('您严重肥胖')

循环

#!/usr/bin/env python
# -*- coding: utf-8 -*-
L = ['Bart','Lisa','Adam']
for x in L:
    print('hello,',x)

利用循环排序

#!/usr/bin/env python
# -*- coding: utf-8 -*-

array = [1, 2, 5, 3, 6, 8, 4]
for i in range(len(array) - 1, 0, -1):
    print(i)
    for j in range(0, i):
        print(j)
        if array[j] > array[j + 1]:
            array[j], array[j + 1] = array[j + 1], array[j]
print(array)

三元二次方程求解

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import math
def quadratic(a,b,c):
    for s in (a,b,c):
        if not isinstance(s, (int, float)):
            raise TypeError('数字类型输入错误,请重新输入')
    d = float(b*b-4*a*c)
    if d < 0:
        print('方程无解')
    elif d == 0:
        x = (b + math.sqrt(d))/ (2*a)
        print('方程仅一个解: %.1f' % x)
    else:
        x1 = (b + math.sqrt(d))/(2*a)
        x2 = -(b + math.sqrt(d))/(2*a)
        print('方程有两个解: %.1f' % x1,x2)

quadratic(1,4,4)

函数的参数

#!/usr/bin/env python
#-*- coding: utf:8 -*-
# 阶乘函数
def power(x,n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

def power(x,n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

print(power(4,3))
print(power(5))

递归函数

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 利用递归函数计算阶乘
# N! = 1 * 2 * 3 * ... * N
def fact(n):
    if n == 1:
        return 1
    return n * fact(n-1)

print('fact(1) =', fact(1))
print('fact(5) =', fact(5))
print('fact(10) =', fact(10))
print('递归调用次数太多容易出现栈溢出')
print('--------------------------')

# 利用递归函数移动汉诺塔:
def move(n, a, b, c):  # n 为最初A柱子上的圆盘个数,将其从A移到C,B为缓冲区
    if n == 1:
        print('move', a, '-->', c)  # n=1 时,直接从A到C
    else:
        move(n-1, a, c, b)  # n 个时,先将 n-1 从A移到B
        move(1, a, b, c)  # 再将剩下最大的一个从A移到C
        move(n-1, b, a, c)  # 将刚才放在B上的 n-1 从B移到C
move(3, 'A', 'B', 'C')

切片

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 切片只能在list列表和tuple元组中,dict字典中不能进行切片输出

# list
L = list(range(20))
print(L)        #输出列表L
print(L[:])      #同上,输出所有列表数字,从起始到结束,起始结束位置可不写
print(L[:5])    #输出前5个数字,起始位置可省略
print(L[-3:])    #输出后3个数字,结尾位置可省略
print(L[::2])    #每隔一位输出L列表(输入偶数位)
print(L[1::2])  #从第一位起每隔两位输出L列表(输出奇数位)
print(L[::-1])  #倒序输出列表L
print(L[::-3])  #倒序每隔两位输出L
print('------------------------------------------------------------')

# tuple
s = (1,2,3,4,5)
print(s[:])
print(s[::-1])

迭代、索引

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#使用for...in...输出就是一种迭代
d = {'a':5, 'b':6, 'c':7, 'd':8}

for key in d:
    print(key)    #迭代输出字典d的字符

print('-----------------分隔符----------------')

for value in d.values():
    print(value)  #迭代输出字典d的字符的值

print('-----------------分隔符-----------------')

#enumerate()函数可以索引列举 list、tuple、dict 里面的内容
for zifu in d:
    print('输出字典d的内容:',zifu)

for value in d.values():
    print('输出字典d的字符值:',value)

for suoyin in enumerate(d):
    print('索引列举出字典d的内容:', suoyin)  #索引单个参数输出的是元组,如 (1, 2)

for key,hey in enumerate(d):
    print('索引列举出 key,hey:', key,hey)  #索引多个参数输出的是 字符序号 和 字符内容本身。

for x,y in ((1,1),(2,4),(3,9)):
    print(x,y)

print('-----------------分隔符-----------------')

#迭代可输出 列表、元组、字典、字符串,但不能迭代整数
#判断是否可迭代, isinstance() 判断对象类型
from collections import Iterable
print('isinstance([1,2,3],Iterable):', isinstance([1,2,3],Iterable))
print('isinstance((1,2,3),Iterable):', isinstance((1,2,3),Iterable))
print("isinstance({'a':1, 'b':2, 'c':3},Iterable):", isinstance({'a':1, 'b':2, 'c':3},Iterable))
print("isinstance('ABC'),Iterable:", isinstance('ABC',Iterable))
print('isinstance(123,Iterable):', isinstance(123,Iterable))

列表生成式

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#列表生成三种方法
print('法一:直接通过range()生成')
print(list(range(10)))

print('法二:通过循环在空列表末尾叠加')
L = []
for x in range(10):
    L.append(x*x)
print(L)

print('法三:列表生成式')
print([x*x for x in range(10)])              #直接列表生成式输出
print([x*x for x in range(10) if x%2==0])    #输出偶数的平方列表
print([x+y for x in 'ABCD' for y in 'EFGH'])  #二层循环输出列表

# *.values()、*.items()函数使用
d = {'A':'a', 'B':'b', 'C':'c', 'D':'d'}
for x in d.values():
    print(x)              #输出字符的值

for y,z in d.items():
    print(y,'=',z)        #将字符的值赋值给字符,即 A=a

元组循环迭代列表生成式输出天干地支

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#天干地支
print('***** 法一:循环 *****')

a=('甲','乙','丙','丁','戊','己','庚','辛','壬','癸')
b=('子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥')
c=[]
for i in range(60):
    print(i)
    c.append(a[i%len(a)]+b[i%len(b)])
print(c)

print('------------------------------------------------------')

print('***** 法二:列表生成式 *****')
#列表生成式一句代替法一循环输出,代码更简洁
a = ['甲','乙','丙','丁','戊','己','庚','辛','壬','癸']
b = ['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥']
c = [a[i%len(a)]+b[i%len(b)] for i in range(60)]
print (c)

将列表大小写字符全部小写输出

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#将列表的内容全部小写输出

print('--------- 场景一 ---------')
L = ['Hello', 'World', 'Apple']
print([s.lower() for s in L])


print('--------- 场景二 ---------')
L1 = ['Hello', 'World', 18, 'Apple', None]
#print([s.lower() for s in L1])  在L列表中能这样,L1中不能这样输出,因为 *.lower()函数对象只针对于字符串,不能对整型,空值进行。
L2 = []
for s in L1:
    if isinstance(s, str):    # isinstance()函数 判断 变量类型
        L2.append(s.lower())
    else:
        L2.append(s)
print(L2)

生成器

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#列表生成
L = [x*x for x in range(10)]
print(L)
print('----------- 分隔符 ----------')

#生成器,不一次生成,有效解决列表生成式循环次数过多带来的内存限制及空间浪费,生成器边循环边计算边输出
g = (x*x for x in range(10))
print('第一个:',next(g))
print('第二个:',next(g))
print('第三个:',next(g))
print('第四个:',next(g))
print('----------- 分隔符 ----------')

#生成器也可利用循环一次单行输出所有,不用向上面每次敲 next(g)
g = (x*x for x in range(10))
for s in g:
    print(s)
print('----------- 分隔符 ----------')

#生成器一次输出成一个列表,如最上面的列表生成一样
g = (x*x for x in range(10))
print([n for n in g])

生成器生成斐波拉契数列

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#斐波拉契数列:从第三位起,每位数都等于前两位数字的和
# 1,1,2,3,5,8,13,21,34,...

#方法一:判断、循环自定义显示斐波拉契数列的数字个数
max = int(input('请输入列表显示的位数 max:'))
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
print(fib(max))
print('----------------- 分隔符 ----------------')

#方法二:生成器生成,使用了 yield ,然后循环列出,输出没有 None 字符
min = int(input('请输入列表显示的位数 min:'))
def fab(min):
    n, a, b = 0, 0, 1
    while n < min:
        yield b
        a, b = b, a+b
        n = n + 1

L = []
for i in fab(min):
    L.append(i)
print(L)
print('------------ 分隔符 -----------')

#方法三:递归、循环自定义显示斐波拉契数列的数字个数
def xh(n):
    if n==1:
        return 1
    elif n==2:
        return 1
    else:
        return xh(n-1)+xh(n-2)

L = []
a = int(input('请输入列表显示的位数 a:'))
for s in range(1,a+1):
    L.append(xh(s))
print(L)

# 以上第一种和第三种会因函数中的变量值的加大而损耗内存,第二种生成器生成的,使用 yield 每次执行一次循环就挂起,
# 下次再从挂起的地方调用,不会一次性生成完,从而不会占用系统资源。虽然在此输出结果是相同的,这是因为for...in...
# 循环调用输出的次数使其全部输出了。

生成器生成杨辉三角

迭代器

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 可直接作用于 for 循环的对象统称为 可迭代对象:Iterable
# list、tuple、dict、str、for循环,是可迭代对象,整数不是可迭代对象。ininstance()判断 变量类型。
from collections import Iterable
print('isinstance([],Iterable):',isinstance([],Iterable))
print('isinstance((),Iterable):',isinstance((),Iterable))
print('isinstance({},Iterable):',isinstance({},Iterable))
print("isinstance('abc',Iterable):",isinstance('abc',Iterable))
print('isinstance((x for x in range(10)),Iterable):',isinstance((x for x in range(10)),Iterable))
print('isinstance(100,Iterable):',isinstance(100,Iterable))
print('-------------------- 分隔符 ------------------')


# 不但可以作用于 for 循环,还可以被next()函数不断调用并返回下一个值的叫 迭代器:Iterator
# list、tuple、dict、str、int 不是 迭代器,for 循环的 为 迭代器
from collections import Iterator
print('isinstance([],Iterator):',isinstance([],Iterator))
print('isinstance((),Iterator):',isinstance((),Iterator))
print('isinstance({},Iterator):',isinstance({},Iterator))
print("isinstance('abc',Iterator):",isinstance('abc',Iterator))
print('isinstance((x for x in range(10)),Iterator):',isinstance((x for x in range(10)),Iterator))
print('isinstance(100,Iterator):',isinstance(100,Iterator))
print('-------------------- 分隔符 ------------------')


# 将 可迭代对象 变为 迭代器 可以使用 iter() 函数
from collections import Iterator
print('isinstance(iter([]),Iterator):',isinstance(iter([]),Iterator))
print('isinstance(iter(()),Iterator):',isinstance(iter(()),Iterator))
print('isinstance(iter({}),Iterator):',isinstance(iter({}),Iterator))
print("isinstance(iter('abc'),Iterator):",isinstance(iter('abc'),Iterator))
print('isinstance((x for x in range(10)),Iterator):',isinstance((x for x in range(10)),Iterator))
print('isinstance(iter(100),Iterator):',isinstance(iter(100),Iterator))  # 注:整数不是 可迭代对象,所以加iter()也不能成为迭代器

# 小结:凡是可作用于for循环的对象都是Iterable类型;
# 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
# 迭代器都是可迭代对象,可迭代对象不一定是迭代器。

高阶函数map、reduce

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# map()函数:map()接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

# 示例一
def f(x):
    return x*x
r = map(f, [1, 2, 3, 4, 5])
print(list(r))

# 示例二
print(list(map(str, [1, 2, 3, 4, 5])))
print('------------------------------')


# reduce():作用在序列上,函数必须接收两个参数。将结果继续和序列下一个元素做累积计算。
# 在python3 中使用reduce函数要先从库中加载

# 示例一:列表元素求和
from functools import reduce
def sum(x,y):
    return x+y
print(reduce(sum, [1, 2, 3, 4, 5]))

# 示例二:将 [1,3,5,7,9] 输出为 13579
from functools import reduce
def fn(m, n):
    return 10 * m + n
print(reduce(fn, [1, 3, 5, 7, 9]))
print('------------------------------')

# 练习一:
# 利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。
# 输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']
# 大写字母转小写函数 lower(), 小写字母转大写函数 upper()
L1 = ['adam', 'LISA', 'barT']
def normalize(name):
    return name[0].upper()+name[1:].lower()
L2 = list(map(normalize, L1))
print(L2)
print('------------------------------')

# 练习二:
# sum()函数和上面reduce()函数代码均可求 list 的和,仿照定义 pord() 函数,求 list 的积
from functools import reduce
def s(x,y):
    return x * y
L = [3, 5, 7, 9]
def prod(L):
    return reduce(s, L)
print(prod(L))

print('------------------------------')

# 练习三:
# 利用 map 和 reduce 编写一个 str2float 函数,把字符串'123.456'转换成浮点数123.456
from functools import reduce
def str2float(s):
    s = s.split('.')    #以小数点为分隔符,把字符串分为两部分
    def f1(x,y):        #函数1,小数点之前的数用这个函数处理
        return x * 10 + y
    def f2(x,y):        #函数2,小数点之后的数用这个函数处理
        return x / 10 + y
    def str2num(str):    #函数3,用于把字符串'123'逐个变为数字
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[str]
    return reduce(f1,list(map(str2num,s[0]))) + reduce(f2,list(map(str2num,s[1]))[::-1])/10

print(str2float('123.456'))
# 最后一步是这个解法的精髓:
# 小数点前的数'123',用 x * 10 + y 正常求和就能得出123,小数点之后的数'456'要怎样才能得出0.456呢?
# 首先把字符串'456'用list(map(str2num,s[1]))转成一个列表[4,5,6]
# 然后用[::-1]切片的方式从后往前取,列表变为[6,5,4]
# 然后把[6,5,4]利用reduce函数放到f2函数中计算,( 6 / 10 + 5) / 10 + 4 = 4.56,得出结果4.56
# 再除以一个10,得出0.456,到此成功把字符串'456'变成了浮点数0.456
# 把前后结果加起来,就得到了最终解,成功把字符串'123.456'变成了浮点数123.456

filter

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 与map()类似,filter()也接收一个函数和一个序列。
# 和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
# 而map()仅返回 True or False
def is_odd(n):
    return n % 2 == 1
print(list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])))  # filter() 将自定义函数 is_odd() 为True的值返回
print(list(map(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])))      # map() 仅判断 True or False,不作筛选
print('----------------------------------------------------------')


# 练习一:计算素数
# 首先,列出从2开始的所有自然数,构造一个序列:
# 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
# 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
# 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
# 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 不断筛下去,就可以得到所有的素数。

def _odd_iter():    # 选取从 2 之后,且不为2倍数的数
    n = 1
    while True:
        n = n + 2
        yield n

def _not_divisible(n):    # 筛选掉以上所选数的倍数
    return lambda x: x % n > 0

def primes():    # 迭代过滤出满足要求的数 n
    yield 2
    it = _odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(_not_divisible(n), it)

def main():        # 给 n 一个取值,输出这些数
    for n in primes():
        if n < 10:
            print(n)
        else:
            break

if __name__ == '__main__':
    main()

print('----------------------------------------------------------')

# 练习二:列出 1~1000 的回数(顺着倒着读都一样,如:12321,909),使用filter()过滤掉非回数
def is_palindrome(n):
    return str(n) == str(n)[::-1]

output = filter(is_palindrome, range(1, 1000))
print(list(output))

sorted

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# sorted() 函数可以对list元素按小到大排序
print(sorted([36, 5, -12, 9, -21]))

# 此外 sorted() 也是一个高阶函数
print(sorted([36, 5, -12, 9, -21], key=abs))

# 字符串也是可以排序的,按的首字母ASCII的大小
print(sorted(['bob', 'about', 'Zoo', 'Credit']))

# 如果要按字母顺序,就需要加参数排除首字母大小写 ASCII 大小不一的干扰
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower))

print('-----------------------------------')

# 练习:
# 一组学生名字和成绩tuple,分别按名字字母、成绩排序
# L = [('Bob', 75), ('adam', 92), ('bart', 66), ('Lisa', 88)]

L = [('Bob', 75), ('adam', 92), ('bart', 66), ('Lisa', 88)]
def by_name(name):
    return name[0].lower()

def by_score(score):
    return score[1]

print(sorted(L, key=by_name))
print(sorted(L, key=by_score))
# 对于单个元组,(名字,成绩): name[0] 为名字,score[1] 为成绩

返回函数

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 函数作为返回值
# map reduce filter sorted 等高阶函数,它们将函数作为参数,除次之外,函数还可作为返回值。

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f = lazy_sum(1, 2, 4, 5, 7, 8, 9)
print(f)    # 输出错误,因为输出f时,f = lazy_sum() ,输出的是 lazy_sum() 函数里面的 sum() 求和函数
print(f())  # 输出 f() 时,才是输出 求和函数 sum() 的计算结果

f2 = lazy_sum(1, 2, 4, 5, 7, 8, 9)
print( f==f2 )      # 调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数。 所以 False
print( f()==f2() )  # 函数的参数一样,返回的结果值也一样,所以 True

# *args 与 **args 的区别:
# *args和**args适用于函数的参数不确定的时候。*args可以看做是多个变量组成的tuple,**args可以看做是个字典。

# def funarg1(arg):  #只允许传入一个参数
#    print(arg)
# funarg1(1)
# >>1          #输出执行结果

# def funarg(arg1,arg2,arg3): #必须传入3个参数
#    print(arg1,arg2,arg3)
# funarg(1,2,3)
# >>1,2,3      #输出执行结果

# def funargs(*args): #可以传入任意数量个参数(包括零个)
#    for i in args:
#        print(i)
# funargs(1,2,3,4,5)  #传入5个参数
# list2=(2,3,4,5,6)
# funargs(list2)      #传入列表
# funargs()
# >>1 2 3 4 5 (2,3,4,5,6)

print('----------------------------')

# 闭包
# why f1(), f2(), f3() returns 9, 9, 9 rather than 1, 4, 9?
def count():
    fs = []
    for i in range(1, 4):
        def f():
            return i * i
        fs.append(f)        # 此时函数f并没有执行,只是返回了函数f
    return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())

print('----------------------------')

def count():
    fs = []
    for i in range(1, 4):
        def f():
            return i * i
        fs.append(f())        # 此时函数f执行了,返回了具体的结果数值。这就不属于 返回函数 了
    return fs

f1, f2, f3 = count()

print(f1)
print(f2)
print(f3)

print('----------------------------')

# fix:
def count():
    fs = []
    def f(n):
        def j():
            return n * n
        return j
    for i in range(1, 4):
        fs.append(f(i))  # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

f1, f2, f3 = count()

print(f1())
print(f2())
print(f3())

# 小结:
# 函数既可以的作为高阶函数的参数,又可以作为一个函数的返回函数。
# 返回一个函数时,该函数并未执行,返回函数中不要引用任何可能会变化的变量。

匿名函数

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 匿名函数 lambda x: x * x
# 匿名函数简介方便,不用事先定义,也不用担心函数重名,但其只有有一个参数,一个表达式。

print(list(map(lambda x: x * x, [1, 2, 3, 4, 5])))

# 等同于:
def f(x):
    return x * x
print(list(f(x) for x in [1, 2, 3, 4, 5]))

偏函数

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# int()函数可以把字符串转换成整数
print(int('12345'))

# int()还可提供额外的base参数
print(int('12345',base=8))  #转化成8进制

print('----------------')

# 如果经常转换,每次都加 base 参数,很麻烦,可以定义一个函数
def int2(x,base=2):
    return int(x, base)

print(int2('1011010'))

print('----------------')

# 其实不用自定义函数,python自带的 functools.partial()偏函数 就能实现这一功能
import functools
int2 = functools.partial(int,base=2)  # functools.partial 就创建了一个偏函数

print(int2('1011010'))

类和实例

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 面向对象编程
# 类和实例

# 类是一个抽象的模版,实例是根据类创建出来的具体对象,属性是这个实例所具有的能力
# 比如说猫类、狗类,然后狗类里面又有具体的实例(泰迪、金毛、二哈),这些狗的实例都具有的属性(爱吃肉、骨头、会游泳)

# 定义 类 使用 class:
# class Student(object):
#    psss
# class 后面紧跟 类名(Student), 类名一般首字母大写。(object)表示该类从哪个类继承下来的。

# 定义 实例, 通过 类名+()实现
class Student(object):    # 创建Student类
    pass
bart = Student()      # 创建 bart 实例
bart.name = 'simpson'  # 给实例绑定属性,name,这个实例叫什么
print(bart.name)

# 创建实例的时候,把一些必须绑定的属性强制填写进去,通过 __init__ 方法 添加上相关属性。
# 以双下划线'__'开头和结尾的是特殊变量
class Student(object):
    def __init__(self, name, score):    # __init__ 方法的第一个参数永远是 self
        self.name = name
        self.score = score
bart = Student('simpson', 99)
print(bart.name)
print(bart.score)

print('------------------- ')


# 数据封装
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):
        print('%s: %s' % (self.name, self.score))
    def grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
# 以上整个类可以封装起来,对于用户来说,只要输入 名字、成绩 即可,不需要了解过程

# 输入
bart = Student('simpson', 99)
bart1 = Student('john', 67)
bart2 = Student('tom', 34)

# 输出
print('bart.name=', bart.name)
print('bart.score=', bart.score)
bart.print_score()
print('grade of bart:', bart.grade())
print('grade of bart1:', bart1.grade())
print('grade of bart2', bart2.grade())

访问限制

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 普通的类、实例、属性代码,可执行无报错
class Student():
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):
        print('%s: %s' % (self.name, self.score))

bart = Student('simpson', 99)
print(bart.name)

# 做了访问限制的属性,从外部访问该实例的属性,不能执行,回显错误
class Student():
    def __init__(self, name, score):
        self.__name = name        # 学生类的 __name__ 属性,是内部属性,外部不可访问
        self.__score = score      # 学生类的 __score__ 属性,是内部属性,外部不可访问
    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))

bart = Student('simpson', 99)
# print(bart.__name)    # 不可访问,代码报错。因为python解释器把 __name 变成了 _Student__name
print(bart._Student__name)    # 如果要在外部访问,可以使用 _Student__name

继承和多态

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 继承:可以把父类的功能直接拿过来,也可新增自己的方法,也可覆盖重写父类的方法,
# 这也造就了子类比父类有更多的可能,形成多态。

class Animal(object):    # 父类 动物类
    def run(self):
        print('Animal is running...')

class Dog(Animal):      # 子类 狗类
    pass
class Cat(Animal):      # 子类 猫类
    pass

dog = Dog()
cat = Cat()

dog.run()    # 无需再定义run(),直接调用父类的函数
cat.run()

print('---------------------')

# 多态
class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')    # 覆盖父类的方法
    def eat(self):
        print('Liking eat meat.')      # 新增自己的方法

dog = Dog()

dog.run()
dog.eat()

获取对象信息

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# type() 判断对象类型
print(type(123))    # int型
print(type('abc'))  # str
print(type(None))    # NoneType
print(type(abs))    # 函数方法

print(type(123)==type(456))  # 判断是否为同种类型, True or False。
print(type(123)==int)

print('----------------')

# isinstance() 与 type() 作用相同, isinstance() 多用于 class 继承关系里
class Animal(object):
    pass
class Dog(Animal):
    pass
class Husky(Dog):
    pass

a = Animal()
d = Dog()
h = Husky()

print(isinstance(h, Husky))
print(isinstance(h, Dog))
print(isinstance(h, Animal))

# dir():获得一个对象的所有属性和方法
print(dir('ABC'))

# 除了把对象的属性和方法列出来,还可使用 getattr()、setattr()、hasattr() 直接操作一个对象的状态
# getattr() 获取对象属性, setattr() 设置对象属性, hasattr() 询问对象是否有某属性
class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x
obj = MyObject()

print(hasattr(obj, 'x'))    # obj 有 x 属性吗?
print(getattr(obj, 'x'))    # 获取 x 属性的结果
print(obj.x)                # 等同于 getattr()
print(hasattr(obj, 'y'))    # 询问是否有 y 属性

setattr(obj, 'y', 10)        # 设置 y 属性及其具体值
print(getattr(obj, 'y'))    # 获取 y 属性结果

实例属性和类属性

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 实例属性 和 类属性 不要使用相同的名字,同名的 实例属性 将覆盖 类属性,当删除 实例属性 后,访问的是 类属性

class Student(object):        # Student类
    name = 'Student'          # 类的 name 属性

s = Student()                # 类的 实例s

print(s.name)                # 打印 实例s 的 name属性,s并没有该属性,往上找到它的类的 name属性
print(Student.name)          # 打印 类的 name属性

s.name = 'Michael'            # 给实例s设置一个name属性 Michael
print(s.name)                # 由于 实例属性 优先级比 类属性 高,覆盖 类属性,打印出 实例属性
print(Student.name)          # 打印 类属性

del s.name                    # 删除 实例属性
print(s.name)                # 输出的就是 类属性

限制实例属性__slots__

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 动态语言可以随时给实例绑定任何属性和方法
class Student(object):      # 定义一个类
    pass

s = Student()              # 创建类的 实例s
s.name = 'Michael'          # 动态给 实例s 加一个 name属性
print(s.name)

def set_age(self, age):    # 定义一个函数作为实例方法
    self.age = age

from types import MethodType
s.set_age = MethodType(set_age, s)    # 给 实例s 绑定 set_age 方法
s.set_age(25)        # 调用 set_age 方法
print(s.age)


s2 = Student()      # 创建类的 实例s2
# s2.set_age(15)      # 调用 set_age 方法
# print(s2.age)      # 输出结果出错,因为 s2 并未绑定 set_age 方法,给一个实例绑定方法,对另一个实例不起作用

# 为了给所有实例都添加可调用的方法,可对 class 绑定方法
# 方法一:动态绑定,可在程序运行过程中动态给 class 加上功能,这在静态语言中很难实现
def set_score(self, score):        # 程序任意位置定义 set_score 方法
    self.score = score

Student.set_score = set_score      # 给 Student类 绑定 set_score 方法

s.set_score(100)        # 实例s 可直接调用 class 方法
print(s.score)
s2.set_score(99)        # 实例s2 也可直接调用 class 方法
print(s2.score)

# 方法二:直接在最初创建类的地方定义类的方法
class Student(object):
    def set_score(self, score):
        self.score = score

# 特殊变量 __slots__  (前面还学习到特殊变量__init__)
# 该变量可限制实例属性,只允许添加定义的属性,相当于属性白名单。
# __slots__ 仅对当前类的实例生效,对其继承的子类实例不生效
class Student(object):
    __slots__ = ('name', 'age')    # 只允许定义这两种属性

s = Student()      # 创建实例
s.name = 'Tom'      # 添加实例 name属性
s.age = '17'        # 添加实例 age属性
# s.score = '90'    # 添加实例 score属性:不被允许,报错
print(s.name)
print(s.age)
# print(s.score)

class Xiaoming(Student):    # 创建子类 Xiaoming
    pass

y = Xiaoming()        # 创建实例y
y.name = 'xm'
y.age = '18'
y.score = '99'        # 父类中 禁用的属性,不影响 子类 的使用
print(y.name)
print(y.age)
print(y.score)        # 正常打印 y.score

使用@property

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#属性函数(property):
#将类方法转换为只读属性
#重新实现一个属性的setter和getter方法

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

s = Student()
s.score = 60
print('s.score =', s.score)
# ValueError: score must between 0 ~ 100!
s.score = 9999

多重继承

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# MixIn
#“混入”:Mix in。
# 在设计类的继承关系时,通常,主线都是单一继承下来的。但是,如果需要“混入”额外的功能,
# 通过多重继承就可以实现。

# 动物类
class Animal(object):
    pass

# 又将动物分为哺乳动物和鸟类:
class Mammal(Animal):
    pass
class Bird(Animal):
    pass

# 上面两类又可以细分各种动物类:
class Dog(Mammal):
    pass
class Bat(Mammal):
    pass
class Parrot(Bird):
    pass
class Ostrich(Bird):
    pass

# 上面的各种动物也可以按 地上跑的 和 天上飞的分类:
class Runnable(object):
    def run(self):
        print('Running...')

class Flyable(object):
    def fly(self):
        print('Flying...')

# 细分的动物可以继承多个类:
class Dog(Mammal, Runnable):
    pass
class Bat(Mammal, Flyable):
    pass

枚举类

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较。可以枚举出该类。

from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

for name, member in Month.__members__.items():
    print(name, '=>', member, ',', member.value)

print('--------------------------------------')

from enum import Enum, unique

@unique
class Weekday(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

day1 = Weekday.Mon

print('day1 =', day1)
print('Weekday.Tue =', Weekday.Tue)
print('Weekday[\'Tue\'] =', Weekday['Tue'])
print('Weekday.Tue.value =', Weekday.Tue.value)
print('day1 == Weekday.Mon ?', day1 == Weekday.Mon)
print('day1 == Weekday.Tue ?', day1 == Weekday.Tue)
print('day1 == Weekday(1) ?', day1 == Weekday(1))

print('--------------------------------------')

for name, member in Weekday.__members__.items():
    print(name, '=>', member, ',', member.value)

文件读写

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 文件读取

# 文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。
# 所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来实现:
try:
    f = open('/Users/xxx/Desktop/sqltest.txt', 'r')  #r 为read
    print(f.read())
finally:
    if f:
        f.close()

# 这么写太繁琐,Python引入了with语句来自动帮我们调用close()方法
with open('/Users/xxx/Desktop/sqltest.txt', 'r') as f:
    print(f.read())

# 如果文件很小,read()一次性读取最方便;如果不能确定文件大小,反复调用read(size)比较保险,
# 但一次次调用繁琐,于是可以调用下面两种:
# readline()可以每次读取一行内容,readlines()一次读取所有内容并按行返回list。
with open('/Users/xxx/Desktop/sqltest.txt', 'r') as f:
    print(f.read())
    for line in f.readlines():
        print(line.strip()) # 把末尾的'\n'删掉

# 二进制文件读取
f = open('/Users/michael/test.jpg', 'rb') #读取二进制文件(read bytes),比如图片、视频等,用 rb 模式打开
print(f.read())

# 字符编码
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk') #gbk编码
print(f.read())

# 写文件
# case1:
f = open('/Users/michael/test.txt', 'w')
f.write('hello world!')
f.close
# case2:
with open('/Users/michael/test.txt', 'w') as f:
    f.write('hello world!')

StringIO_BytesIO

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# StringIO 在内存中读写str。
from io import StringIO
f = StringIO()
f.write('hello')
f.write(' ')
f.write('world!')
print(f.getvalue())

print('----------------------')

from io import StringIO
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
    s = f.readline()
    if s == '':
        break
    print(s.strip())
print('----------------------')

# StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue())

from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
print(f.read())

操作文件和目录

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 在操作系统中对文件的操作可以直接使用cp、dir等系统命令完成。
# Python中内置的 os 模块也可以直接调用操作系统提供的接口函数。

import os
print(os.name) # 输出系统结果, nt 代表windows系统, posix 代表linux/unix/macos
#print(os.uname())  # 输出详细的系统信息(只针对于 非 windows系统,windows会报错)

# 输出环境变量
import os
print(os.environ)  # 输出环境变量

# 输出指定环境变量的值
print(os.environ.get('PATH'))  # 输出环境变量的路径


# 查看当前目录的绝对路径
print(os.path.abspath('.'))

# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来
print(os.path.join('/Users/xxx', '111'))
# windows下会显示 /Users/xxx\111 ,但不影响生成目录
# linux下会显示  /Users/xxx/111

# 在某个路径下新建一个新目录
print(os.mkdir('/Users/xxx/111'))

# 删除该新增目录
print(os.rmdir('/Users/xxx/111'))

# 目录拆分
print(os.path.split('/Users/xxx/111'))
# 这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名

# os.path.splitext() 可以得到文件的扩展名
print(os.path.splitext('/Users/xxx/111/test.txt'))

#### 注: os.path.join()、os.path.split()、os.path.splitext(),合并、拆分不需要这些文件、
#### 文件夹真是存在,他们只对字符串进行操作。


# 文件重命名
print(os.rename('/Users/xxx/111/test.txt', '/Users/xxx/111/te.py'))

# 删除文件
print(os.remove('/Users/xxx/111/123.txt'))

# 创建文件可以结合前面的文件读写
with open('/users/xxx/111/123.txt', 'w') as f:
    f.write('hello world')

# 复制文件
# 虽然 os 模块没有复制文件的函数,但 shutil模块中有,它可以看作是 os模块的补充模块


# 过滤文件
# 输出当前目录下的文件夹
import os
L = [x for x in os.listdir('.') if os.path.isdir(x)]
print(L)

# 输出当前目录下的py文件
M = [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] == '.py']
print(M)

代码实现dir-l功能

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from datetime import datetime
import os

pwd = os.path.abspath('.')

print('      Size    Last Modified  Name')
print('------------------------------------------------------------')

for f in os.listdir(pwd):
    fsize = os.path.getsize(f)
    mtime = datetime.fromtimestamp(os.path.getmtime(f)).strftime('%Y-%m-%d %H:%M')
    flag = '/' if os.path.isdir(f) else ''
    print('%10d  %s  %s%s' % (fsize, mtime, f, flag))

序列化_pickle模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 序列化:
# Python中叫pickling。把变量从内存中变成可存储或传输的过程称之为序列化,如把内存中的字符字符串以二进制格式存储在硬盘上。

# 反序列化:
# Python中叫unpickling。反过来,把变量存储起来的内容从序列化的对象重新读到内存里称之为反序列化。

# 将一个对象序列化并写入文件:
# 1.将对象序列化:
import pickle
d = dict(name='Bob', age=20, score=80)
print(pickle.dumps(d))  # pickle.dumps() 方法将任意对象序列化成一个bytes

print('---------------------------')

# 2.写入文件(新建文件dump.txt)
f = open('dump.txt', 'wb')
pickle.dump(d, f)
f.close()

print('---------------------------')

# 将对象反序列化,从磁盘读取到内存
f = open('dump.txt', 'rb')
d = pickle.load(f)
f.close()
print(d)

JSON

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,
# 但更好的方法是序列化为JSON。
# JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

# json标准规定编码为 utf-8

# dumps()方法返回一个str,内容是标准json。类似dump()方法可以直接把json写入一个file-likes Object
import json
import pickle
d = dict(name='Bob', age=20, score=88)
print(json.dumps(d))

# 把json反序列化为Python对象,用loads()或者load()
# 前者把json字符串反序列化,后者从file-like Object中读取字符串并反序列化
json_str = '{"age":20, "score":88, "name":"Bob"}'
print(json.loads(json_str))

多进程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# unix/linux操作系统提供了一个 fork() 函数,
# 通过系统调用创建一个与原来进程几乎完全相同的进程,这个新产生的进程称为子进程。
# 只需要调用getppid()就可以拿到父进程的ID。
# 子进程用getpid()查看PID。

import os
print('Process (%s) start...' % os.getpid())

# 以下在linux/unix/macos下执行,因为windows没有fork调用
'''
if pid == 0:
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
'''

# multiprocessing:python多进程模块
from multiprocessing import Process
import os

# 子进程执行的代码
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('child process will start.')
    p.start()
    p.join()
    print('child process end.')
# join()方法 用于将序列中的元素以指定的字符连接生成一个新的字符串。


# Pool:进程池。用于要启用大量子进程时,批量创建子进程。
from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random()*3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end-start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i, ))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')


# 子进程
# subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出。
import subprocess

print('$ nslookup www.python.org') # 打印出内容,为显示好看,无实际作用。
r = subprocess.call(['nslookup', 'www.python.org'])
print('Exit code:', r)


import subprocess

print('$ nslookup')
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx\npython.org\nexit\n')
print(output.decode('gbk'))
print('Exit code:', p.returncode)


# 进程间通信
# Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。
# Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。
from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

多线程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 多任务可以由多进程完成,也可由一个进程的多个线程完成。
# Python标准库提供 _thread(低级模块) 和 threading(高级模块) 两个模块进行多线程处理。

import time, threading

# 新线程执行的代码:
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n<5:
        n = n+1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)


# Lock
# 多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,
# 互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,
# 因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。
import time, threading

balance = 0
lock = threading.Lock()

def change_it(n):
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        # 先获取锁
        lock.acquire()
        try:
            # 更改数据
            change_it(n)
        finally:
            # 改完释放锁
            lock.release()


t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

# 注:
# 进程(Process) 比 线程(thread) 更稳定,windows下创建进程开销巨大。

正则表达式

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 正则表达式
# 正则表达式(Regular Expression,一般简写为RegEx或者RegExp),
# 也译为正规表示法、常规表示法,在计算机科学中,是指一个用来描述
# 或者匹配一系列符合某个句法规则的字符串的单个字符串。

# 用法细节见笔记“正则表达式”

# re模块
import re
print(re.match(r'^\d{3}\-\d{3,8}$', '010-12345'))
print(re.match(r'^\d{3}\-\d{3,8}$', '010 12345'))
# match()方法判断是否匹配成功,成功返回Match对象,失败返回None

print(r'a b  c'.split(' '))
print(re.split(r'\s+', 'a b  c'))

datetime模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from datetime import datetime  # 导入datetime模块中的datetime类
now = datetime.now()
print(now)

print(type(now))

# 获取指定日期和时间
from datetime import datetime
dt = datetime(2015, 4, 19, 12, 20, 00)
print(dt)

# 1970年1月1日 00:00:00 UTC+00:00时区的时刻称为 epoch time
# 当前时间就是相对于epoch time的秒数,称为timestamp
# 示例:
# epochtime = 1970-1-1 00:00:00 UTC+0:00
# timestamp = 1970-1-1 09:00:00 UTC+9:00

# datetime 转换为 timestamp
# 使用timestamp()函数
from datetime import datetime
dt = datetime(2015, 4, 19, 12, 20, 00)
print(dt.timestamp())

# timestamp 转换为 datetime
# 使用 datetime 提供的 fromtimestamp()方法
from datetime import datetime
t = 1429417200.0
print(datetime.fromtimestamp(t))

# str转换为datetime
# 很多时候用户输入的是字符串,得把str转换datetime。
# 通过datetime.strptime()实现,需要一个日期和时间的格式化字符串
from datetime import datetime
cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
print(cday)

# datetime转换为str
# 如果已经有了datetime对象,将它格式化为字符串现实给用户,就需要转换str
# 用 strftime() 实现。
from datetime import datetime
now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))

# 小结
# datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间。
# 如果要存储datetime,最佳方法是将其转换为timestamp再存储,因为timestamp的值与时区完全无关。

collections模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# collections是Python内建的一个集合模块,提供了许多有用的集合类。

# namedtuple()函数用来创建自定义 tuple对象,且规定 tuple元素的个数。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])  # 规定tuple元素为 x, y
p = Point(1, 2)
print(p.x)
print(p.y)


# deque
# 实现高效插入与删除操作的双向列表,适合于队列和栈。
# (list是线性存储,按索引访问元素很快,但插入和删除元素就很慢)
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)

# defaultdict
# 使用dict时,如果引用的Key不存在,就会抛出KeyError。
# 使用defaultdict如果Key不存在会返回一个默认值。
from collections import defaultdict
dd = defaultdict(lambda : 'N/A')
dd['key1'] = 'abc'
print(dd['key1'])  # key1存在,正常输出
print(dd['key2'])  # key2不存在,返回默认值 N/A

# OrderedDict
# 在对dict做迭代时,key是无序的。OrderedDict会保持按插入的顺序输出。
# 即 FIFO(先进先出),当容量超出限制时,先删除最早添加的Key。
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)  # 无序输出
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(od)  # 顺序输出,先入先出

# Counter
# Counter是一个简单的计数器,统计字符出现的次数。
from collections import Counter
c = Counter()
for ch in 'programming':
    c[ch] = c[ch] + 1
print(c)

base64模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import base64
print(base64.b64encode(b'testtest'))  # 编码
print(base64.b64decode(b'dGVzdHRlc3Q='))  # 解码

hashlib模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 摘要算法:
# 摘要算法又称哈希算法、散列算法。它通过一个函数,
# 把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)

# hashlib提供常见的摘要算法,如:md5,sha1.
# case1(md5):
import hashlib
md5 = hashlib.md5()
md5.update('just test'.encode('utf-8'))
print(md5.hexdigest())

# case2(sha1):
import hashlib
sha1 = hashlib.sha1()
sha1.update('just test'.encode('utf-8'))
print(sha1.hexdigest())

# 小结
# 摘要算法在很多地方都有广泛的应用。要注意 摘要算法 不是 加密算法,
# 不能用于加密(因为无法通过摘要反推明文),只能用于防篡改。
# 但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。

hmac模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# hmac模块实现标准的Hmac算法,将原始消息message加入随机的key,哈希算法生成加salt的密文。
import hmac
message = b'Hello world!'
key = b'secret'
h = hmac.new(key, message, digestmod='MD5')
print(h.hexdigest())  # 加盐的md5加密

import hashlib
message = hashlib.md5()
message.update('Hello world!'.encode('utf-8'))
print(message.hexdigest())  # 未加盐,密文结果不同

# 小结
# Python内置的hmac模块实现了标准的Hmac算法,它利用一个key对message计算“杂凑”后
# 的hash,# 使用hmac算法比标准hash算法更安全,因为针对相同的message,不同的key会
# 产生不同的hash。

itertools模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# itertools模块提供了用于操作迭代对象的函数。
# count()会创建一个无限的迭代器,将数据一直打印出来,必须按ctrl+c退出。
import itertools
natuals = itertools.count(1)
for n in natuals:
    print(n)


# cycle()会将一个序列无限重复下去,同样停不下来。
import itertools
cs = itertools.cycle('ABC')
for c in cs:
    print(c)


# repeat()可以将一个元素无限重复下去,不过其第二个参数可以控制重复次数
import itertools
ns = itertools.repeat('A', 5)
for n in ns:
    print(n)


# 无限序列虽然可以无限迭代下去,但可以用 takewhile()函数 通过条件判断来截取有限序列
import itertools
natuals = itertools.count(1)
ns = itertools.takewhile(lambda x: x<=10, natuals)  # 限定只取10及以内的数
print(list(ns))  # 输出取的数的列表


# chain()
# 把一组迭代对象串联起来,形成一个更大的迭代器
import itertools
for c in itertools.chain('ABC','XYZ'):
    print(c)  # 输出 A B C X Y Z


# groupby()
# 把迭代器中相邻的重复元素跳出来放在一起
import itertools
for key, group in itertools.groupby('AAABBBCCCAAA'):
    print(key, list(group))
# 输出:
# A ['A', 'A', 'A']
# B ['B', 'B', 'B']
# C ['C', 'C', 'C']
# A ['A', 'A', 'A']

# 上面字符必须大小写统一,如果大小写混杂,可以使用upper(),
# 其会将小写字符转变为大写字符排列,与lower()功能相反。
import itertools
for key, group in itertools.groupby('AAaBbBcCCaAA', lambda x: x.upper()):
    print(key, list(group))

contextlib模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Query(object):

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('Begin')
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            print('Error')
        else:
            print('End')

    def query(self):
        print('Query info about %s...' % self.name)

with Query('Bob') as q:
    q.query()

urllib模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# urllib提供了一系列用于操作url的功能

# get
from urllib import request

with request.urlopen('https://api.douban.com/v2/book/2129650') as f:
    data = f.read()
    print('Status:', f.status, f.reason)
    for k, v, in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', data.decode('utf-8'))
# 可以获取到http相应头和json数据
'''
Status: 200 OK
Date: Wed, 06 Dec 2017 03:51:05 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2058
Connection: close
Vary: Accept-Encoding
X-Ratelimit-Remaining2: 98
X-Ratelimit-Limit2: 100
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
Set-Cookie: bid=ernch-JwbnQ; Expires=Thu, 06-Dec-18 03:51:05 GMT; Domain=.douban.com; Path=/
X-DOUBAN-NEWBID: ernch-JwbnQ
X-DAE-Node: sindar1b
X-DAE-App: book
Server: dae
Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峰"],"pubdate":"2007","tags":[{"count":21,"name":"spring","title":"spring"},{"count":13,"name":"Java","title":"Java"},{"count":6,"name":"javaee","title":"javaee"},{"count":5,"name":"j2ee","title":"j2ee"},{"count":4,"name":"计算机","title":"计算机"},{"count":4,"name":"编程","title":"编程"},{"count":3,"name":"藏书","title":"藏书"},{"count":3,"name":"POJO","title":"POJO"}],"origin_title":"","image":"https://img3.doubanio.com\/mpic\/s2552283.jpg","binding":"平装","translator":[],"catalog":"","pages":"509","images":{"small":"https://img3.doubanio.com\/spic\/s2552283.jpg","large":"https://img3.doubanio.com\/lpic\/s2552283.jpg","medium":"https://img3.doubanio.com\/mpic\/s2552283.jpg"},"alt":"https:\/\/book.douban.com\/subject\/2129650\/","id":"2129650","publisher":"电子工业出版社","isbn10":"7121042622","isbn13":"9787121042621","title":"Spring 2.0核心技术与最佳实践","url":"https:\/\/api.douban.com\/v2\/book\/2129650","alt_title":"","author_intro":"","summary":"本书注重实践而又深入理论,由浅入深且详细介绍了Spring 2.0框架的几乎全部的内容,并重点突出2.0版本的新特性。本书将为读者展示如何应用Spring 2.0框架创建灵活高效的JavaEE应用,并提供了一个真正可直接部署的完整的Web应用程序——Live在线书店(http:\/\/www.livebookstore.net)。\n在介绍Spring框架的同时,本书还介绍了与Spring相关的大量第三方框架,涉及领域全面,实用性强。本书另一大特色是实用性强,易于上手,以实际项目为出发点,介绍项目开发中应遵循的最佳开发模式。\n本书还介绍了大量实践性极强的例子,并给出了完整的配置步骤,几乎覆盖了Spring 2.0版本的新特性。\n本书适合有一定Java基础的读者,对JavaEE开发人员特别有帮助。本书既可以作为Spring 2.0的学习指南,也可以作为实际项目开发的参考手册。","price":"59.8"}
'''

# 模拟浏览器发送请求,需要往 Request对象 添加http头信息
from urllib import request

req = request.Request('http://www.douban.com/')
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0')
with request.urlopen(req) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))


# post
# 发送一个post请求,只需把data以bytes形式传入。
# 模拟微博登陆
from urllib import request,parse

print('Login to weibo.cn...')
email = input('Email:')
passwd = input('Password:')
login_data = parse.urlencode([
    ('username', email),
    ('password', passwd),
    ('entry', 'mweibo'),
    ('client_id', ''),
    ('savestate', '1'),
    ('ec', ''),
    ('pagerefer', 'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F')
])

req = request.Request('https://passport.weibo.cn/sso/login')
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0')
req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')

with request.urlopen(req, data = login_data.encode('utf-8')) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))


# handler
# 通过一个代理 proxy 去访问网站,需要用 ProxyHandler 来处理。
from urllib import request
proxy_handler = urllib.request.ProxyHandler(['http': 'http://www.example.com:1080/'])
proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
with opener.open('http://www.example.com/login.html') as f:
    pass


# 小结
# urllib提供的功能就是利用程序去执行各种HTTP请求。如果要模拟浏览器完成特定功能,
# 需要把请求伪装成浏览器。伪装的方法是先监控浏览器发出的请求,再根据浏览器的请求
# 头来伪装,User-Agent头就是用来标识浏览器的。

XML解析

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# python解析xml,准备好三个事件函数 start_element, end_element, char_data 就可以完成。
# 示例: <a href="/">python</a>
# 会产生3个事件:
# 1.start_element事件,读取:<a href="/">;
# 2.char_data事件,读取:python;
# 3.end_element事件,读取:</a>。

from xml.parsers.expat import ParserCreate

class DefaultSaxHandler(object):
    def start_element(self, name, attrs):
        print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))

    def end_element(self, name):
        print('sax:end_element: %s' % name)

    def char_data(self, text):
        print('sax:char_data: %s' % text)

xml = r'''<?xml version="1.0"?>
<ol>
    <li><a href="/python">Python</a></li>
    <li><a href="/ruby">Ruby</a></li>
</ol>
'''

handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)

HTMLParser模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from html.parser import HTMLParser
from html.entities import name2codepoint

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print('<%s>' % tag)

    def handle_endtag(self, tag):
        print('</%s>' % tag)

    def handle_startendtag(self, tag, attrs):
        print('<%s/>' % tag)

    def handle_data(self, data):
        print(data)

    def handle_comment(self, data):
        print('<!--', data, '-->')

    def handle_entityref(self, name):
        print('&%s;' % name)

    def handle_charref(self, name):
        print('&#%s;' % name)

parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
    <p>Some <a href=\"#\">html</a> HTML&nbsp;tutorial...<br>END</p>
</body></html>''')

# feed()方法可以多次调用,也就是不一定一次把整个HTML字符串都塞进去,
# 可以一部分一部分塞进去。

pillow模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from PIL import Image
im = Image.open('101010.jpg')
w, h = im.size
print('Original image size: %sx%s' % (w, h))  # 输出原始图像大小
im.thumbnail((w//2, h//2))
print('Resize image to: %sx%s' % (w//2, h//2))  # 输出的图片宽高缩小一半
im.save('thumbnail.jpg', 'jpeg')

requests模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# requests
# python内置的urllib模块用于访问网络资源,但用起来麻烦,缺少很多实用的高级功能。
# requests处理url更方便。

#get
import requests
r = requests.get('https://www.douban.com/')
print(r.status_code)  # 输出页面状态码 200
print(r.text)  # 输出内容

# 对于带参数的url,传入一个dict作为params参数
import requests
r = requests.get('https://www.douban.com/search', params={'q':'python', 'cat':'1001'})
print(r.url)
# 此代码实际请求的url是 https://www.douban.com/search?q=python&cat=1001


# requests自动检测编码,可以使用 encoding属性查看:
print(r.encoding)

# content 获取响应内容(不管是文本还是二进制内容均以二进制获取)
print(r.content)

# requests方便在于特定类型的响应,如 JSON,可直接获取
r = requests.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=json')
print(r.json())

# 传入 HTTP Header 时,可加入 dict 添加headers 参数
r = requests.get('https://www.douban.com/', headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})
print(r.text)   # 以文本内容获取

# post
import requests
r = requests.post('https://accounts.douban.com/login',data={'form_email': 'abc@example.com', 'form_password': '123456'})
print(r.status_code)
print(r.text)

# requests 默认使用 application/x-www-form-urlencoded 对POST数据编码
# 如果要传递json数据,可直接传入json参数
params = {'key':'value'}
r = requests.post(url, json=params)  # 替换url和params数据

# requests 还可进行更复杂的编码格式(如:二进制),文件上传
import requests
upload_files = {'file':open('test.xls', 'rb')}
r = requests.post(url, file=upload_files)

# 同理,把 requests.get()、requests.post() 替换为 put、delete,也可进行该方式请求。

# requests 获取响应信息
print(r.headers)  # 获取http头信息
print(r.status_code)  # 获取状态码
print(r.text)  # 获取页面内容

# cookie
# requests 对 cookie 做了特殊处理,是我们不必解析cookie就可以轻松获取cookie
print(r.cookies)
# 如果要在请求中传入cookie,和post一样,使用dict传入cookie参数
cookie_params = {'token':12345, 'status':'abc', 'session':'DWEHDWLLKSNDQ2SD2H4'}

# 指定超时时间
r = requests.get('url', timeout=2.5) # 2.5秒超时

chardet模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# chardet 用于监测编码
import chardet
print(chardet.detect(b'hello world!'))
# 结果:{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
# confidence 表示概率,1.0 代表100%


# 检测GBK编码的中文:
data = '离离原上草,一岁一枯荣'.encode('gbk')
print(chardet.detect(data))
# 结果:{'encoding': 'GB2312', 'confidence': 0.7407407407407407, 'language': 'Chinese'}

# 监测utf-8编码的中文:
data = '离离原上草,一岁一枯荣'.encode('utf-8')
print(chardet.detect(data))
# 结果:{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

# 检测日文
data = '最新の主要ニュース'.encode('euc-jp')
print(chardet.detect(data))
# 结果:{'encoding': 'EUC-JP', 'confidence': 0.99, 'language': 'Japanese'}

psutil模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# psutil:process and system utilities, 进程和系统实用工具。
# 自动化运维使用普遍。

import psutil
print(psutil.cpu_count())  # 获取CPU逻辑数量
# 结果:4
print(psutil.cpu_count(logical=False))  # CPU物理核心
# 结果:2
# 因为我的电脑是双核四线程的。

# 统计cpu的用户/系统/空闲时间
print(psutil.cpu_times())


# 实现类似 top 命令的cpu使用率,每秒刷新一次,累计10次:
'''for x in range(10):
    print(psutil.cpu_percent(interval=1, percpu=True))
'''
print('------------------------------')

# 获取内存信息
print(psutil.virtual_memory())  # 获取物理内存信息
# svmem(total=8467226624, available=4421910528, percent=47.8, used=4045316096, free=4421910528)
# 总内存8G,可用4G多,已用占比47.8%,已使用4G少一点,空余4G多=前面的可用数额
print(psutil.swap_memory())  # 获取交换分区信息
# sswap(total=13087117312, used=5167869952, free=7919247360, percent=39.5, sin=0, sout=0)

print('------------------------------')

# 获取磁盘信息
print(psutil.disk_partitions())  # 获取磁盘分区信息
print(psutil.disk_usage('/'))  # 磁盘使用情况
print(psutil.disk_io_counters())  # 磁盘IO,输入输出吞吐量

print('------------------------------')

# 获取网络信息
print(psutil.net_io_counters())  # 获取网络读写 字节/包 的个数

print('------------------------------')

# 获取网络接口
print(psutil.net_if_addrs())

print('------------------------------')

# 获取接口状态
print(psutil.net_if_stats())

print('------------------------------')

# 获取当前网络连接信息
print(psutil.net_connections())

print('------------------------------')

# 获取进程信息
'''
>>> psutil.pids() # 所有进程ID
[3865, 3864, 3863, 3856, 3855, 3853, 3776, ..., 45, 44, 1, 0]
>>> p = psutil.Process(3776) # 获取指定进程ID=3776,其实就是当前Python交互环境
>>> p.name() # 进程名称
'python3.6'
>>> p.exe() # 进程exe路径
'/Users/michael/anaconda3/bin/python3.6'
>>> p.cwd() # 进程工作目录
'/Users/michael'
>>> p.cmdline() # 进程启动的命令行
['python3']
>>> p.ppid() # 父进程ID
3765
>>> p.parent() # 父进程
<psutil.Process(pid=3765, name='bash') at 4503144040>
>>> p.children() # 子进程列表
[]
>>> p.status() # 进程状态
'running'
>>> p.username() # 进程用户名
'michael'
>>> p.create_time() # 进程创建时间
1511052731.120333
>>> p.terminal() # 进程终端
'/dev/ttys002'
>>> p.cpu_times() # 进程使用的CPU时间
pcputimes(user=0.081150144, system=0.053269812, children_user=0.0, children_system=0.0)
>>> p.memory_info() # 进程使用的内存
pmem(rss=8310784, vms=2481725440, pfaults=3207, pageins=18)
>>> p.open_files() # 进程打开的文件
[]
>>> p.connections() # 进程相关网络连接
[]
>>> p.num_threads() # 进程的线程数量
1
>>> p.threads() # 所有线程信息
[pthread(id=1, user_time=0.090318, system_time=0.062736)]
>>> p.environ() # 进程环境变量
{'SHELL': '/bin/bash', 'PATH': '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:...', 'PWD': '/Users/michael', 'LANG': 'zh_CN.UTF-8', ...}
>>> p.terminate() # 结束进程
Terminated: 15 <-- 自己把自己结束了
'''

print('------------------------------')

# 模拟ps命令效果
print(psutil.test())

TCP编程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# TCP 是可靠的,面向连接的协议。

# Socket 是网络编程的一个抽象概念,意为“孔、插座”,用于两个客户端之间的网络连接,
# 打开一个socket需要指定目标机器的IP和端口。


### 客户端
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # AF_INET指定使用ipv4,如果是ipv6使用AF_INET6
s.connect(('www.sina.com.cn', 80))  # socket链接 参数是一个 tuple,包含地址、端口号

# 向新浪服务器发送请求
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')

# 接收服务器返回数据
buffer = []
while True:
    d = s.recv(1024)  # recv(max)方法,一次最多接收指定的字节数
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
s.close()  # close()方法关闭Socket,网络通信结束。

# 输出http头信息
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))

# 把接收的内容数据写入文件
with open('sina.html', 'wb') as f:
    f.write(html)


### 服务器
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定监听端口
s.bind(('127.0.0.1', 9999))

# 调用listen()开始监听,并设置最大等待连接数量,不是连接的客户端数量
s.listen(5)
print('Waiting for connection...')

# 服务器通过永久循环来接受来自客户端的连接
while True:
    # 接受一个新连接:
    sock, addr = s.accept()
    # 创建新线程来处理TCP连接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

# 每次连接都要创建新的线程或进程
def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)


# 客户端与上面服务器通信
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
s.connect(('127.0.0.1', 9999))
# 接收欢迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 发送数据:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

UDP编程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# UDP 是面向无连接的协议。

### 服务端
import socket
s = socket.socket(socket.AF_INET, sock.SOCK_DGRAM)  # SOCK_DGRAM 指定Socket类型为UDP
# 绑定端口
s.bind(('127.0.0.1'. 9999))

# UDP与TCP相比,不需要调用listen(),直接接收客户端数据
print('Bind UDP on 9999..')
while True:
    # 接收数据
    data, addr = s.recvfrom(1024)  # recvfrom()返回数据和客户端地址、端口
    print('Received from %s: %s.' % addr)
    s.sendto(b'Hello, %s!' % data, addr)
    # 服务器收到后通过 sendto() 把数据通过UDP发送给客户端

### 客户端
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 发送数据
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收数据
    print(s.recv(1024).decode('utf-8'))
s.close()

SMTP发送邮件

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Python的 smtplib 和 email 两个模块对邮件支持。
# email 负责构造邮件,smtplib 负责发送邮件

from email.mime.text import MIMEText
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')

# 输入邮箱地址和口令
from_addr = input('From:')
password = input('Password:')
# 输入收件人地址
to_addr = input('To:')
# 输入SMTP服务器地址
smtp_server = input('SMTP server:')

import smtplib
server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)  # 打印出和SMTP服务器交互的所有信息
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

# 完整邮件:
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

from_addr = input('From:')
password = input('Password:')
to_addr = input('To:')
smtp_server = input('SMTP server:')

msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr)
msg['To'] = _format_addr('管理员 <%s>' % to_addr)
msg['Subject'] = Header('来自SMTP的问候。。。', 'utf-8').encode()

server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

POP3收取邮件

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Python内置的poplib模块,用于实现邮件接收。

# 收取邮件分为两步:
# 1.用 poplib 把邮件原始文本下载到本地;
# 2.用 email 解析原始文本,还原邮件对象。

from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
import poplib

# 解析邮件
# 打印出 message 对象的层次结构
# indent用于缩进显示
def print_info(msg, indent=0):
    if indent == 0:
        for header in ['From', 'To', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header=='Subject':
                    value = decode_str(value)
                else:
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = u'%s<%s>' % (name, addr)
            print('%s%s: %s' % (' ' * indent, header, value))
    if(msg.is_multipart()):
        parts = msg.get_payload()
        for n, part in enumerate(parts):
            print('%spart %s' % (' ' * indent, n))
            print('%s----------------' % (' ' * indent))
            print_info(part, indent + 1)
    else:
        content_type = msg.get_content_type()
        if content_type=='text/plain' or content_type=='text/html':
            content = msg.get_payload(decode=True)
            charset = guess_charset(msg)
            if charset:
                content = content.decode(charset)
            print('%sText: %s' % (' ' * indent, content + '...'))
        else:
            print('%sAttachment: %s' % (' ' * indent, content_type))
# 邮件中的名字都是编码后的str,要正常显示,必须解码decode
def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value
# 邮件内容也要检测编码
def guess_charset(msg):
    charset = msg.get_charset()
    if charset is None:
        content_type = msg.get('Content-Type', '').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos + 8:].strip()
    return charset

# 输入邮件地址、口令和POP3服务器地址
email = input('Email:')
password = input('Password:')
pop3_server = input('POP3 server:')

#连接到POP3服务器
server = poplib.POP3(pop3_server)
# 打开调试信息
server.set_debuglevel(1)
# 打印POP3服务器的欢迎文字
print(server.getwelcome().decode('utf-8'))

# 身份认证
server.user(email)
server.pass_(password)

# stat()返回邮件数量和占用空间
print('Messages: %s. Size: %s' % server.stat())
# list()返回所有邮件编号
resp, mails, octets = server.list()
# 查看返回列表
print(mails)

# 获取最新一封邮件
index = len(mails)
resp, lines, octets = server.retr(index)

# lines存储了邮件的原始文本的每一行,可以获得整个邮件原始文本
msg_content = b'\r\n'.join(lines).decode('utf-8')
# 稍后解析出邮件
msg = Parser().parsestr(msg_content)
print_info(msg)
# 关闭连接
server.quit()

使用SQLite

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# SQLite是一种嵌入式数据库,数据库就是一个文件

# 导入sqlite数据库
import sqlite3
# 连接test.db数据库,如果不存在会自动创建
conn = sqlite3.connect('test.db')
# 创建Cursor,操作数据库通过Cursor执行SQL语句
cursor = conn.cursor()
# 执行创建表的命令
cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
# 插入一条记录
cursor.execute('insert into user (id, name) values (\'1\', \'Michael\')')
# 通过rowcount获得插入的行数
print(cursor.rowcount)
# 关闭Cursor
cursor.close()
# 提交事务
conn.commit()
# 关闭连接
conn.close()

# 查询
conn = sqlite3.connect('test.db')
cursor = conn.cursor()
# 执行查询语句
cursor.execute('select * from user where id?', ('1',))
# 获得查询结果集
values = cursor.fetchall()
print(values)
cursor.close()
conn.close()

使用MySQL

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 安装mysql驱动
# pip3 install mysql-connector-python --allow-external mysql-connector-python
# pip3 install mysql-connector

import mysql.connector
# 连接数据库
conn = mysql.connector.connect(use='root', password='root', database='test')
cursor = conn.cursor()
# 创建user表
cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
# 插入一行记录,注意mysql的占位符是 %s
cursor.execute('insert into user (id, name) values (%s, %s)', ['1', 'Michael'])
print(cursor.rowcount)
# 提交事务
conn.commit()
cursor.close()
# 查询
cursor = conn.cursor()
cursor.execute('select * from user where id = %s', ('1',))
values = cursor.fetchall()
print(values)
# 关闭cursor和connection
cursor.close()
conn.close()

使用SQLAIchemy

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# SQLAlchemy 是python 操作数据库的一个库。
# pip3 install sqlalchemy

from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 创建对象的基类
Base = declarative_base()
# 定义user对象
class User(Base):
    # 表的名字
    __tablename__ = 'user'

    # 表的结构
    id = Column(String(20), primary_key=True)
    name = Column(String(20))

# 初始化数据库连接
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 创建DBSession类型
DBSession = sessionmaker(bind=engine)

# ORM(Object Relational Mapping,对象关系映射)框架的作用就是把数据库表的一行记录
# 与一个对象互相做自动转换。

WSGI接口

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# WSGI:Web Server Gateway Interface, web服务网关接口(接口规范)
# 1.浏览器发送一个HTTP请求;
# 2.服务器收到请求,生成一个HTML文档;
# 3.服务器把HTML文档作为HTTP响应的Body发送给浏览器;
# 4.浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。


# hello.py
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']

# server.py
from wsgiref.simple_server import make_server
from hello import application  # 导入 hello.py 定义的application()

httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
httpd.serve_forever()

# hello.py 与 server.py 在同一目录下,运行 server.py,
# 浏览器 输入 http://localhost:8000,就能显示处 hello.py 的内容。
posted @ 2019-02-13 18:55  素时听风  阅读(209)  评论(0编辑  收藏  举报