python常用模块

模块

概念

  • 概念:
    1、在计算机程序开发过程中,随着代码越写越多,在一个文件中会越来越长,越来越难以维护
    2、为了编写可维护性的代码,我们会把很多函数进行分组,分别放到不同的文件里。这样,每个文件包含的代码就相对较少,大多数编程语言都是采用这种组织代码的方式
    3、python中一个.py文件就称为一个模块(module)
  • 优点
    1、提高了代码的可维护性
    2、提高了代码的复用度,编写代码可以不必从零开始,当一个模块编写完成,就可以被其他的地方引用
    3、引用其他模块,python内置许多模块且还有许多第三方模块
    4、避免函数名和变量名的冲突

使用标准库中的模块

#使用import语句引入标准库中的模块
import sys
# 包含命令行参数的列表
print(sys.argv)
# 自动查找所需模块的路径列表
print(sys.path)
  • 常用标准库
标准库 说明
builtins 内建函数默认加载
math 数学库
random 生成随机数
time 时间
datetime 日期和时间
calendar 日历
hashlib 加密算法
copy 拷贝
functools 常用的工具
os 操作系统接口
re 字符串正则匹配
sys Python自身的运行环境
multiprocessing 多进程
threading 多线程
json 编码和解码 JSON 对象
logging 记录日志,调试
  • 模块的搜索路径
    当导入一个模块时,解释器先在当前包中查找模块,若找不到,然后在内置的built-in模块中查找,找不到则按sys.path给定的路径找对应的模块文件(模块名.py)
    • python标准库
    • 第三方库
    • 自定义库

使用自定义模块

  • import语句

    • 作用:导入整个模块
    • 格式:import module1[, module2[, module3],……]
    • 注意:
      1、一般一个import只引入一个模块
      import time
      import sys
      import random
      2、一个模块只会被导入一次,不管你执行了多少次import,有效的防止模块被一次次的执行导入
      import time
      import time
      使用模块中的内容:module.方法/变量/类
  • from……import语句

    • 作用:从模块中导入指定内容
    • 格式:from module_name import name1[, name2,……]
    • 注意:导入没有的对象会报错
  • from……import 星语句

    • 作用:把模块中的所有内容全部导入当前命名空间
    • 格式:from module_name import *
    • 注意:不应该过多的使用,很可能会造成变量的冲突
  • from 包.模块 import 对象 as 别名

    • 作用:给导入的模块的对象起别名

__ name__属性

  • 概念:每个模块都有一个__name__属性,当其值为"main"时,表名该模块自身在运行,否则是被当做模块引入,此时值为模块的名

  • 作用:模块就是一个可执行的python文件,一个模块被另一个模块引入,想让模块中的某一段程序不执行,我们可以使用__name__属性来隐藏该段代码,当自身执行时在执行该段代码

  • 以后一般程序的起始位置都是从__name__=="main"处开始

第三方模块

物理环境安装步骤:
1.在终端中输入命令:pip -V 【检查版本,这个步骤在安装Python环境的时候如果勾选了Add path选项,则已自动安装】

2.安装第三方模块:pip install pillow 【pillow为一个图形处理的第三方模块,需要联网下载】

如果此步出错,则执行命令  python -m pip install --upgrade 

https://pillow.readthedocs.io/en/latest/reference/ImageDraw.html#functions

3,.如果不使用第三方模块,则可以执行命令:pip uninstall pillow ,卸载第三方模块

  • 思考:如果不同的人编写的模块同名,怎么办?
  • 解决:为了避免模块名冲突,python引入了按目录来组织模块的方法,称为包
  • 特点:引入包以后,只要顶层的包不予别人冲突,那么所有的模块都不会冲突
  • 注意:每个包下面都会有一个名为__init__.py的文件,默认什么内容都没有(表示该目录是个包),作用为导出包里的内容

time模块

  • UTC(世界协调时间):格林尼治时间,世界标准时间,在中国是UTC+8
  • DST(夏令时):是一种为了节约能源而人为规定地方时间的制度,一般在天亮早的夏季将时间提前一小时
  • 时间的表示形式
    • 1、时间戳形式
      以整数或者浮点数标识的一个以秒为单位的时间间隔,这个时间的基础值是1970年1月1日零时
    • 2、元组形式
      一种python的数据结构,这个元组有9个整型元素,分别代表不同的时间含义
      year
      month(1-12)
      day(1-31)
      hours(0-23)
      minutes(0-59)
      seconds(0-59)
      weekday(0-6,0表示星期一)
      Julian day(1-366):标识当前日期在本年是第几天
      DST flag(-1 or 0 or 1):夏令时格式,0表示正常,1表示为夏令时格式,-1表示根据当前的日期格式来判定
    • 3、格式化字符串形式
      python常用模块_第1张图片

常用方法

# time()
# 返回当前时间的时间戳
t1 = time.time()
print(t1)
#1563612216.2735271

#gmtime()
#将时间戳格式转为UTC时间元组格式,接收一个浮点型时间戳作为参数,如果不传默认使用当前时间戳
t2 = time.gmtime()
print(t2)	#time.struct_time(tm_year=2019, tm_mon=7, tm_mday=20, tm_hour=8, tm_min=43, tm_sec=36, tm_wday=5, tm_yday=201, tm_isdst=0)

print(type(t2))	#


# localtime()
# 将时间戳转为本地时间元组格式,接收一个浮点型时间戳作为参数,如果不传默认使用当前时间戳
t3 = time.localtime()
print(t3)	#time.struct_time(tm_year=2019, tm_mon=7, tm_mday=20, tm_hour=16, tm_min=43, tm_sec=36, tm_wday=5, tm_yday=201, tm_isdst=0)
print(type(t3))	#


#mktime()
#将本地时间元组转为时间戳,接收一个时间元组
t4 = time.mktime(t3)
print(t4)	#1563612216.0
print(type(t4))	#

#asctime()
# 将时间元组格式转为字符串形式,接收一个时间元组,默认值为localtime的时间元组
t5 = time.asctime(t3)
print(t5)	#Sat Jul 20 16:43:36 2019
print(type(t5))	#

#ctime()
#将时间戳转为字符串,接收一个时间戳,默认为当前时间戳
t6 = time.ctime()
print(t6)	#Sat Jul 20 16:43:36 2019
#
print(type(t6))

#strftime()
#将时间元组以指定的格式转为字符串形式,接收一个字符串格式化串,时间元组(默认本地时间元组)
t7 = time.strftime("%Y-%m-%d %X", t3)
print(t7)	#2019-07-20 16:43:36


#strptime()
#将指定格式的时间字符串解析为时间元组,是strftime逆过程,两个参数要对应
t8 = time.strptime("2018-02-23 12:34:45", "%Y-%m-%d %X")
print(t8)	#time.struct_time(tm_year=2018, tm_mon=2, tm_mday=23, tm_hour=12, tm_min=34, tm_sec=45, tm_wday=4, tm_yday=54, tm_isdst=-1)


#sleep()
# 延迟一个时间段,接收整型或者浮点型,以秒为单位

#clock()
# 返回当前程序执行的时间,在Unix、linux系统中始终返回全部运行时间,而windows从第二次开始都是以第一次调用此函数的时间戳为基准,而不是以程序开始的时间戳为基准

# tzset()
# 改变时区

python常用模块_第2张图片

datetime模块

datetime 比 time 模块高级了不少,可以理解为datetime基于time进行了封装,提供了更实用的接口函数

模块中的类:
time 只关注时间
date 只关注日期
datetime 同时关注日期和时间
timedelta 主要用于计算时间跨度
tzinfo 时区相关

#获取当前时间
t1 = datetime.datetime.now()
print(t1)
#2019-07-20 17:00:50.372674
#
print(type(t1))

#获取指定时间
t2 = datetime.datetime(2001, 10, 1, 8, 8, 8, 0)
print(t2)
#2001-10-01 08:08:08
<class 'datetime.datetime'>
print(type(t2))

# 将时间转为字符串
t3 = t2.strftime("%y-%m-%d %X")
print(t3)
#01-10-01 08:08:08
#
print(type(t3))

#将格式化的字符串转为datetime对象
t4 = datetime.datetime.strptime(t3, "%y-%m-%d %X")
print(t4)
print(type(t4))
#2001-10-01 08:08:08
#


#计算时间差
t5 = datetime.datetime(2001, 10, 1, 8, 8, 8, 0)
t6 = datetime.datetime(2001, 9, 29, 7, 8, 1, 0)
t7 = t5 - t6
print(t7)
print(type(t7))
#2 days, 1:00:07
#
#间隔天数
print(t7.days)
#2
# 除去间隔天数以外的间隔秒数
print(t7.seconds)
#3607


python常用模块_第3张图片

calendar模块

#日历模块
import calendar

#返回指定年的某月
print(calendar.month(2019,3))
'''
     March 2019
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
'''
#返回指定年的日历
print(calendar.calendar(2018))	

#判断某一年是否是闰年
print(calendar.isleap(2001))	#False
print(calendar.leapdays(2000,2020))	#5

#返回某个月的weekday的第一天和这个月的所有天数
print(calendar.monthrange(2019, 8))	#(3, 31)
# 返回某个月以一周为周期的元素序列
print(calendar.monthcalendar(2019, 8))	#[[0, 0, 0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17, 18], [19, 20, 21, 22, 23, 24, 25], [26, 27, 28, 29, 30, 31, 0]]
print(type(calendar.monthcalendar(2019, 8)))
#当前日期表示的星期数
print(calendar.weekday(2019,7,20))	#5
		

uuid模块

  • 概述:
    是128位的全局唯一标识符,通常由32字节的字符串表示,它可以保证时间和空间的唯一性,页称为GUID

  • 原理:
    通过mac地址、时间戳、命名空间、随机数、伪随机数来保证产生的id的唯一性

  • 作用:
    随机生成字符串,当成账号、token、订单号等使用(要求不相同字符串)

  • 算法:
    1、uuid1()基于时间戳
    由mac地址、当前时间戳、随机数字,可以保证全球范围内的唯一性,但是用于mac地址的使用时带来安全问题,局域网中可以使用ip代替mac
    2、uuid2()基于分布式计算环境DCE
    算法和uuid1相同,不同的是把时间戳的前四位换位POSIX的UID,实际当中甚少使用,注意,python中没有这个函数
    3、uuid3()基于名字和MD5散列值
    通过计算名字和命名空间的MD5散列值得到的,保证了同一命名空间中不同名字的唯一性,和不同命名空间的唯一性,但同一命名空间的相同名字生成相同的uuid
    4、uuid4()基于随机数
    由伪随机数得到的,有一定的重复概率,这个概率是可以计算出来的
    5、uuid5()基于名字和SAH1散列值
    算法和uuid3相同,不同的是使用SHA1算法

  • 使用经验:
    1、python中没有基于DCE的,所以uuid2可以忽略
    2、uuid4存在概率性重复,由于无映射性,最好不用
    3、如果在全局的分布式环境下,最好使用uuid1()
    4、如果名字的唯一性要求,最好使用uuid3或uuid5

  • 简单使用

print(uuid.uuid1())
print(uuid.uuid4())
print(uuid.uuid3(uuid.NAMESPACE_DNS, "tom"))
print(uuid.uuid5(uuid.NAMESPACE_DNS, "tom"))
print(uuid.uuid5(uuid.NAMESPACE_DNS, "tom"))
#
c9abcfa2-aacf-11e9-a290-f4b7e20ea694
0e196870-d353-4d02-a8cc-69d240c90e84
f973ba0f-cf78-3bb8-ade3-4c7b492d9e55
b73c6264-f580-56d3-9a04-299b8616690e
b73c6264-f580-56d3-9a04-299b8616690e

collections模块

collections是python内建的一个集合模块,提供了许多有用的集合类(类型)

namedtuple

命名元组,本质是一个函数,用它来创建一个自定义的tuple对象
规定tuple元素的个数,并可以用属性而不是索引来引用tuple中的元素
使用namedtuple定义了一个新的数据类型

#d定义一个新的数据类型,
'''
参数1:类型名字
参数2:列表,给创建出来的命名元组类型的数据的元素起名字
'''
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p2 = Point(y=1, x=2)  # p2 = Point(1, 2)
print(p2, type(p2))
#Point(x=2, y=1) 
print(isinstance(p2, Point))
#True
print(isinstance(p2, tuple))
#True

#获取命名元组中的元素
print(p2[0], p2[1])	# 2 1
print(p2.x, p2.y)	# 2 1

deque

  • 使用list存储数据,按索引访问元素,但是插入和删除元素会根据元素的个数增多而降低效率,因为list是显性存储,数据量大插入和删除效率会降低,而且list属于非线程安全的数据类型

  • deque就是为了高效实现插入和删除操作,且是线程安全的数据类型,作为双向列表,适用于队列和栈

  • 简单使用

from collections import deque
deq = deque([1,2,3,4,5])
print(deq)  #deque([1, 2, 3, 4, 5])
deq.append(6)
print(deq)  #deque([1, 2, 3, 4, 5, 6])
deq.appendleft(0)
print(deq)  #deque([0, 1, 2, 3, 4, 5, 6])
print("------",deq.pop())   #------ 6
print(deq)  #deque([0, 1, 2, 3, 4, 5])
deq.popleft()   
print(deq)  #deque([1, 2, 3, 4, 5])
print(deq[3])   #4

defaultdict

使用dict时,如果引用的key不存在,会抛出KeyError的异常(若使用get()方法会得到None)。如果希望key不存在时,能得到一个默认在的值,就使用defaultdict

  • 简单使用
d2 = defaultdict(lambda :-1)
d2["a"] = 1
d2["b"] = 2
print(d2["a"])  #1
print(d2["c"])  #-1
print(d2.get("d")) #获取不到key对应的值得到None

OrderedDict

  • 使用dict时,key是无序的,对dict做迭代时无法保证key的顺序。如果需要key有顺序,就可以使用OrderDict
  • 字典key的顺序按照插入的顺序排序,OrderedDict接收一个列表,每一个键值对是列表中的一个元素,每个元素是一个元组,元祖的第一个元素为key,第二个元素为value
  • 简单使用
from collections import OrderedDict
d2 = OrderedDict([("a", 1),("c", 3),("b", 2)])
print(d2)	#OrderedDict([('a', 1), ('c', 3), ('b', 2)])
print(d2["a"])	#1
print(d2.get("b"))	#2
print("--------------")
# print(d2["d"])     #报错
print(d2.get("d"))  #None

Counter

  • 一个简单的计数器,本质上上dict的一个子类,使用中括号方式访问键,那么键不存在则获取到数字0
  • 简单使用
from collections import Counter
#变量c本质是一个字典,
a = 'hello world'
c = Counter()
c["a"] = 1
c["b"] = 2
print(c["a"])
print(c["d"])
print(c, type(c), isinstance(c, dict))	#Counter({'b': 2, 'a': 1})  True
for ch in a:
    c[ch] = c[ch] + 1
print(c)	#Counter({'l': 3, 'b': 2, 'o': 2, 'a': 1, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})

base64

  • 概述:用记事本打开图片等文件,看到的是一坨乱码,因为二进制文件包含很多无法显示的内容。所以想让记事本能处理二进制数据,需要将二进制字符串转换,base64是一种比较常见的二进制编码方式

  • 编码原理:
    一个包含64个字符的列表
    [‘A’, ‘B’, ……, ‘Z’,‘a’, ‘b’, ……, ‘z’, ‘0’, ‘1’, ……, ‘9’, ‘+’, ‘/’]

    对二进制数据进行处理,每三个字节一组,一组就是3x8=24bit,划为4组,每组正好6bit
    得到4个数字作为索引,然后查表,获得相应4个字符,就是编码后的字符串

  • 作用:适用于小段内容编码,比如数字证书签名、cookie、网页中传输的少量二进制数据

  • 如果编码的二进制不是3的倍数,怎么办?

    • 答案:base64会用\x00字节在末尾补足,在编码的时候末尾加上1个或两个等号表示补了多少字节,解码时会自动去掉
  • 简单使用

import base64
#编码
s1 = b"sunck is a good man"  #字节串,二进制的数据

'''
sun对应的编码
011100  110111  010101  101110
28      55       21      46

n 对应的编码
011011 100000 000000 000000
'''
print(base64.b64encode(s1))
s2 = b'c3VuY2sgaXMgYSBnb29kIG1hbg=='	#b'c3VuY2sgaXMgYSBnb29kIG1hbg=='
#解码
print(base64.b64decode(s2))	#b'sunck is a good man'
  • 由于标准base64编码后可能出现+和/,在url中就不能直接作为参数编码
    • 提供了urlsafe_b64encode编码函数,保证url的安全,将+和/替换成-和_,以供urlsafe_b64dencode进行url安全解码
s3 = b"sunck is a good m~"
print(base64.b64encode(s3))
print(base64.urlsafe_b64encode(s3))

s4 = b'c3VuY2sgaXMgYSBnb29kIG1-'
print(base64.urlsafe_b64decode(s4))
  • 可以自定义编码对照表中64个字符的排列顺序,这样可以自定义编码,但是通常情况下没有任何必要

hashlib模块

  • hashlib模块提供了常见的摘要算法,如MD5、SHA1

摘要算法(又称哈希算法、散列算法)

  • 原理:它通过一个函数,把任意长度的数据转为一个长度固定的数据串(通常用16进制的字符串表示)
  • MD5:最常见的摘要算法,速度快,生成的结果是128位字节,通常用32位16进制字符串表示
s1 = b"tom is a good man"
m1 = hashlib.md5()
m1.update(s1)
print(m1)
#
res1 = m1.hexdigest()
print(res1, type(res1))
#b49b5dc2b05db94179474bd4b1cefad9 

#如果数据量较大,可以分多次调用update,最后得到的结果是一样的
m2 = hashlib.md5()
m2.update(b"tom is ")
m2.update(b"a good man")
res2 = m2.hexdigest()
print(res2)
#b49b5dc2b05db94179474bd4b1cefad9

  • SHA1
  • 调用sha1与md5完全一样,SHA1的结果是160bit字节,通常用40位16进制字符串表示
s3 = b"tom is a good man"
h3 = hashlib.sha1()	
h3.update(s3)	
res3 = h3.hexdigest()
print(res3, type(res3))	#cee73cb1dcd6e85d1f714e37f9a9ce2081fb0977 
  • 更安全
    SHA256
    SHA512
    越安全的算法不仅越慢,而且摘要会越长

  • 有没有两个不同的数据通过hash运算后得到相同的摘要呢?

    • 答:有这种可能性,因为摘要算法是将无限多的数据映射到有限的集合中,如果两个数据的摘要相同,称为碰撞,可能出现,但是非常渺茫
  • 应用
    任何允许用户登录的网站都会存储用户登录的用户名和密码,那么密码一般存储的都是原密码的摘要值
    如果明文存储到数据库中,如果数据库泄露,所有用户信息都会暴露
    正确的保存口令方式不是存储明文内容,而是存储口令的摘要,当用户登录时,首先会计算用户输入的明文口令的摘要,和数据库中的对比,如果一致说明口令正确,否则一定错误

hmac

实现了hmac算法,是用一个key对数据进行“杂凑”后在进行的hash,使用hmac比hash算法更安全,不同的key产生不同的hash值

import hmac
s = b"tom is a good man"
key = b"secret"
h = hmac.new(key, s, digestmod="SHA1")
res1 = h.hexdigest()
print(res1)
#8b30502efa35ada5d128070ec73a1fcc1cba41f1

itertools模块

  • 无限迭代
import itertools
import time

#1、count(start=0, step=1)
c = itertools.count()
print(c, type(c))	#count(0) 
for i in c:
    print(i)
    time.sleep(0.5)


# 2、cycle(iterable)
# 把传入的一个序列无限重复下去
cyc = itertools.cycle("tom")    # 
print(cyc, type(cyc))
for i in cyc:
    print(i)
    time.sleep(0.5)


# 3、repeat(object[, times])
# 把一个元素无限重复下去,如果提供了第二个参数,就可以指定重复的次数
r = itertools.repeat("tom")
for i in r:
    print(i)
    time.sleep(0.5)

  • 有限迭代
import itertools
# 1、chain([iterable[, iterable, ……]])
# 把一组迭代对象串联起来,形成一个更大的迭代器
ch = itertools.chain("ABC", "abc")
# 
for i in ch:
    print(i)



#2、groupby(iterable)
# 把迭代器中相邻的重复元素挑出来放在一起
g = itertools.groupby("AAAABBBAAccdeffgHHH")
print(g,type(g))
# 
for key, value in g:
    print(key, list(value))
 
'''
A ['A', 'A', 'A', 'A']
B ['B', 'B', 'B']
A ['A', 'A']
c ['c', 'c']
d ['d']
e ['e']
f ['f', 'f']
g ['g']
H ['H', 'H', 'H']
'''

  • 排列组合
#排列
# #从n个不同的元素中取出m(m<=n)个元素按照一定的顺序排成一列,叫做从n个元素中获取m个元素的一个排列,当m==n时,这个排列称为全排列
#从n个中选m个  n!/(n-m)!
li1 = [1,2,3,4]
p1 = list(itertools.permutations(li1, 2))
#
print(p1)
print(len(p1))


#从n不同元素中,任意m(m<=n)个元素为一组,叫做从n个不同元素中取出m个元素的组合
#从n个不同元素中获取m个   n!/m!x(n-m)!
li2 = [1,2,3,4]
p2 = list(itertools.combinations(li2, 2))
print(p2)
print(len(p2))


##排列组合(笛卡尔积)
#从n个元素中获取m个元素    n^m
li3 = "qwertyu"
p3 = list(itertools.product(li3, repeat=2))
print(p3)
print(len(p3))


#暴力破解
import time
s4 = "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM"
passwds = ("".join(x) for x in itertools.product(s4, repeat=16))
for i in passwds:
    print(i)
    time.sleep(1)

pillow模块

  • 作用:处理图像
  • 安装:pip install pillow

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pilllow # 可以提高下载速度
from PIL import Image
#打开图片
im = Image.open("fengjing.jpg")
#查看图片信息
print(im.format, im.size, im.mode)
#JPEG (1920, 1200) RGB
#修改图片大小
im.thumbnail((192, 120))
#生成新图片
im.save("fengjing2.jpg", "JPEG")

# 放缩图片: 原图像缩放为128x128
im_resized = im.resize((128, 128))
#显示图片
im_resized.show()

# 旋转图片: 指定逆时针旋转的角度
img_rotate = im.rotate(45)       # 旋转之后的图片的大小并不会发生变化,旋转的留白区域会用黑色填充
img_rotate.show()

# 翻转图片:图像的翻转用 transpose()函数,直接在入参中指定变换方式即可,不仅支持上下、左右翻转;也支持逆时针90、180、270等角度的旋转,效果与rotate()相同。示例如下:

out_lr = im.transpose(Image.FLIP_LEFT_RIGHT)   # 左右翻转
out_lr.show()
out_tb = im.transpose(Image.FLIP_TOP_BOTTOM)   # 上下翻转
# out_tb.show()
# out = img.transpose(Image.ROTATE_90)    # 逆时针旋转九十度
# out = img.transpose(Image.ROTATE_180)
# out = img.transpose(Image.ROTATE_270)
# out.show()

递归

  • 递归:
    一个函数调用自身,称为递归调用。
    一个会调用自身的函数称为递归函数
  • 说明:
    1、凡是循环能干的事,递归都能干
    2、以后尽量少使用递归,递归不好写,效率低
  • 方式:
    1、写出临界条件
    2、找这一次和上一次的关系
    3、假设当前函数已经能用,调用自身计算上一次结果,在求出本次的结果
# 编写函数,实现给函数一个大于等于1的整数数字,求1+2+3+……+n的和

def my_sum2(num):
    if num == 1:
        return 1
    else:
        return my_sum2(num-1) + num

#原理
'''
my_sum2(5)
my_sum2(4) + 5
my_sum2(3) + 4 + 5
my_sum2(2) + 3 + 4 +5
my_sum2(1) + 2 + 3 + 4 + 5
1          + 2 + 3 + 4 + 5
'''
  • 递归和迭代的区别:
    递归:重复调用函数自身实现循环称为递归;
    递归实际上不断地深层调用函数,直到函数有返回才会逐层的返回,递归是用栈机制实现的,每深入一层,都要占去一块栈数据区域,因此,递归涉及到运行时的堆栈开销(参数必须压入堆栈保存,直到该层函数调用返回为止),所以有可能导致堆栈溢出的错误;但是递归编程所体现的思想正是人们追求简洁、将问题交给计算机,以及将大问题分解为相同小问题从而解决大问题的动机。

       例如:if else 调用自己,并在合适时机退出
    

迭代:利用变量的原值推出新值称为迭代,或着说迭代是函数内某段代码实现循环;
迭代大部分时候需要人为的对问题进行剖析,分析问题的规律所在,将问题转变为一次次的迭代来逼近答案。迭代不像递归那样对堆栈有一定的要求,另外一旦问题剖析完毕,就可以很容易的通过循环加以实现。迭代的效率高,但却不太容易理解,当遇到数据结构的设计时,比如图表、二叉树、网格等问题时,使用就比较困难,而是用递归就能省掉人工思考解法的过程,只需要不断的将问题分解直到返回就可以了。

     例如:for,while循环

两者关系:所有的迭代可以转换为递归,但递归不一定

定义 优点 缺点
递归 重复调用函数自身实现循环 a.用有限的循环语句实现无限集合;b.代码易读; c.大问题转化成小问题,减少了代码量。 a.递归不断调用函数,浪费空间 b.容易造成堆栈溢出
迭代 利用变量的原值推出新值; 函数内某段代码实现循环。 a.效率高,运行时间只随循环的增加而增加;b.无额外开销。 a.代码难理解;b.代码不如递归代码简洁; c.编写复杂问题时,代码逻辑不易想出
两者关系 a.递归中一定有迭代,但是迭代中不一定有递归;大部分可以相互转换。 b.相对来说,能用迭代不用递归(因为递归不断调用函数,浪费空间,容易造成堆栈溢出)

栈和队列

  • 两种数据存储格式,二者的区别:
    解:(1).队列先进先出,栈先进后出。
    (2). 对插入和删除操作的"限定"。
    栈是限定只能在表的一端进行插入和删除操作的线性表。
    队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
    (3).遍历数据速度不同。栈只能从头部取数据,也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性。队列则不同,它基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影像数据结构,速度要快的多
  • 用列表模拟栈操作
#栈
#特点:先进后出
myStack = []
#压栈(往栈结构存储数据)
myStack.append(1)
print(myStack)
myStack.append(2)
print(myStack)
myStack.append(3)
print(myStack)
#出栈
myStack.pop()
print(myStack)
myStack.pop()
print(myStack)
myStack.pop()
print(myStack)

#队列
#特点:先进先出
from collections import deque
q = deque([1,2,3,4])
#进队
q.append(5)
print(q)
q.append(6)
print(q)
#出队
q.popleft()
print(q)
q.popleft()
print(q)
q.popleft()
print(q)
q.popleft()
print(q)

堆栈

  • 内存结构
    python常用模块_第4张图片
  • 堆栈对比
    python常用模块_第5张图片
    python常用模块_第6张图片

psutil模块(系统信息)

官方文档
详细解读

chardet模块(检测编码)

详细解读

requests模块

详细解读

pygame模块

一、hello world

pygame.init()     #初始函数,使用pygame的第一步;
pygame.display.set_mod((600,500)032)     #生成主屏幕screen;第一个参数是屏幕大小,第二个0表示不使用特性,可用FULLSCREEN,RESIZEBLE,NOFRAME,DOUBLEBUF(双缓冲,使用时需用pygame.display.flip()来刷新屏幕)等替换,32表示色深;
pygame.display.set_caption("string")     #命名
pygame.display.update()        #刷新
pygame.display.list_modes()        #查看本地显示器支持的分辨率;
screen.fill(0,0,0)        #填充

二、绘图

pygame.draw.rect(surface,color,Rect,width=0) 画一个矩形,Rect为两个坐标元组的元组;

  • rect(矩形)参数属性
  •   r.left         左边x坐标的整数值
      r.right        右边x坐标的整数值
      r.top         顶部y坐标的整数值
      r.bottom      底部y坐标的整数值
      r.centerx      中央x坐标整数值
      r.centery      中央y坐标整数值
      r.width        宽度
      r.height       高度
      r.size         即元组(width,height)
      r.topleft      (left,top)
      r.topright     (right,top)
      r.bottomleft   (left,bottom)
      r.bottomright  (right,bottom)
      r.midleft      (left,centery)
      r.midright     (right,centery)
      r.midtop       (centerx,top)
      r.midbottom    (centerx,bottom)
    
  • 其他形状
  •   pygame.draw.polygon(surface,color,pointlist,width=0)    多边形
      pygame.draw.circle(surface,color,pos,radius,width=0)      圆
      pygame.draw.ellipse(surface,color,Rect,width=0)         椭圆
      pygame.draw.arc(surface,color,Rect,start_angle,stop_angle,width=1) 圆弧
      pygame.draw.line(surface,color,start_pos,end_pos,width=1)    直线;
      pygame.draw.lines(surface,color,closed,pointlist,width=1)     closed为一bool值,表示是否封闭;
      pygame.draw.aaline(surface,color,start_pos,end_pos,width=1)    一根平滑的线;
      pygame.draw.aalines(surface,color,closed,pointlist,width=1)    一系列平滑的线;
    
  • font(以图形模式输出文本)
  •   1.pygame.font.Font("字体","字号",*)
    
      2.my_font.render(text,True,(255,255,255))        使用已有的文本创建一个位图image,返回值为一个image;对于位图可用get_height(),get_width()的方法获得高与宽;True表示是否抗锯齿,第三个为字体颜色,还可以有第四个为背景色,没有时就为默认的透明;
    
      3.Font()       使用的是字体文件,要使用系统中的字体需用SysFont(),但一些中文扩展的字体不是很好用。
    
      4.screen.blit(image,(100,100))             将位图绘制到屏幕上,screen为建立的主屏;
    
      5.pygame.font.get_fonts()           查看当前系统所有可使用的字体
    

三、 图片处理

pygame支持的图片格式有:JPEG,PNG,GIF,BMP,PCX,TGA,TIF,LBM,PBM,XPM

pygame.image.load("图片路径").conver()        将图片处理为surface对象,如果使用conver_alpha()则保留了Alpha通道信息(可透明),使用时用blit()函数来添加到显示屏
pygame.Surface((250,250),flags,depth)        创建一个surface对象,如果不指定尺寸则会创建和屏幕一样大小;flags为可选,有SRCALPHA(保留Alpha通道)、HWSURFACE(优化)两个选择,depth为色深;
screen.subsurface((0,0),(80,80))           子表面对象;
screen.set_at(pos,color)                   设置一个像素的色彩;
screen.get_at(pos)                        获取某一像素的色彩,不过此操作的反应比较慢;
pygame.transform.scale(surface,(width//2,height//2)    缩放图片
pygame.transform.smoothscale(surface,(width,height)    缩放图片,比scale慢,但效果更好;
pygame.sprite.Group()           精灵组,一个简单的实体容器;
pygame.sprite.add(sprite)        添加精灵对象;
pygame.sprite.update(ticks)        
pygame.sprite.draw(screen)
pygame.sprite.collide_rect(arrow,dragon)    冲突
screen.set_clip(0,400,200,600)    设定裁剪区域;
screen.get_clip()              获得裁剪区域

四、事件event

 1 pygame.event.get()    获取事件的返回值,使用event.type == 进行区分
2 pygame.event.wait()    等待发生一个事件才会继续下去;
3 pygame.event.poll()    会根据现在的情形返回一个真实的事件
4 pygame.event.set_blocked(事件名)    过滤
5 pygame.event.set_allowed() 允许事件
  • 自定义事件

     1 my_event = pygame.event.Event(KEYDOWN,key=K_SPACE,mod=0,unicode=u' ')
     2 pygame.event.post(my_event)
    
  • pygame所有事件type

      QUIT             退出;
      ACTIVEEVENT     pygame被激活或隐藏;
      KEYDOWN         区分不同键 event.key == pygame.K_a,pygame使用keys=pygame.key.get_pressed()来轮询键盘接口,返回的是所有按下键值的元组;用keys[K_b]方式来核对键值;K_b也可以是键值Unicode码;如果mod & KMOD_CTRL为真的话表示同时按下Ctrl键;key.get_mods()组合键,key.set_repeat()重复事件;key.name()接受键值返回键名;
      KEYUP            按键放开
      MOUSEMOTION     含event.pos,event.rel,event.buttons属性,用mouse_x,mouse_y = event.pos进行确认,pygame.mouse.get_pos()返回鼠标的当前位置,pygame.mouse.get_rel()获取鼠标相对移动,pygame.mouse.get_pressed()返回按钮状态数组(鼠标三个键的状态)
      mouse.set_visible(False) 使鼠标不可见;
      event.set_grab(True)     使鼠标不会跑出窗口
      mouse.set_pos()          设置鼠标位置
      mouse.get_focused()      如果鼠标在pygame窗口内有效,返回True
      mouse.set_cursor()       设置鼠标默认光标式样;
      mouse.get_cursor()       获取鼠标默认光标式样;
      MOUSEBUTTONUP      鼠标放开
      MOUSEBUTTONDOWN    鼠标按下
      JOYAXISMOTION      x手柄移动
      JOYBALLMOTION      所有手机移动
      JOYHATMOTION       hat手柄移动
      JOYBUTTONUP        手柄按键放开
      JOYBUTTONDOWN      手柄按键按下
      VIDEORESIZE        窗口缩放;
      VIDEOEXPOSE        窗口部分公开;
      USEREVENT          触发了一个用户事件;
    

五、异常捕捉

try:
    screen = pygame.display.set_mode(SCREEN_SIZE)
except pygame.error,e:
    print("Can't create the display :-(")
    print(e)
    exit()

六、时间

1 clock = pygame.time.Clock()    初始化一个clock对象
2 clock.tick()     返回一个上次调用的时间,以毫秒为单位
3 clock.tick(30)    控制游戏绘制的最大帧率为30

七、声音

(一)sound对象

pygame.mixer.Sound(“文件”) 读取声音对象sound,格式只有wav和ogg两种;

对象方法:
1 fadeout()        淡出时间,可用参数为毫秒;
2 get_lengh()         获得声音文件长度,以秒为单位;
3 get_num_channels()     声音要播放的次数;
4 play(loop,maxtime)     对读取的声音对象可执行播放操作,loop为-1表示无限循环,1表示重复两次,maxtime表示多少毫秒后结束;返回一个Channel对象,失败则返回None;
5 set_volum()         设置音量;
6 stop()          停止播放;
7 pygame.mixer.music   背景音乐处理方法
8 pygame.mixer.music.load() 加载文件可为mp3和ogg格式;
9 pygame.mixer.music.play() 播放
10 pygame.mixer.music.stop() 停止,还有pause()和unpause()方法

(二)Channels对象

pygame.mixer.get_num_channels() 获取当前系统可同时播放的声道数;pygame中默认为8;

对象方法:
1 fadeout()    设置淡出时间
2 get_busy()    如果正在播放,返回True;
3 set_endevent() 设置播放完毕时要做的event;
4 get_endevent() 获取播放完毕时要做的event,如果没有则返回None;
5 get_queue()   获得队列中的声音,如果没有则返回None;
6 set_volume()   设置音量;
7 get_volume() 获得音量;
8 pause()   暂停播放;
9 unpause()    继续播放;
10 play()    播放;
11 stop()    停止播放;
12 queue()   将一个Sound对象加入队列,在当前声音播放完毕后播放;
13 set_num_channels() 自定义声道数;

(三)music对象
pygame.mixer.pre_init(frequency,size,stereo,buffer) 声音系统初始化,第一个为采样率,第二个为量化精度,第三为立体声效果,第四为缓冲;

对象方法:
1 fadeout()    设置淡出时间
2 set_endevent() 设置播放完毕后事件
3 get_endevent() 获取播放完毕后进行的事件;
4 set_volume() 设置音量;
5 get_volume() 获取音量;
6 load()    加载音乐文件;
7 rewind()    从头开始播放;
8 get_pos() 获得当前播放的位置,以毫秒为单位;

小游戏贪吃蛇

from pygame.locals import *
import pygame
import sys
import time
import random


# 初始化窗口
class Window(object):
    def __init__(self):
        # 初始化pygame
        pygame.init()
        # 刷新速度
        self.fpsClock = pygame.time.Clock()
        # 创建pygame显示层
        self.playSurface = pygame.display.set_mode((640, 480))
        # 设置标题
        pygame.display.set_caption('贪吃蛇')

    # 定义结束窗口
    def gameOver(self, color):
        # 设置字体
        gameOverFont = pygame.font.SysFont('Arial', 72)
        # 设置字体属性
        gameOverSurf = gameOverFont.render('Game Over', True, color)
        #
        gameOverRect = gameOverSurf.get_rect()
        # 设置字体位置
        gameOverRect.midtop = (320, 240)
        # 在窗口显示
        self.playSurface.blit(gameOverSurf, gameOverRect)
        # 刷新窗口
        pygame.display.flip()
        time.sleep(5)
        pygame.quit()
        sys.exit()


# 定义snake类


class Snake(object):
    def __init__(self):
        # 初始化snake出现位置
        self.snakeHead = [100, 100]
        self.snakeBody = [[100, 100], [80, 100], [60, 100]]
        # 移动的方向
        self.direction = 'right'
        self.changeDirection = self.direction

    # 定义键盘事件
    def key_Event(self):
        # 检测键盘事件
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN:
                # 判断键盘事件
                if event.key == K_RIGHT or event.key == ord('d'):
                    self.changeDirection = 'right'
                if event.key == K_LEFT or event.key == ord('a'):
                    self.changeDirection = 'left'
                if event.key == K_UP or event.key == ord('w'):
                    self.changeDirection = 'up'
                if event.key == K_DOWN or event.key == ord('s'):
                    self.changeDirection = 'down'
                if event.key == K_ESCAPE:
                    pygame.event.post(pygame.event.Event(QUIT))

    # 移动
    def move(self):

        # 判断是否输入了当前移动方向的反方向
        if self.changeDirection == 'right' and not self.direction == 'left':
            self.direction = self.changeDirection
        elif self.changeDirection == 'left' and not self.direction == 'right':
            self.direction = self.changeDirection
        elif self.changeDirection == 'up' and not self.direction == 'down':
            self.direction = self.changeDirection
        elif self.changeDirection == 'down' and not self.direction == 'up':
            self.direction = self.changeDirection

        # 根据方向移动蛇头的坐标
        if self.direction == 'right':
            self.snakeHead[0] += 20
        elif self.direction == 'left':
            self.snakeHead[0] -= 20
        elif self.direction == 'up':
            self.snakeHead[1] -= 20
        elif self.direction == 'down':
            self.snakeHead[1] += 20

    def eat(self, food):
        self.snakeBody.insert(0, list(self.snakeHead))
        # 判断是否吃掉了food
        if self.snakeHead[0] == food.raspberryPosition[0] and self.snakeHead[1] == food.raspberryPosition[1]:
            x = random.randrange(1, 32)
            y = random.randrange(1, 24)
            food.raspberryPosition = [int(x * 20), int(y * 20)]
        else:
            self.snakeBody.pop()


# 定义Food类


class Food(object):
    def __init__(self):
        # 出现位置
        self.raspberryPosition = [300, 300]

    #
    # 拓展
    #
    # 通过判断snakes的长度来调整游戏速度和food数量
    '''
    def add_food(self,obj1,obj2):
        num =len(obj2.snakeBody)
        if num>0 and  num<10:
            obj1.fpsClock.tick(5)
        if num>=10 and num <20:
            obj1.fpsClock.tick(10)
        if  num>=20:
            obj1.fpsClock.tick(13)
    '''


def main():
    # 定义颜色
    redColour = pygame.Color(255, 0, 0)
    blackColour = pygame.Color(0, 0, 0)
    whiteColour = pygame.Color(255, 255, 255)
    greyColour = pygame.Color(150, 150, 150)

    # 定义窗口,snake,food
    user_Interface = Window()
    snake = Snake()
    food = Food()
    # img=pygame.image.load(r'C:\Users\LAB\Desktop\1.jpg')
    while True:

        # 设置窗口背景色
        user_Interface.playSurface.fill(blackColour)
        # 设置snake和food的位置及颜色
        for position in snake.snakeBody:
            pygame.draw.rect(
                user_Interface.playSurface, whiteColour, Rect(
                    position[0], position[1], 20, 20))
            pygame.draw.rect(user_Interface.playSurface, redColour, Rect(
                food.raspberryPosition[0], food.raspberryPosition[1], 20, 20))

        # 键盘事件
        snake.key_Event()
        # 移动snake
        snake.move()
        # 吃食物
        snake.eat(food)

        # 判断是否死亡
        if snake.snakeHead[0] > 620 or snake.snakeHead[0] < 0 or snake.snakeHead[1] > 460 or snake.snakeHead[1] < 0:
            user_Interface.gameOver(greyColour)

        else:
            for snakeBody in snake.snakeBody[1:]:
                if snake.snakeHead[0] == snakeBody[0] and snake.snakeHead[1] == snakeBody[1]:
                    user_Interface.gameOver(greyColour)

        # 刷新界面
        pygame.display.flip()

        # food.add_food(user_Interface, snake)

        user_Interface.fpsClock.tick(5)


if __name__ == '__main__':
    main()

你可能感兴趣的:(python基础)