Python语言程序设计笔记

例:获得用户输入数字N,计算并输出从N开始的5个质数,单行输出 

首先:定义函数判断一个数是否是质数,return True/False,注意return True的格式,不在for循环体中,在函数体中(循环的高级用法,for---else);其次:确定输入的数、计数为0;最后while循环,计数5次,在循环中调用判断是否是质数的函数,是就打印出来,计数加一,再将输入的数加一。注意:输入的数加一,要在if循环外,若在里面就不会继续判断了!

continue一般用在循环里,退出当前循环,

for word in words:
    if len(word) == 1:
        continue

return语句用于退出函数, return false 返回错误的处理结果,终止处理,阻止提交表单,阻止执行默认的行为,就相当于终止符。return true  返回正确的处理结果,相当于执行符。

def prime(m):
    for i in range(2,m):
        if m % i == 0:
            return False  #若有余数,将灰飞烟灭,不会现世(终止处理,阻止提交表单,阻止执行默认的行为)
    return True

n = eval(input())
nt = int(n)
nt = nt + 1 if nt < n else nt
count = 0

while count < 5:
    if prime(nt):
        print(nt,end=',')
        count += 1
    nt += 1

点击run modle/F5运行

代码的改进:可以先将输出质数个数设出来,count=5,在while循环中依次减一,便于参数的修改!若要求输出时,数据用逗号分割,最后一个不用逗号:print(mt,end=',')  print(mt,end='')

def zhi(n):
    for i in range(2,n):
        if n % i == 0:
            return False
    return True

m = eval(input())
mt = int(m)
mt = mt+1 if mt < m else mt
count = 5

while count > 0:
    if zhi(mt):
        if count > 1:
            print(mt,end=',')
        else:
            print(mt,end='')
        count -= 1
    mt += 1

画同心圆

import turtle
turtle.pensize(2)
turtle.circle(10)
turtle.circle(40)
turtle.circle(80)
turtle.circle(100)

画五角星

from turtle import *
color('red','red')
begin_fill()
for i in range(5):
    fd(200)
    rt(144)
end_fill()
done()

import 模块:导入一个模块,每次使用模块中的函数都要是定是哪个模块

from...import *:导入一个模块中的所有函数,每次使用模块中的函数直接使用函数就可。因为已经知道该函数是那个模块中的了。

from...import:导入一个模块中的一个函数,后面使用可直接调用函数

import support
support.print_func("Runoob")

from support import *
print_func("Runoob")

实例1:温度转换

需求分析:将摄氏度转为华氏度,或将华氏度转为摄氏度。摄氏度——标准大气压下水的结冰点为0度,沸点为100度;华氏度——标准大气压下水的结冰点为32度,沸点为212度。

分析问题:理解1,直接将温度值进行转换;理解2,将温度信息发布的声音或图像形式进行理解和转换;理解3,监控温度信息发布渠道,实时获取并转换温度值。(采用理解1)

划分边界:I—带华氏或摄氏标志的温度值,P—选择适当的温度转换算法,O—带华氏或摄氏标志的温度值

设计输入输出格式:标识放到温度最后,F表示华氏度,C表示摄氏度(82F表示82华氏度)

设计算法:根据华氏和摄氏温度定义,利用转换公式:C=(F-32)/1.8    F = c*1.8+32

TempStr = input("请输入带有符号的温度值:")
if TempStr[-1] in ['F','f']:
    C = (eval(TempStr[0:-1]) - 32)/1.8
    print("转换后的温度是{:.2f}C".format(C))     #若计算较为复杂可先把C的式子列出来,若较简单可直接再print的format中进行
elif TempStr[-1] in ['C','c']:
    F = 1.8*eval(TempStr[0:-1]) + 32
    print("转换后的温度是{:.2f}F".format(F))
else:
    print("输入格式错误") 
请输入带有符号的温度值:80f
转换后的温度是26.67C
>>> 
==================== RESTART: F:\PYECourse\TempConvert.py ====================
请输入带有符号的温度值:78c
转换后的温度是172.40F

举一反三:货币转换、重量转换、面积转换

“温度转换”实例编程理解

代码高亮:编程的色彩辅助体系,不是语法要求。    

缩进:表达程序格式框架,表达代码间包含和层次关系;4个空格/1个TAB

注释:辅助说明信息。单行注释—#开头,多行注释:'''开头和结尾(3个单引号),不被计算机程序运行。

变量:程序中用于保存和表示数据的占位符号。TempStr是变量名字,用=向变量赋值

命名:大小写字母、数字、下划线和汉字等字符及组合,大小写敏感、数字不能用开头,不能用保留字(33个,编程语言的基本单词)。如TempStr。

数据类型:10,011,101表示啥意思呢?数字类型:整数- 10011101;浮点数-带小数

字符串类型:"10,011,101";字符串的序号有正向递增序号(0开始)和反向递减序号(-1开始)获得字符串中的一个或多个字符——索引:返回字符串中的单个字符,<字符串>[M],如TempStr[-1];切片:返回字符串中的一段字符串<字符串>[M:N],如TempStr[0:-1]表示从0开始但不到最后一个字符

列表类型:[10,011,101](表示3个数)['F','f']表示两个元素'F'和'f',可用保留字in判断元素是否在列表中

赋值语句:由赋值符号(=)构成的一行代码,右侧的数据类型同时作用于变量,TempStr=input( ),input( )返回一个字符串,TempStr变量也是一个字符串

分支语句:if  elif   else构成条件判断的分支结构,保留字所在行的最后存在一个冒号

函数:一个名字+一个括号,如input( )、eval( )、print()根据输入参数产生不同输出的功能过程,<函数名>(<参数>)

输入函数:input( )函数,<变量> = input(<提示信息字符串>),如TempStr = input("请输入")

输出函数:1、print( )函数,print(<拟输出字符串/字符串变量>),如print("输入格式错误")

2、print( )函数的格式化,如print("转换后的温度是{:.2f}C".format(C)) 字符串中出现了大括号,{ }表示槽,后续变量嵌入中,槽中可以嵌套槽,用来表示宽度、填充等含义。 :.2f仅输出小数点后两位。

eval( )函数:评估函数,去掉参数最外侧引号并执行余下语句

  C = (eval(TempStr[0:-1]) - 32)/1.8

 eval(TempStr[0:-1])  对TempStr除去最后一位之外的其他位进行评估运算,如用户输入82F,TempStr[0:-1] —— 去掉最后一位F获得一个字符串82; eval( )—— 变成数字类型,产生整数82

例:数字转换,获得用户输入的一个正整数输入,输出该数字对应的中文字符表示。

列表也是从0开始的,所以与变量的字符串相对应!

template = "零一二三四五六七八九"

a = input()
for i in a:
    print(template[eval(i)],end='')
791
七九一

print()函数中增加end=" "参数表示输出后不增加换行,多个print()可以连续输出

print(" ", )中间加逗号,输出的字符串之间会增加空格

for i in range (5):
    print("Hello:",i)
Hello: 0
Hello: 1
Hello: 2
Hello: 3
Hello: 4

实例2:Python蟒蛇绘制   

import turtle
turtle.setup(650,350,200,200)
turtle.penup()
turtle.fd(-250)
turtle.pendown()
turtle.pensize(25)
turtle.pencolor("purple")   #准备工作,确定起画位置、画笔大小、画笔颜色
turtle.seth(-40)            #改变方向非常重要!图1为改变方向,图2为没变方向
for i in range(4):
    turtle.circle(40,80)
    turtle.circle(-40,80)   #4个循环绘制了蟒蛇4个关节
turtle.circle(40,80/2)      #半个关节弧长的一半
turtle.fd(40)
turtle.circle(16,180)
turtle.fd(40*2/3)
turtle.done()               #程序运行后需手动退出

 理解turtle.seth() + turtle.circle():改变方向后,可想象沿该方向画直线,circle的第一个参数表示圆的半径,若为正向左画(图1\3),若为负向右画(图2\4),第二个参数表示角度所对应的弧长。

#图0
import turtle
turtle.circle(40,80)
#图1
import turtle
turtle.seth(-40)
turtle.fd(100)
turtle.circle(40,80)
#图2
import turtle
turtle.seth(-40)
turtle.fd(100)
turtle.circle(-40,80)
#图3
import turtle
turtle.seth(40)
turtle.fd(100)
turtle.circle(40,80)
#图4
import turtle
turtle.seth(40)
turtle.fd(100)
turtle.circle(-40,80)

 

 举一反三:程序参数的改变——修改蟒蛇颜色,蟒蛇长度(1节、3节、10节),蟒蛇走向(向左走、斜着走)。计算问题的拓展——圆形、五角星、国旗、机器猫绘制,掌握绘制一条线的方法就可以绘制整个世界。

turtle库

绘图库,(海龟库)1969年诞生,用于程序设计入门;python语言的标准库之一;入门级的图像绘制函数库。turtle是一种真实的存在,一只海龟在窗体正中心、在画布上游走,走过的轨迹形成了绘制的图形,海龟由程序控制,可以变换颜色、改变宽度。

turtle的绘图窗体:(绘制100长的直线指的是100像素长的直线

turtle.setup(width, height, startx, starty)包括4个参数:宽度,高度,起始点xy的坐标(窗体左上角位置坐标:相对于屏幕左上角的坐标,可选)。setup( )函数非必须,只在需要设置窗体大小、在屏幕中显示位置的时候才需要。

turtle的行进:画布上以中心为原点 走直线&曲线(绝对坐标&海龟坐标)

turtle.goto(x,y):让在任何位置的海龟去到指定的坐标位置

turtle.forward(d)  别名turtle.fd(d)正前方行进,海龟走直线    d为行进距离,可为负数

turtle.bk( ):向海龟的反方向行进

turtle.circle(r,extent=None):r-半径(默认圆心在海龟左侧距r处,海龟处在圆的最低点),extent-绘制的弧度。 注意圆心的位置!!!

turtle的行进方向:(绝对角度&海龟角度)

turtle.seth(angle),改变海龟行进方向但不行进,+ turtle.fd( )朝着当前设定的方向直线运行

turtle.left(angle)turtle.right(angle)用左右的方式改变运行角度。 

常用的RGB色彩:每色取值范围整数0-255或0-1小数,turtle默认小数值,可切换为整数值。

turtle.colormode(1.0):RGB小数模式;turtle.colormode(255):RGB整数值模式。

库引用:扩充python程序功能的方式。使用import保留字完成。三种方式:

import<库名>                              import turtle                引入turtle库

<库名>.<函数名>(<函数参数>)    turtle.setup(650,350)  使用turtle库函数完成功能

from <库名> import *                  from turtle import *

<函数名>(函数参数)                setup(650,350)

import <库名> as <库别名>        import turtle as t         给库关联一个更短、更适合自己的名字

<库别名>.<函数名>(<函数参数>)

from <库名> import <函数名>

第一种方法不会出现函数重名问题(<库名>.<函数名>是新程序中的函数名); 第二种方法会出现(库中的某个函数名称可能与用户自定义的函数名称一致,导致函数名字发生冲突);若程序很短,只使用了这个库,没有自己定义的函数,可使用from<库名> import *的形式。

turtle画笔控制函数

turtle.penup( )  别名turtle.pu( ) :抬起画笔,海龟在飞行

turtle.pendown( ) 别名turtle.pd( ) :落下画笔,海龟在爬行

抬起画笔、落下画笔,一般成对出现,去到想去的地方,而不留痕迹!!!

注意与函数goto( )的区别,抬起画笔+fd( )/goto( )+落下画笔  确定画的起点,不会画出实际线条。

turtle.pensize(width)  别名turtle.width(width):画笔宽度,海龟的腰围

turtle.pencolor(color)  color有3种形式,颜色字符串或r,g,b值:画笔颜色,海龟在涂装turtle.pencolor("purple") / turtle.pencolor(0.63,0.13,0.94) / turtle.pencolor((0.63,0.13,0.94))---元组值是指将小数值或整数值形成一个独立元素,如(0.63,0.13,0.94)

turtle.hideturtle()  在程序最后运用turtle库的.hideturtle(),可隐藏画笔

循环语句for    in range  按照一定次数循环执行一组语句。

for <变量> in range(<参数>)

        <被循环执行的语句>

range的参数就是循环的次数,缩进的代码将被循环执行;for   in 之间的变量表示每次循环的计数,0 — 次数-1。

range( )函数:产生循环计数序列,最主要作用是和for  in 搭配形成计数循环。

range(N):产生0到N-1的整数序列,共N个。如range(5)   0,1,2,3,4

range(M,N):产生M到N-1的整数序列,共N-M个。如range(2,5)    2,3,4

例:turtle风轮绘制

import turtle as t 
t.pensize(2)
for i in range(4):
    t.left(90)
    t.fd(150)
    t.right(90)
    t.circle(-150,90/2)
    t.goto(0,0)
    t.left(135)
import turtle as t
t.pensize(2)
for i in range(4):
    t.seth(90*i)
    t.fd(150)
    t.right(90)
    t.circle(-150, 45)
    t.goto(0,0)

个人感悟:for  in range循环在绘图种的作用:复制粘贴。不要把turtle.circle()想得太复杂,直接在点上绘制弧度对应的弧长即可,注意是哪个方向。第3张图为没有加 t.right(90),图像方向改变可想象为一条虚线,即辅助线



数字类型及操作

整数类型:可正可负。pow(x,y)函数计算x的y次方,想算多大算多大。

>>> pow(2,100)
1267650600228229401496703205376
>>> pow(2,pow(2,15))
14154610310449547890015530277449516013481307114723881672343857482723666342408452…

四种进制表示形式:a.十进制 如1010,99    b.二进制 — 以0b或0B开头 如0b010,0B101   c.八进制 — 以0o或0O开头 如0o123,0O456    d.十六进制 — 以0x或0X开头 如0x9a,-0X89

浮点数类型:带有小数点及小数的数字,浮点数的取值范围和小数精度都存在限制(取值范围数量级为-10的308次方—10的308次方,精度数量级围为10的-16次方),但常规计算可忽略。浮点数间的运算存在不确定尾数,不是bug。

>>> 0.1+0.3
0.4
>>> 0.1 + 0.2
0.30000000000000004    #不确定尾数造成的
>>> 0.1 + 0.2 == 0.3
False
>>> round(0.1+0.2,1) == 0.3
True

浮点数间运算可能会产生不确定尾数。原因是,计算机中所有数字都采用二进制方式表示,53位二进制表示小数部分。0.1表示为0.00011001100110011001 10011001100110011001 1001100110011010(二进制)。二进制与十进制不存在严格对等关系,所以二进制表示小数,会无限接近,但不完全相同。0.1表示为0.1000000000000000055511151231257827021181583404541015625(十进制),只输出前16位小数。所以0.1+0.2计算时,在计算机内部经过二进制转换,再经过二进制运算,再反向转换为十进制小数时,结果会无限接近0.3,但可能出现一个不确定的尾数。

round(x,d )函数:对x四舍五入,d是小数截取位数。浮点数间运算及比较,用round()函数辅助。

int(x):取整,简单截取,不是四舍五入。

浮点数可以以用科学计数法表示,使用字母eE作为幂的符号,以10为基数,格式为<a>e<b> 表示 a*10b  如:4.3e-3 值为0.0043   9.6E5 值为960000.0

复数类型

如果x2 = -1,那么x的值是什么?

如 z = 1.23e - 4 + 5.6e + 89j,z.real 获得实部,z.imag获得虚部。

复数类型在常规编程中很少使用,但却是进行空间变换,尤其是跟复变函数相关的科学体系中最常用的一种类型。

数值运算操作符

//%配合完美

二元操作符:两个数运算后,去更改其中的一个数。

x +=y  /  x-=y   /   x*=y   /   x/=y    /     x//=y    /   x%=y   /   x**=y       如x**=3与x = x**3等价 

数字类型间可进行混合运算,生成结果为"最宽"类型。 整数 -> 浮点数 -> 复数(逐渐变宽),浮点数是虚部为0的复数。如123 + 4.0 = 127.0(整数+浮点数=浮点数,浮点数再经过运算时可能会产生不确定的尾数)

 数值运算函数:以函数形式提供的数值运算功能

 

 

 每天进步/退步1‰,累计进步/退步多少?

dayup = pow(1.001,365)
daydown = pow(0.999,365)
print("向上:{:.2f},向下:{:.2f}".format(dayup,daydown))

向上:1.44,向下:0.69

5‰和1%的力量

dayfactor = 0.005      #运用变量,一处修改即可。  =0.01
dayup = pow(1+dayfactor,365)
daydown = pow(1-dayfactor,365)
print("向上:{:.2f},向下:{:.2f}".format(dayup,daydown))

向上:6.17,向下:0.16     #向上:37.78,向下:0.03

使用变量的好处:一处修改即可,只需在变量赋值的地方修改一处,相关结果会发生变化。

 工作日的力量(工作日每天进步1%,休息日每天退步1%)

从数学思维转为用计算机程序解决问题的计算思维(for  in range!!!用计算机程序来模拟365的过程,抽象+自动化。遇到工作日向上增加,遇到休息日向下减少,累计循环。

dayup = 1
dayfactor = 0.01
for i in range(365):
    if i%7 in [0,6]:
        dayup = dayup*(1-dayfactor)
    else:
        dayup = dayup*(1+dayfactor)
print(dayup)

a = pow(1.01,260)
b = pow(0.99,105)
c = a*b
print(c)
4.626500529730141
4.626500529730134

例:工作日的努力

A君:每天进步1%,不停歇。B君:每周工作5天休息2天,休息日下降1%,要多努力才能和A同?

"笨办法"试错def..while..,让B尝试工作日达到一个什么样的能力值,能够超过A君。不断增加B的能力值,直到达到A君的效果。函数就像是数学中中含未知数x的等式,x就是定义函数中的占位符。然后再笨办法试错,算出未知数x。

从程序设计上来说,我们需要一段函数,它能够根据不同的努力值来计算工作日模式下的累积效果。为了能复用这段代码,需要编写一段函数(代码的组合)

函数的基本代码框架:def dayup(df)   参数df是一个占位符,用df表示dayfactor的简写,记得返回return dayup。

def dayUP(df):
    dayup = 1
    for i in range(365):
        if i % 7 in [6,0]:
            dayup = dayup * (1 - 0.01)
        else:
            dayup = dayup * (1 + df)
    return dayup
dayfactor = 0.01
while dayUP(dayfactor) < 37.78:
    dayfactor += 0.001
print("工作日的努力参数是:{:.3f}".format(dayfactor))
工作日的努力参数是:0.019

举一反三:如果休息日不下降呢? 如果工作如提高1%,休息日下降1‰呢? 如果工作3天休息1天呢? 如果“三天打鱼,两天晒网”呢? 


字符串类型及操作

字符串表示方法:a.由一对单引号表示  b.由一对双引号表示  c.由一对3单引号表示    d.由一对3双引号表示(a.b表示单行字符串,c.d表示多行字符串)

注:3单引号可以当多行注释,3单引号构成字符串,若在程序中出现一个字符串,字符串并没有给到某一个变量中或者没有进行任何操作,那么它也可以当注释来使用。

为啥要由两类四种表示呢?若在字符串中出现双引号,字符串可以用单引号表示;若字符串中出现单引号和双引号,字符串可以用3单引号表示。若在字符串中出现双引号,字符串也想用双引号表示,则可以用转义符 \:表达字符的本意。如"这里有个双引号(\")" 结果为这里有个双引号(\")。转义符还可以形成一些组合,表达一些不可打印的含义:\b 回退,\n 换行(光标移动到下行首), \r 回车(光标移动到本行首)

字符串的两个重要操作:索引切片

<字符串>[M:N]  如“零一二三四五六七八九十"[:3] 结果是"零一二"

<字符串>[M:N:K] 根据步长K对字符串切片 如“零一二三四五六七八九十"[1:8:2] 结果是"一三五七"   “零一二三四五六七八九十"[::-1] 结果是"是、十九八七六五四三二一零"(字符串从最开始到最结尾,步长为-1,指从后向前逐一地取出 将字符串逆序

字符串操作符

x + y :连接字符串x和y

n * x 或 x * n :将字符串x复制n次

x in s :如果x是s的字串,返回True,否则返回False

weekStr = '一二三四五六日'
weekId = eval(input("输入星期数字(1-7):"))
print("星期" + weekStr[weekId - 1])
weekStr = '星期一星期二星期三星期四星期五星期六星期日'
weekId = eval(input("请输入星期数字(1-7):"))
pos = (weekId - 1)*3
print(weekStr[pos:pos+3])
输入星期数字(1-7):5
星期五

字符串处理函数(字符串6个重要函数)

len(x) :返回字符串x的长度  如len("一二三456")结果为6  注:数字/标点符号/字母/汉字都为1字符

str(x) :转换为字符串类型 如str(1.23)结果为"1.23"  str([1,2])结果为"[1,2]"   与eval( )函数功能相反

hex(x)oct(x) :整数x的十六进制或八进制形式的字符串。 如hex(425)结果为"0x1a9" oct(425)结果为"0o651"    hexadecimal[ˌheksəˈdesɪml]十六进制的,octagon[ˈɒktəgən]八边形

二进制:0b 或 0B 开头      八进制:0o 或 0O 开头      十六进制:0x 或 0X 开头

chr(u)  :u为Unicode编码——返回对应的字符ord(x) :x为字符——返回对应的Unicode编码 

Unicode编码是python字符串的编码形式,python所有字符串、代码都是采用Unicode编码。计算机是由欧洲和美国人发明的,所以最开始计算机中只有英文字符,英文字符的空间范围有限,国际上广泛使用ASCII码来表示所有的英文字符。随着计算机广泛应用到世界各地,如何对中文字符进行编码,如何让计算机可以处理中文汉字?用一套编码覆盖世界上所有的字符,即Unicode编码。从0到1114111(十六进制0x10FFFF)空间,每个编码对应一个字符。

>>> "1 + 1 = 2" + chr(10004)
'1 + 1 = 2✔'                     #10004对应的字符是✔

>>> "这个字符♉的Unicode值是:" + str(ord("♉"))
'这个字符♉的Unicode值是:9801'    #金牛对应的编码是9801,金牛座是十二星座第二位

for i in range(12):
    print(chr(9800 + i),end="")
♈♉♊♋♌♍♎♏♐♑♒♓   #通过Uincode输出十二星座字符

学完python语言程序设计内容,记得去看《python密码学编程》,完成恺撒密码加密算法,第3章的程序设计题。 

例:恺撒密码加密破译

s = input()
t = ""
for c in s:
    if 'a' <= c <= 'z': 
        t += chr( ord('a') + ((ord(c)-ord('a')) + 3 )%26 )
    elif 'A' <= c <= 'Z':
        t += chr( ord('A') + ((ord(c)-ord('A')) + 3 )%26 )
    else:
        t += c
print(t)
python is good
sbwkrq lv jrrg

字符串处理方法(字符串8个重要方法)

方法<a>.<b>( )风格中的函数<b>( );方法本身也是函数,但与<a>有关<a>.<b>( )风格使用。字符串及变量也是<a>,存在一些方法。注:<a>.<b>( )风格也是面向对象的一种使用风格,a为对象,b是某一对象能够提供的功能,即方法。方法必须用.的形式来执行

str.lower( )或str.upper( ) :全部字符串小写/大写  如"AbCdEfGh".lower( )结果为"abcdefgh"

str.join(iter) :在每个字符间加入一个str字符 如",".join("12345") 结果为"1,2,3,4,5" 

str.split(sep=None) :字符串分割符 如 "A,B,C".split(",")结果为['A','B','C']  !!!分割字符要加引号!默认以空格的形式对字符串分隔,以列表形式返回变量,里边的每个元素就是空格分开的单词。把一个大元素按要求劈成若干小元素

str.strip(chars) :去掉最左侧和右侧的字符 如"= python=".strip(" =np") 结果为"ytho"

str.count(sub) :用于计数,如"an apple a day".count("a")结果为4

str.replace(old,new) :把原字符串替换成新字符串 如"python".replace("n","n123.io")结果为"python123.io"

str.center(width[,fillchar]) :将字符串位于居中位置,中间字符串一定有宽度,左右两侧一定会有填充存在  如"python".center(20,"=") 结果为'=======python======='

" i,love,python  ".strip().split(',')
Out[10]: ['i', 'love', 'python']

字符串类型的格式化(槽机制+format方法)  { }  +  ( )

格式化是对字符串进行格式化表达的方式。相当于一个占位信息符,用一对{}表示,只在字符串中有用。

字符串格式化的用法:<模板字符串>.format<逗号分隔的参数>

 

 槽内部格式化的配置方式:{<参数序号> : <格式控制标记>}   6个格式控制参数分两组

:后面数字---输出宽度,出现.---精度,出现,---千位分隔符,出现><^---对齐,出现字母---类型

format( )可以槽嵌套槽,表示宽度、填充含义。print("{0:^{1}}".format('*'*i,n)),用户输入的数据不确定,使行的宽度也不确定,通过嵌套槽为n来确定宽度。

例:读入一个整数N,N是奇数,输出由星号字符组成的等边三角形,要求:‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬第1行1个星号,第2行3个星号,第3行5个星号,依次类推,最后一行共N的星号。‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬

注:s='PYTHON'  print("{0:3}".format(s)) 结果为PYTHON,而不是PYT

n = eval(input())
for i in range(1,n+1,2):
    print("{0:^{1}}".format('*'*i,n))
5
  *  
 *** 
*****

time库

python中处理时间的标准库。能表达计算机时间、获取系统时间并格式化输出、提供系统级的精确计时功能,用于程序性能分析。  import time           time.<b>( )

time库包括三类函数:时间获取、时间格式化、 程序计时

时间获取

time( ):获取当前时间戳(当前系统中表示时间的一个浮点数)表示从1970年1月1日0:00开始到当前时刻为止的以秒为单位的数值。

ctime( ):获取当前时间并以易读的方式表示。time库中获取人类译读方式时间的最简单的函数。

gmtime( ):生成计算机程序可处理的时间格式。

>>> import time
>>> time.time()
1645008151.1828973
>>> time.ctime()
'Wed Feb 16 18:45:12 2022'
>>> time.gmtime()
time.struct_time(tm_year=2022, tm_mon=2, tm_mday=16, tm_hour=10, tm_min=47, tm_sec=41, tm_wday=2, tm_yday=47, tm_isdst=0)

时间格式化:将时间以合理方式展现出来。类似于字符串格式化(.format),需要有展示模板;展示模板由特定的格式化控制符组成;

strftime(tpl,ts ):tpl是格式化模板字符串,ts是计算机内部时间类型变量。

年是大写,月、日小写小时、分种、秒是大。所有的控制符都是%+字母 的形式表达,%Y:年份(0000-9999),%m:月份(01-12),%B:月份名称(January-December),%b:月份名称缩写(Jan-Dec),%d:日期(01-31),%A:星期(Monday-Sunday),%a:星期缩写(Mon-Sun),%H:小时(24h制 00-23),%I:小时(12h制 00-12),%p:上/下午(AM,PM),%M:分钟(00-59),%S:秒(00-59)

strptime(str,tpl ):str是字符串形式的时间值,tpl是格式化模板字符串,用来定义输出效果。与strftime( )互补。将一个字符串变为计算机内部可以操作的一个时间

>>> time.strftime("%Y-%m-%d %H:%M:%S")
'2022-02-16 11:30:05'

timeStr = '2022-02-16 18:45:12'	  
>>> time.strptime(timeStr,"%Y-%m-%d %H:%M:%S")	  
time.struct_time(tm_year=2022, tm_mon=2, tm_mday=16, tm_hour=18, tm_min=45, tm_sec=12, tm_wday=2, tm_yday=47, tm_isdst=-1)

程序计时:测量起止动作所经历的时间

perf_counter( ):返回一个CPU级别的精准时间计数值,单位为秒,由于计数值起点不确定,连续调用差值才有意义。

sleep(s):s为拟休眠时间,单位为秒,可以是浮点数。

>>> start = time.perf_counter()
>>> end = time.perf_counter()
>>> end - start
23.1431617

>>> def wait():
	time.sleep(3.3)
>>> wait()               #程序将等待3.3s,然后再向前运行

文本进度条:用字符串的方式,打印可以动态变化的文本进度条;进度条需要能在一行中逐渐变化。进度条反映某一个事件的运行,与时间有关系,故需模拟一个持续的进度——sleep()函数。

import time
scale = 10                  #文本进度条的大概宽度
print("------执行开始------")
for i in range(scale+1):
    a = '*' * i            #字符串与整数的乘积表示字符串被复制的次数
    b = '.' * (scale - i)
    c = (i/scale)*100      #与字符串进度一致的百分比
    print("{:^3.0f}%[{}->{}]".format(c,a,b))   #设置了3个槽(填充、对齐、宽度)
    time.sleep(0.1)
print("------执行结束------")
------执行开始------
 0 %[->..........]
10 %[*->.........]
20 %[**->........]
30 %[***->.......]
40 %[****->......]
50 %[*****->.....]
60 %[******->....]
70 %[*******->...]
80 %[********->..]
90 %[*********->.]
100%[**********->]
------执行结束------

文本进度条单行动态刷新:根据程序的进度不断显示文本进度条的信息。刷新的本质是用后打印的字符覆盖之前的字符,要求不能换行—print( )需要被控制(在print函数中增加,end=" ",光标停留在字符串后面,不会换行,仅不换行就赋值为空,若要增加信息在end参数中增加);要能回退—打印后光标退回到之前的位置\r(在输出字符串前使光标退回到当前行首)

import time
for  i in range (101):
    print("\r{:3}%".format(i),end="")  #要输出字符串,但输出前先把光标放行首再输出,输出后不换行,循环
    time.sleep(0.1)

注意:IDLE中F5键执行代码,无刷新效果,所有信息都打印出来。因为IDLE是编写程序的开发环境,不是程序运行的主要环境,为保证其中参数运行的效果,把\r功能屏蔽掉了。

实例4:文本进度条 

精髓:想要刷新多少次,设置scale变量,得到刷新的%数;进度条由两种符号组成*和.;动态刷新效果是\r + end='',需要不换行且回到开始位置;time.sleep(0.1)要由停顿,才能看到刷新。

import time
scale = 50
print("执行开始".center(scale//2,'-'))
start = time.perf_counter()
for i in range (scale + 1):         #range (scale)取不到scale,range(scale+1)才能取到scale
    a = '*' * i                     #'*'和'.'数量和为50
    b = '.' * (scale - i)
    c = (i/scale)*100               #i最大值为scale50,(i/scale)*100=100完成全部进度
    dur = time.perf_counter()-start #time.perf_counter()为计时,与程序运行时间有关,与scale无关
    print("\r{:^3.0f}%[{}->{}]{:.2f}s".format(c,a,b,dur),end='')   
    time.sleep(0.1)
print("\n"+"执行结束".center(scale//2,'-'))
-----------执行开始----------
100%[**************************************************->]5.45s
-----------执行结束----------

在打印“执行输出”两侧通过“-”字符来构成线条,a.直接打印输出。b..center( )方法,包括两个参数:字符串长度填充符号//表示整数商 10//3 结果为 3 c.字符串槽内部的格式化,填充对齐宽度,但得作用在槽内,槽机制+format方法

time库计时使用perf_counter()函数  start = time.perf_counter()   dur = time.perf_counter() - start .注意进度百分号要没有小数点,时间保留两位小数点。

message = '执行开始'
print("{:-^25}".format(message))   #字符串的填充对齐宽度,需要作用在槽中,槽机制+format方法

print("----------执行开始-----------")

print("执行开始".center(25,'-'))     #25表示输出字符串的总长度

----------执行开始-----------
----------执行开始-----------
-----------执行开始----------

举一反三:perf_counter( )计时 可以比较部分程序运行时间,统计程序中可能消耗大量运行时间的部分。在运行时间需要较长的程序中增加进度条;在任何希望提高用户体验的应用中增加进度条。

文本进度条的不同设计函数:

 

 什么样的进度条展示模式让用户体验更好,相比线性展示,开始展示进度条速度慢些,随着持续下载,后续进度条展示的增长效果组件增加,更符合人类需求。


程序的分支结构 

程序结构:线性结构、分支结构(单分支结构if、二分支结构if - else、多分支结构if - elif - else、条件判断及组合not and or > >= >>、程序的异常处理try - except - else - finally)、循环结构(遍历循环---for in 计数,字符串,列表,文件、无限循环---while、退出当前循环 continue,break、循环else的高级用法 与break有关)

单分支语句if   

guess = eval(input())
if guess == 99:
    print("猜对了")

二分支结构if — else

紧凑形式   <表达式1> if <条件> else <表达式2>  print("猜{ }了".format("对" if guess == 99 else "错")) ,判断if条件,若guess的值=99,返回前面的“对”,否则返回后面的字符串“错”。紧凑形式if 、else所对应的输出不是语句,是表达式,表达式是语句的一部分(简单理解为带赋值形式的有等号构成的语句,字符串“对”、“错是语句中的一部分,没有赋值的过程”)

guess = eval(input())
if guess == 99:
    print("猜对了")
else:
    print("猜错了")

guess = eval(input())
print("猜{}了".format("对" if guess==99 else"错"))

guess = eval(input())
if True:                   #后一部分是不会执行的
    print("猜对了")
else:                  
    print("猜错了")

多分支结构if - elif - elif - elif /if - elif - else 注意多条件之间的包含关系、变量取值范围的覆盖

score = eval(input())
if score >= 60:
    grade = 'D'
elif score >= 70:
    grade = 'C'
elif score >= 80:
    grade = 'B'
elif score >= 90:
    grade = 'A'
print("输入成绩属于级别{}".format(grade))

80
输入成绩属于级别D

#正常运行,但逻辑错误!

只要遇到if True,后边的语句就会被执行;not True相当于False,不会执行语句块2 ,只会执行else部分的语句块1

if True:                               if not True:
    print("条件正确")                       print("语句块2")
                                       else:  
                                           print(“语句块1”)
                                           

条件判断的操作符

<小于    <=小于等于     >= 大于等于     >大于    ==等于     !=不等于

条件组合的保留字

x and y :条件x和条件y的逻辑与 ;x or y :条件x和条件y的逻辑或;not x:条件x的逻辑非

guess = eval(input())
if guess > 99 or guess < 99:          #既使用了条件判断操作符又使用了条件组合保留字
    print("猜错了")
else:
    print("猜对了")

程序的异常处理

num = eval(input("请输入一个整数: "))   print(num**2)   当用户没有输入整数时,会产生异常。会提示异常发生的代码行数、异常类型、异常内容提示。

使用保留字 try - except .要执行的内容放try的语句块1中。有异常,执行except的语句块2。无异常,执行语句块1----执行后续语句。except中可增加异常类型,仅针对一种类型。

异常处理的高级使用:try - except - else - finally,finally对应的语句块4一定执行,else对应的语句块3在不发生异常时执行。(先执行try,没异常,奖励执行else;有异常,执行except;最后都要执行finally)

try:                         try:                               try:
    <语句块1>                     <语句块1>                          <语句块1>
except:                      except <异常类型>:                 except:
    <语句块2>                     <语句块2>                          <语句块2>
                                                                else:
                                                                    <语句块3>
                                                                finally:
                                                                    <语句块4>
try:
    num = eval(input("请输入一个整数:"))
    print(num**2)
except:
    print("输入不是整数")
try:
    num = eval(input("请输入一个整数:"))
    print(num**2)
except NameError:           #except + 异常名字   针对这一个异常类型
    print("输入不是整数")

实例5:身体质量指数BIM   

问题需求:同时输入体重、身高数据,同时输出国内、国际BMI指标分类信息BMI = 体重 (kg) / 身高2 (m2)   有国际、国内分类

思路:分别计算并给出国内和国际的BMI分类;混合计算并给出国内和国际的BMI分类(求同存异)

注意:同时赋值不能写成这样:who = " ",nat = " ",应该是who,nat = "",""

height,weight = eval(input("输入身高和体重数据[用逗号分隔]:"))
bmi = weight / pow(height,2)
print("BMI 数值为{:.2f}".format(bmi))
who,nat = "",""
if bmi < 18.5:
    who,nat = '偏瘦','偏瘦'
elif 18.5 <= bmi < 24:
    who,nat = '正常','正常'
elif 24 <= bmi < 25:
    who,nat = '正常','偏胖'
elif 25 <= bmi < 28:
    who,nat = '偏胖','偏胖'
elif 28 <= bmi < 30:
    who,nat = '偏胖','肥胖'
else:
    who,nat = '肥胖','肥胖'
print("BMI指标为:国际{0},国内{1}".format(who,nat))

输入身高和体重数据[用逗号分隔]:1.60,48
BMI 数值为18.75
BMI指标为:国际正常,国内正常

遍历循环遍历某个结构形成的循环运行方式。由for + in 组成,从遍历结构中逐一提取元素,放在循环变量中。完整遍历所有元素后结束。一串数、一个字符串、一个列表、一个文件……都是可以遍历的结构。

for <循环变量> in <遍历结构>:
    <语句块>

计数循环(N/特定次):for   in range(N) / for in range(M,N,K)   遍历range()函数产生的数字序列

for <循环变量> in range(N):               for <循环变量> in range(M,N,K):
    <语句块>                                  <语句块>     #从M开始,到N之前的整数,以K为步长

for i in range(1,6,2):
    print("Hello:",i)
Hello: 1
Hello: 3
Hello: 5

字符串遍历循环:s为字符串,遍历整个字符串,产生循环。

for c in s:
    <语句块>

for c in "python123":
    print(c,end=',')
p,y,t,h,o,n,1,2,3,

 列表遍历循环:ls为列表,遍历其每个元素,产生循环。注:遍历列表不会把列表中的,打印

for item in ls:
    <语句块>

for item in [123,'PY',456]:
    print(item,end=',')
123,PY,456,

文件遍历循环:fi是一个文件标识符,遍历其每行,产生循环。(一个外部文件通过python函数打开,若是以字符形式打开就会表示为一个文件标识的名字,相当于用一个变量标识系统中的文件)

for line in fi:
    <语句块>

for line in fi:
    print(line)
优美胜于丑陋
明了胜于隐晦
简洁胜于复杂

如果出现两个未知数:“笨办法”,考虑 def + 循环。与天天向上例子关联。def 部分会有return,但有return False、return True,在后面调用函数时前面需要if判断数是否是素数),return dayup(天天向上是返回一个数值,工作日需要多少努力)

例:求100以内所有素数之和。

def is_prime(n):
    for i in range(2,n):
        if n%i == 0:
            return False
    return True

sum = 0
for i in range(2,100):
    if is_prime(i):
        sum += i
print(sum)

1060

无限循环条件控制的循环运行方式,while反复执行语句块,直到条件不满足时结束

while <条件>:
    <语句块>
a = 3
while a > 0:
    a = a -1        #若修改为a = a + 1,程序将无限循环,永不退出,ctrl + c 组合键退出
    print(a)
2
1
0

循环打断:使用保留字continuebreakcontinue为结束本次循环,break为结束整个循环 

for i in  range(1,11):
    if i == 6:
        break
    print(i)
结果为1,2,3,4,5

for i in range(1,11):
    if i == 6:
        continue
    print(i)
结果为1,2,3,4,5,7,8,9,10

循环的高级用法循环+else。当循环没有遇到break语句时,执行else语句块(break相当于退出循环,break仅能退出最内层的当前循环)。else语句块作为“正常”完成循环的一种奖励(与异常处理else作用类似)。

for <循环变量> in <遍历结构>:               while <条件>:
    <语句块1>                                  <语句块1>
else:                                      else:
    <语句块2>                                  <语句块2>
for c in 'PYTHON':
    if c == 'T':
        continue
    print(c,end='')
else:
    print("正常退出")
PYHON正常退出

for c in 'PYTHON':
    if c == 'T':
        break
    print(c,end='')
else:
    print("正常退出")
PY

例:计算1-2+3-4...966‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬   

关键:设初始为0

a = 0
for i in range(1,967):
    if i%2 == 0:
        a -= i  #a = a - i
    else:
        a += i  #a = a + i
print(a)
-483
a = 0
count = 1
while count <= 966:
    if count % 2 == 0:
        a -= count
    else:
        a += count
    count += 1
print(a)
-483

例:用户登录,输入密码

若首行输入用户名为‘Kate’,第二行输入密码为‘666666’,输出‘登录成功!’;‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬当有3次输入用户名或密码不正确输出“3次用户名或者密码均有误!退出程序。”。关键:设初始次数为0,用户输入的名字和密码要在循环中,在else中累加登录次数,注:while :后为一整个循环体。

i = 0
while i < 3:
    name = input()
    key = input()
    if name =='Kate' and key =='666666':
        print("登录成功!")
        break
    else:
        i += 1
        if i == 3:
            print("3次用户名或者密码均有误!退出程序。")

random库

是使用随机数的python标准库(自带库,不需要安装,直接import使用)。伪随机数:采用梅森旋转算法,生成的伪随机序列,序列中的元素为伪随机数,表现为随机数的形式

random库包括两类函数,常用8个。基本随机数函数:seed( )、random()

产生小数:random( )/uniform( ) 产生整数:randint( )/randrange( ) 序列选一:choice( )/shuffle( )

基本随机数函数:

种子只需给一次,随机数会随着每次调用而产生不同的随机数;也可不给种子,直接调用random产生随机数(默认的种子是第一次调用random函数所对应的系统时间,精确到微秒,很难再现)

为啥要给种子?因为如果编程中给出了随机种子,下一次程序再运行,只要种子相同,产生的随机数也相同,对于使用随机数的程序可以复现或再现程序运行过程

在程序运行中如何利用seed( )函数呢?from...import 引入具体的函数,使用seed()需要提前引入

import random
random.seed(10)  
random.random()
Out[5]: 0.5714025946899135
random.random()
Out[6]: 0.4288890546751146

import random
random.seed(10)
random.random()
Out[9]: 0.5714025946899135
random.seed(10)
random.random()
Out[11]: 0.5714025946899135
from random import random, seed

DARTS = eval(input())
seed(123)
hits = 0.0
for i in range(DARTS):
    x, y = random(), random()
    dist = pow(x ** 2 + y ** 2, 0.5)
    if dist <= 1.0:
        hits = hits + 1
pi = 4 * (hits/DARTS)
print("{:.6f}".format(pi))

 扩展随机数函数:

 实例6:圆周率的计算

1、数学方法:

2、蒙特卡罗方法:圆的面积与方形面积之商与圆周率有关系。如何计算圆的面积?对一个区域面积,进行撒点,每个点随机出现在区域的任何一个位置。如果点尽可能的多且随机,圆内部的点构成了圆的面积,正方形中的所有点为正方形的面积。该方法还应用在很多工程问题中。

分析:1、无穷个数的累加:模拟一个很大的数,for循环实现累加。2、用随机数表示x,y的坐标,计算点到圆心的距离来判断点是在圆内还是方形内。

若代码特别长,在一行中无法表达,可在代码中增加“\”(与除"/"相反)使代码换行。若多行代码放到一行,需添加";"如s=[1,2,3,4,5,6,7,8,9];random.shuffle(s);print(s)

#数学公式方法,前提是知道公式
pi = 0 
N = 100
for k in range(N):
    pi += 1/pow(16,k)*(\ #pi += 1/pow(16,k)*( 4/(8*k+1)-2/(8*k+4)-1/(8*k+5)-1/(8*k+6))
               4/(8*k+1)-2/(8*k+4)-\
               1/(8*k+5)-1/(8*k+6))      
print("圆周率值是:{}".format(pi))

圆周率值是:3.141592653589793
#蒙特卡罗方法  先用整体的1/4
from random import random
from time import perf_counter   #计时的函数
DARTS = 1000*1000               #区域中抛撒点的总数量
hits = 0.0                      #在圆内部的点的数量
start = perf_counter()          #启动计时
for i in range(1,DARTS+1):      #for in循环模拟每次撒点
    x,y = random(),random()     #生成随机数的坐标值,random函数返回0-1之间的小数值
    dist = pow(x**2+y**2,0.5)   #计算点到圆心的距离,来判断点在圆内or方形内
    if dist <= 1.0:
        hits += 1
pi = 4 * (hits/DARTS)
print("圆周率值是:{}".format(pi))
print("运算时间是:{}".format(perf_counter()-start))

圆周率值是:3.141248
运算时间是:1.0513156000006347

举一反三:数学思维(找到公式,利用公式求解),计算思维(抽象一种过程,撒点过程,计算机自动求解)。程序运行80%的时间都花在10%的代码(循环)上,发现程序运行了较长时间,可以perf_counter去测量循环,再优化。



函数的定义与使用

使用def定义函数lambda定义匿名函数;可选参数(赋初值)、可变参数(*b)、名称传递;使用return可以返回任意多个结果;使用global声明使用全局变量,一些隐式规则;代码复用与函数递归

定义函数:一段代码;功能的抽象,函数表达特定功能。两个作用:降低编程难度代码复用

def 定义函数名,return给出返回值,中间是函数代码,名字后通过括号给出参数。指定的参数是占位符参数是输入,函数体是处理,结果是输出;函数不经调用,不会被执行;

调用函数:调用时要用实际参数替换定义中的形式参数,函数调用后得到返回值。

执行代码a = fact(10)时,会去查找所定义的函数def fact (n),将给定的参数10赋给函数的参数n,(10代替了定义函数中那个的n),执行函数 体的相关程序(for i in range(1,n+1)中的n也会替换为10),运算代码后产生一个具体的s值,s值作为返回值(返回给fact(10)这行代码)赋值给a。

函数参数:函数可以有参数,也可以没有参数,但必须保留括号。

def <函数名>(<参数(0个或多个)>):
    <函数体>
    return <返回值>
#案例:计算n!
def fact(n):
    s = 1
    for i in range(1,n+1):
        s *= i
    return (s)
a = fact(10)
print(a)                #结果为3628800

可选参数传递:函数定义时为某些参数指定默认值,构成可选参数(可以提供参数也可不提供参数)可选参数须放在必选参数之后

def <函数名>(<必选参数>,<可选参数>):
    <函数体>
    return <返回值>
#案例:计算n!//m(//表示整除)
def fact(n,m=1):#给出了第二个参数(可选参数),就用实际值;若没有给,就把m设为1进行下面的运算
    s = 1
    for i in range(1,n+1):
        s *= i
    return (s//m)

a = fact(10)  #调用时可以使用第二个参数,也可不使用
print(a)      #结果为3628800

a = fact(10,5)  #调用时可以使用第二个参数,也可不使用
print(a)        #结果为725760

可变参数传递:不定参数总数量。必选参数放前面,最后增加 *b表达不确定的参数(*a、*c都行),for item in b:

应用:python提供的函数max和min,计算一组数据的最大值和最小值,其参数是不确定的

def <函数名>(<参数>, *b):
    <函数体>
    return <返回值>

例:计算n!乘数 

def fact(n,*b):  #设定可变参数
    s = 1
    for i in range(1,n+1):
        s *= i    #计算n!的值
    for item in b:   #for in,b是一个组合数据类型,包含一个或多个数,每次取一个数,与s相乘
        s *= item  
    return (s)

a = fact(10,3)  #10!乘以3
print(a)        #结果为10886400

b = fact(10,3,5,8)
print(b)        #结果为435456000

例:计算任意输入数的乘积

def cmul(a,*b):
    s = a
    for i in b:
        s *= i
    return s

print(eval("cmul({})".format(input())))

参数传递的方式:函数调用时,可以按照位置或名称方式传递。

def fact(n,m=1):
    s = 1
    for i in range(1,n+1):
        s *= i
    return s//m

a = fact(10,5)      #位置传递
print(a)

b = fact(m=5,n=10)  #名称传递
print(b)

函数的返回值:return保留字用来传递返回值,return可以传递1个或多个返回值,之间用隔开不用加括号!函数可以有返回值,也可以没有,可以有return,也可以没有return。

def fact(n,m=1):
    s = 1
    for i in range(1,n+1):  #不能用range(n),若从0开始,阶乘都为0
        s *= i
    return s//m,n,m

print(fact(10,5))

a,b,c = fact(10,5)  #还可以使用变量,之间用逗号分隔并获得返回值。将函数运算的返回值分别赋给a,b,c
print(a,b,c)
(725760, 10, 5)   #元组类型,小括号中间用逗号分隔的几个元素
725760 10 5

局部变量和全局变量:函数体内部的变量为局部变量,函数体外的变量为全局变量。

规则1:局部变量和全局变量是不同的变量,即使重名(基本数据类型)。因为局部变量只是函数内部的占位符,函数运算结束后,局部变量会被释放,就不存在了;可以使用global保留字在函数内部使用全局变量

n,s = 10,100
def fact(n,s):
    s = 1
    for i in range(1,n+1):
        s *= i
    return s

print(fact(n,s),s)
#结果为3628800 100  ,s为全局变量中的s,局部变量的s在执行函数后会被释放
n,s = 10,100
def fact(n):
    global s   #global保留字声明,此处的s是全局变量
    for i in range(1,n+1):
        s *= i
    return s   #此处s指全局变量

print(fact(n),s)  #此处全局变量s被函数修改

#结果为362880000 362880000

规则2:局部变量为组合数据类型,且未创建时,等同于全局变量。

组合数据类型在python中是由指针体现,如果函数中没有真实创建组合数据类型,它使用的变量是指针,而指针指的是外部的全局变量,所以修改指针对应的内容就修改了全局变量。

ls = ['F','f']   #通过[]创建全局变量列表
def func(a):
    ls.append(a)  #此处ls为列表类型,未真实创建,则等同于全局变量
    return
func('C')    #全局变量ls被修改
print(ls)

#结果为['F', 'f', 'C']
ls = ['F','f']   
def func(a):
    ls = []        #ls为局部变量,函数运行后会被释放,就不存在了
    ls.append(a) 
    return
func('C')    #局部变量ls被修改
print(ls)

#结果为['F', 'f']

lambda函数:是一种匿名函数(没有名字的函数),用lambda保留字定义,函数名是返回结果。用于定义简单的、能在一行内表示的函数。谨慎使用lambda函数!

实例7:七段数码管绘制(七段小的数码管,可形成0-9,A-F)

 基本思路:绘制单个数字对应的数码管;获得一串数字,绘制对应的数码管;获得当前系统时间,绘制对应的数码管。 

已定义函数drawLine(draw),一般调用函数是给定实参。但如果是drawLine(True)就可以执行前面的函数。drawLine(True)不执行函数drawLine。

import turtle
def drawLine(draw):  #绘制一条线
    turtle.pendown() if draw else turtle.penup() #如果参数是draw就落笔,否则起飞
    turtle.fd(40)
    turtle.right(90)
    #如果是drawLine(True)是不是就可以执行函数呢?是的
def drawDigit(digit): #绘制一个数字
    drawLine(True) if digit in [2,3,4,5,6,8,9] else drawLine(False) #如果参数在[]中,True,执行drawLine函数,否则不执行
    drawLine(True) if digit in [0,1,3,4,5,6,7,8,9] else drawLine(False)
    drawLine(True) if digit in [0,2,3,5,6,8,9] else drawLine(False)
    drawLine(True) if digit in [0,2,6,8] else drawLine(False)
    turtle.left(90) #在drawLine函数中有turtle.right(90),每画一次都会拐个弯
    drawLine(True) if digit in [0,4,5,6,8,9] else drawLine(False)
    drawLine(True) if digit in [0,2,3,5,6,7,8,9] else drawLine(False)
    drawLine(True) if digit in [0,1,2,3,4,7,8,9] else drawLine(False)
    turtle.left(180)
    turtle.penup() #为绘制后续数字确定位置
    turtle.fd(20)
def drawDate(date): #绘制一串数字
    for i in date:
        drawDigit(eval(i))
def main():
    turtle.setup(800,350,200,200)
    turtle.penup()
    turtle.fd(-300)
    turtle.pensize(5)
    drawDate('20181010')
    turtle.hideturtle()
    turtle.done()
main()

 增加小数码管的间隔,用time库获取系统当前时间,增加年月日的标记,年月日颜色不同

import turtle,time
def drawGap(): #绘制数码管间隔
    turtle.penup()
    turtle.fd(5)
def drawLine(draw):  #绘制小段数码管
    drawGap() #调用drawGap函数,绘制数码管间隔
    turtle.pendown() if draw else turtle.penup() #如果参数是draw就落笔,否则起飞
    turtle.fd(40)
    drawGap()
    turtle.right(90)
    #如果是drawLine(True)是不是就可以执行函数呢?是的
def drawDigit(digit): #根据数字绘制七段数码管
    drawLine(True) if digit in [2,3,4,5,6,8,9] else drawLine(False) #如果参数在[]中,True,执行drawLine函数,否则不执行
    drawLine(True) if digit in [0,1,3,4,5,6,7,8,9] else drawLine(False)
    drawLine(True) if digit in [0,2,3,5,6,8,9] else drawLine(False)
    drawLine(True) if digit in [0,2,6,8] else drawLine(False)
    turtle.left(90) #在drawLine函数中有turtle.right(90),每画一次都会拐个弯
    drawLine(True) if digit in [0,4,5,6,8,9] else drawLine(False)
    drawLine(True) if digit in [0,2,3,5,6,7,8,9] else drawLine(False)
    drawLine(True) if digit in [0,1,2,3,4,7,8,9] else drawLine(False)
    turtle.left(180)
    turtle.penup() #为绘制后续数字确定位置
    turtle.fd(20)
def drawDate(date):  #data为日期,格式为 '%Y-%m=%d+'
    turtle.pencolor("red")
    for i in date:
        if i == '-':
            turtle.write("年",font=("Arial",18,"normal"))  #用turtle.write()写汉字,先字体再字号
            turtle.pencolor("green")  #在'-'后面的颜色变为绿色
            turtle.fd(40)
        elif i == '=':
            turtle.write("月",font=("Arial",18,"normal"))
            turtle.pencolor("blue")
            turtle.fd(40)
        elif i == '+':
            turtle.write("日",font=("Arial",18,"normal"))
        else:
            drawDigit(eval(i))   #注意要用eval()去掉最外面的引号
def main():
    turtle.setup(800,350,200,200)
    turtle.penup()
    turtle.fd(-300)
    turtle.pensize(5)
    drawDate(time.strftime('%Y-%m=%d+',time.gmtime())) #获取当前时间,并转为计算机程序可处理的时间格式
    turtle.hideturtle()
    turtle.done()
main()

举一反三理解方法思维,模块化思维:确定模块接口,封装功能;规则化思维:抽象过程为规则,计算机自动执行(每个数字都走了7条线,用参数控制是绘 制/飞过去不绘制);化繁为简:将大功能变为小功能组合。应用问题拓展:带小数点的七段数码管、带刷新的时间倒计时效果。

代码复用的两种形式:函数对象。函数将代码命名,在代码层面建立了初步抽象;对象通过属性和方法<a>.<b> 和 <a>.<b>(),在函数之上再次组织进行抽象,抽象级别变高。

模块化设计:通过函数或对象,封装,将程序划分为模块及模块间的表达。具体包括:主程序、子程序和子程序间关系。模块化设计要求紧耦合、松耦合:模块内部紧耦合、模块之间松耦合(模块内通过局部变量进行大量传输,函数间尽可能减少传递参数和返回值,才能使代码尽可能复用)。

递归一个函数调用自己函数+分支结构(if + else),分支结构判断递归链条和递归基例(一个或多个不需再次递归)。递归在数学中的高大上表达:数学归纳法.

递归的调用过程:把函数的定义理解为一个模板,计算机对赋予的参数去运算时,会将函数的模板拷贝一份,放到计算机的某一个位置,用实际给定的参数去运算;若运算过程中又遇到一个函数,会在计算机中再开辟一个新内存,再运算。这样就可以不断调用程序自身。函数定义的过程调用的是自身,但函数执行的过程调用的是不同自身代码的复制版本

例:计算n! 

def fact(n):
    if n == 0:
        return 1
    else:
        return n*fact(n-1)
print(fact(5))   #结果为120

第一次循环:n = 5 返回值:5 * foo(5-1)
第二次循环:n = 4 返回值:5 * 4 * foo(4-1)
第三次循环:n = 3 返回值:5 * 4 * 3 * foo(3-1)
第四次循环:n = 2 返回值:5 * 4 * 3 * 2 foo(2-1)
第五次循环:n = 1 返回值:5 * 4 * 3 * 2 * 1 = 120

例:字符串反转后输出

>>>s[::-1] :字符串s从最开始到最后采用-1的步长进行输出,-1的步长就是指从后向前依次取出

分析:函数+分支结构(链条,基例),基例:空字符串,链条:将首字符放到其余字符最后

def rvs(s):
    if s == "":
        return s
    else:
        return rvs(s[1:])+s[0]

例:斐波那契数列

def f(n):
    if n == 1 or n == 2:
        return 1
    else:
        return f(n-1)+f(n-2)

例:汉诺塔问题(递归的经典案例)

若干不同颜色不同大小圆圈,3根柱子,每次移动一个盘子,但要使得3个柱子都是从小到大排列,龙卷风。如果只有123盘子,把23当作一个整体,若有1234盘子,把234当作一个整体。要解决上面n-1个盘子的移动,就要解决上面n-2个盘子的移动…变成一个盘子移动的问题,递归。

递归链条的分析:将n个圆盘从A柱搬到C柱:先将n-1个圆盘从A搬到B,将最后一个圆盘搬到C;再将B柱中的n-1个圆盘挪到C柱上。总之:把n个圆盘化解为n-1个圆盘的搬运,n-1个圆盘怎么搬呢?递归过程只关系递归链条,只关心当圆盘数量为n时,怎么拆解为当前与当前n-1之间的关系

位置函数:函数的参数是由位置决定的 。注:后面else中的递归hanoi的参数位置与函数定义hanoi的参数位置有关。

count = 0
def hanoi(n,src,dst,mid):  #有n个圆盘,3根柱子:源柱子,目的柱子,中间过渡柱子
    global count #为了计算每一次移动圆盘的步骤,定义全局变量,递归函数本身也是函数,若内部变量不是全局变量,再每次调用时初值都是被清零
    if n == 1:
        print("{}:{}->{}".format(1,src,dst))
        count += 1 #每次移动圆盘时对全局变量加一
    else:
        hanoi(n-1,src,mid,dst) #位置函数,把n-1个圆盘从源柱子搬到中间柱子上 src---mid,借由目的柱子
        print("{}:{}->{}".format(n,src,dst)) #等价于 hanoi(1,src,dst,mid) 把源柱子上最底层的一个移动到目的柱子,src---dst
        count += 1
        hanoi(n-1,mid,dst,src)#将n-1个圆盘从之前的中间柱子搬运到目标柱子上 mid---dst

hanoi(3,"A","C","B") 
print(count)    
1:A->C
2:A->B
1:C->B
3:A->C
1:B->A
2:B->C
1:A->C
7

PyInstaller库

第三方库,将扩展名为.py的源代码转换成无需源代码的可执行文件,系统上可能没有安装python的IDLE或者解释器,将源程序先编译或者打包成一个可以直接执行的程序。

PyInstaller是命令行的执行程序,不是python执行指令。以七段数码管为例(SevenDigitDraw),打开cmd,在源代码目录下, pyinstaller -F<文件名.py> ,生成3个新的目录:__pycache__和build可删除,dist文件中有一个与原文件同名的exe文件,鼠标双击,执行程序。

PyInstaller库常用参数:例:对一个源代码文件关联一个图标(curve.ico),并进行打包。pyinstaller -i curve.ico -F SevenDigitsDrawV2.py,会产生一个包含预定图标的可执行文件。

注:只有在打包过程的计算机中,需安装PyInstaller库,打包后的程序(.exe)发给朋友可直接执行

 

实例8 科赫雪花小包裹

分形几何:整体与局部具有很强的相似性,分形几何中有一种特殊的曲线:科赫曲线(雪花曲线)

 分析:递归思想:函数+分支  递归链条:线段的组合   递归基例:初识线段

#绘制科赫曲线
import turtle
def koch(size,n):  #线段长度size,阶数n
    if n == 0:
        turtle.fd(size) #绘制一条直线,不需要return
    else:               #将一条直线分为3段,中间段去掉,再进一阶:把其中每一个线段做下一次科赫曲线绘制
        for angle in [0,60,-120,60]:
            turtle.left(angle)
            koch(size/3,n-1) #!为n-1
def main():
    turtle.setup(800,400)
    turtle.penup()
    turtle.goto(-300,-50)
    turtle.pendown()
    turtle.pensize(2)
    koch(600,3)         #3阶科赫曲线
    turtle.hideturtle() #将海龟本身进行隐藏
main()

#绘制科赫小雪花
import turtle
def koch(size,n):  #线段长度size,阶数n
    if n == 0:  #基例 n为0,而非1
        turtle.fd(size) #绘制一条直线
    else:               #将一条直线分为3段,中间段去掉,再进一阶:把其中每一个线段做下一次科赫曲线绘制
        for angle in [0,60,-120,60]:
            turtle.left(angle)
            koch(size/3,n-1)
def main():
    turtle.setup(600,600)
    turtle.penup()
    turtle.goto(-200,100)
    turtle.pendown()
    turtle.pensize(2)
    level = 3     #3阶科赫雪花
    koch(400,level)
    turtle.right(120)
    koch(400,level)
    turtle.right(120) #若绘制的不是科赫曲线,则是等边三角形
    koch(400,level)
    turtle.hideturtle() #将海龟本身进行隐藏
main()

举一反三:修改绘制阶数、修改科赫曲线旋转角度、修改科赫雪花的基础框架图形;康托尔集、谢尔宾斯基三角形、门格海绵…龙形曲线、空间填充曲线、科赫曲线等分形几何



组合数据类型及操作

集合类型:创建---{ }和set(),操作有交(&)、并(|)、差(-)、补(^)、比较(>=<),方法有 .add( )、   .discard( )、.pop( ),应用于包含关系比较、数据去重

序列类型:包括字符串、元组和列表。元组,创建---( )和tuple( ),操作同序列操作。列表,创建---[ ]和list( ),操作---在序列操作基础上增删改

字典类型:映射关系用键值对表达,创建---{ }和dict( ),键值对间用:分隔;d[key]可以索引,也可赋值;一批操作方法和函数,重点.get( )

集合类型:元素无序,每个元素唯一,不存在相同类型;元素不可更改,不可变数据类型。(因为集合中元素是独一无二,若改变后可能会与其他元素相同)集合用大括号{ }表示,元素间用逗号分隔;建立集合类型用{ }或set( );建立空集合,必须用set( )

>>> ls = set("123") #使用set()函数创建集合类型,要在()中添加“”,不需要间隔,其中的,也会当作元素
{'2', '1', '3'}
>>> ls = set("1,2,3")
{',', '1', '3', '2'}
>>> B = set("pypy123")   #使用set()建立集合
{'3', 'y', 'p', '1', '2'}   #把相同的元素删除,元素不是按定义的顺序,因为集合无序
>>> A = {"python",123,("python",123)}  #使用{}建立集合
{('python', 123), 123, 'python'}
>>> C = {"python",123,"python",123}
{123, 'python'}

集合操作符

>>> A = {"p","y",123}
>>> B = set("pypy123")
>>> A - B
{123}
>>> B - A
{'3', '1', '2'}
>>> A&B
{'p', 'y'}
>>> A|B
{'3', 'y', 'p', '1', 123, '2'}
>>> A^B
{'3', '1', '2', 123}

集合类型处理函数+方法:(方法=变量+“.”称为.xxx方法)10个

 

>>> A = {"p","y",123}
>>> for item in A:
	print(item,end="")
123yp
>>> A
{123, 'y', 'p'}

A = {"p","y",123}
try:
    while True:  #程序不断运行,看似形成了一个死循环
        print(A.pop(),end="")   #但A中元素不存在时,会产生异常,会被try-except捕捉到,正常退出
except:
    pass
123yp
>>>A
set()  #程序运行结束后,A为空集合

注:使用for in 循环,返回获得的元素也不确定,可能与定义的顺序不同。(其实一个集合类型定义生成后,内部是有顺序的,但这个顺序对于程序员来讲,是无法利用的,是程序内部保存集合时所运用的一种顺序)

集合类型的应用场景包含关系比较,比较一组数据是否在这个数据中;数据去重,集合类型所有元素无重复

>>>"p" in {"p","y",123}
 True
>>>{"p","y"} >= {"p","y",123}
 False

>>>ls = ["p","p","y","y",123]
>>>s = set(ls)  #set()函数,将列表转为集合(也可逐一比较判断是否相同,但太复杂)
{123, 'y', 'p'}
>>>lt = list(s)  #list()函数,可将集合类型转为列表类型
[123, 'y', 'p']

序列类型 :是一组有先后关系的元素,元素间由序号引导,通过下标访问序列的特定元素,可正向/反向递增/减序号。序列是一个基类类型,包括字符串类型、元组类型、列表类型

序列类型的操作符、函数和方法

 

ls = ["python",123,".io"]
ls[::-1]
Out[13]: ['.io', 123, 'python']

s = "python123.io"
s[::-1]
Out[15]: 'oi.321nohtyp'
ls = ["python",123,".io"]
len(ls)
Out[17]: 3

s = "python123.io"
max(s)     #获得序列中最大的元素,字符串序列中,每个元素都是字符,字符间的比较是按照字母序比较
Out[19]: 'y'

元组类型:是一种序列类型,一旦创建不能修改;用小括号()/tuple()创建元素间用逗号分隔可用或不用小括号。 如def func(): ;return 1,2  返回的1,2就是一个元组

>>>creature = "cat","dog","tiger","human"  #元组可以没有括号
>>>creature
('cat', 'dog', 'tiger', 'human')
>>>creature[::-1]    #新创建一个元组
('human', 'tiger', 'dog', 'cat')

>>>color = (0x001100,"blue",creature)
>>>color
(4352, 'blue', ('cat', 'dog', 'tiger', 'human'))
>>>color[-1][2]    #元组color的[-1]是creature元组,creature元组[2]是tiger
'tiger'

列表类型:是一种序列类型,创建后能随意修改;用方括号[ ]/list()创建元素间用逗号分隔列表中元素类型可不同,无长度限制。如果使用[]或list,真正创建了一个列表,若仅使用=赋值,它只是将一段列表赋给了一个新的名字,相当于重命名 

列表类型的函数或方法

 列表中的函数/方法会作用到列表本身,删除列表元素:del ls[i]、  ls.pop(i)、  ls.remove(x)。

>>> ls = ["cat","dog","tiger",1024]
>>> ls[1:2] = [1,2,3,4]
['cat', 1, 2, 3, 4, 'tiger', 1024]
>>> del ls[::3]   #删除步长为3的元素,即删除0、3、6
[1, 2, 4, 'tiger']
>>> ls * 2     #列表中的函数/方法会作用到列表本身
[1, 2, 4, 'tiger', 1, 2, 4, 'tiger']
>>> ls = ["cat","dog","tiger",1024]
>>> ls.append(1234)
['cat', 'dog', 'tiger', 1024, 1234]
>>> ls.insert(3,"human")
['cat', 'dog', 'tiger', 'human', 1024, 1234]
>>> ls.reverse()
[1234, 1024, 'human', 'tiger', 'dog', 'cat']

列表功能默写 

序列类型应用场景:元组tp用于元素不改变的应用场景,如函数return;列表ls更灵活,使最常用的序列类型。主要作用:表示一组有序数据,进而操作它们。元素遍历:for item in ls:;<语句块>、or item in tp:;<语句块>。     数据保护:不希望数据被程序所改变,转换为元组类型

>>> ls = ["cat","dog","tiger",1024]
>>> lt = tuple(ls)  #定义为元组类型
>>> lt
('cat', 'dog', 'tiger', 1024)

实例9:“基本统计值计算”问题:求和、平均值、方差、中位数

给出一组数据,求总个数len()、求和:for…in、平均值:求和/总个数、方差:各数据与平均数差的平方的和的平均数、中位数:排序,奇数找中间1个,偶数找中间2个取平均。

与pandas数据的.describle()方法效果类似,注:print的槽机制.format( )中可以直接调用函数。sorted()函数.sort方法可以对列表进行排序

def getNum():   #获得用户不定长度的输入
    nums = []
    iNumStr = input("请输入数字(回车退出):")
    while iNumStr != "":
        nums.append(eval(iNumStr))
        iNumStr = input("请输入数字(回车退出):")
    return nums
def mean(numbers):  #计算平均数
    s = 0.0
    for num in numbers:
        s += num
    return s / len(numbers)
def dev(numbers,mean):    #计算方差
    sdev = 0.0
    for num in numbers:
        sdev = sdev + (num - mean)**2
    return pow(sdev / (len(numbers)-1),0.5)
def median(numbers):  #计算中位数
    sorted(numbers)   #sorted函数可以对列表进行排序,计算中位数要先排序
    size = len(numbers)
    if size % 2 == 0: #这里要用%,判断有没有余数来判断奇偶个数,后面要用//
        med = (numbers[size//2-1] + numbers[size//2])/2  #要注意numbers[]是从0开始的,在找中位数时要注意位置
    else:
        med = numbers[size//2]  #//整数除法,即商
    return med

n = getNum()
m = mean(n)
print("平均值:{},方差:{:.2},中位数:{}".format(m,dev(n,m),median(n)))
请输入数字(回车退出):1
请输入数字(回车退出):2
请输入数字(回车退出):3
请输入数字(回车退出):4
请输入数字(回车退出):5
请输入数字(回车退出):6
请输入数字(回车退出):7
请输入数字(回车退出):8
请输入数字(回车退出):9
请输入数字(回车退出):
平均值:5.0,方差:2.7,中位数:5

举一反三:从控制台获取多个不确定数据数据(while),模块化设计方法(分隔多个函数),充分利用python提供的内容函数(排序:sorted函数,个数:len函数,平方根/开平方:pow函数

理解“映射”:是一种键和值的对应,序列类型由0…N整数作为数据的默认索引(["python",123,".io"]),映射类型由用户为数据自定义索引(内部颜色:蓝色),数据组织与表达的新的形态,字典类型是“映射”的体现。

字典:键值对的集合,键值对之间无序,键是数据索引的扩展;采用大括号{}dict创建,键值对用表示,元素间用分隔,字典变量= {<键1>:<值1>,<键2>:<值2>,…<键3>:<值3>}

<值>=<字典变量>  [键]       <字典变量>[键]=<值>  ,d[key]用来向字典变量中索引或增加元素

在集合类型中,生成空集合不能用空{}的方式只能用set()函数,因为空{}默认生成字典类型。函数type(x):返回变量x的类型。创建字典时,若相同键有不同值,字典采用最后一个"键值对"。

>>> d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>> d["中国"]
'北京'
>>> de = {};type(de)
<class 'dict'>

字典类型的函数或方法

注:方法.keys()和.values()和.items( )不返回列表类型,返回字典的key类型或values类型,可用for in 的方式做遍历,但不能当列表类型来操作。如 for nation,capital in d.items() 遍历字典中的每一个键值对,并赋值给键和值的变量nation,capital。如果只用for i in d:只会返回键(国家)

.get( )方法重要,两种用法:1.( )中只有1个元素---判断键是否在字典中返回True/False。2.( )中有2个元素,若第一个元素不是字典的键,通过get返回的第二个值赋给字典的键,得到一个新的键值对,常用于计数!若要增加键值对,直接字典名["键"] = "值"

d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
d['澳大利亚'] = d.get('澳大利亚','有趣')
print(d)
#{'中国': '北京', '美国': '华盛顿', '法国': '巴黎', '澳大利亚': '有趣'}

字典转为列表时,一定要记得用方法.items()

>>> d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>> "中国" in d
True
>>> d.keys()
dict_keys(['中国', '美国', '法国'])
>>> d.values()
dict_values(['北京', '华盛顿', '巴黎'])
>>>d["韩国"] = "首尔"
{'中国': '北京', '美国': '华盛顿', '法国': '巴黎', '韩国': '首尔'}
>>>d.items()
dict_items([('中国', '北京'), ('美国', '华盛顿'), ('法国', '巴黎'), ('韩国', '首尔')])
>>>list(d)
['中国', '美国', '法国', '韩国']
>>> list(d.items())
[('中国', '北京'), ('美国', '华盛顿'), ('法国', '巴黎'), ('韩国', '首尔')]
>>> d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>> d.get("中国","伊斯兰堡") #以中国为键,获得d中对应的值,若不是字典d中的索引就返回伊斯兰堡
'北京'
>>> d.get("巴基斯坦","伊斯兰堡")
'伊斯兰堡'
>>> d.popitem()   #从字典d中随机获取一个键值对,以元组形式表达
('法国', '巴黎')

字典类型应用场景:映射的表达,如统计数据出现的次数,数据为键,次数是值。元素遍历:for k in d: <语句块>

例:读入一个字典类型的字符串,反转其中键值对输出

示例{"a": 1, "b": 2},输出{1: 'a', 2: 'b'}

s = input()
try:
    d = eval(s)
    e = {}
    for k in d:  #字典的单纯遍历,只会返回字典的键,即k=a,b
        e[d[k]] = k 
    print(e) 
except:
    print("输入错误")

例:输出一个字符串中出现最多的人名(包含了含有重复的人名)。

counts = { } 

counts['fortune'] = counts.get('fortune',0) + 1 = 1       counts = { 'fortune':1} 

counts['the'] = counts.get('the',0) + 1 = 1                   counts = { 'fortune':1,'the':1} 

counts['the'] = counts.get('the',0) + 1 = 1+1=2           counts = { 'fortune':1,'the':2} 

words = ['fortune','the','who','who','the','are','the']
counts = {}
for word in words:
    counts[word] = counts.get(word,0) + 1
print(counts)
{'fortune': 1, 'the': 3, 'who': 2, 'are': 1}

jieba库

优秀的中文分词第三方库,中文文本需要通过分词获得单个的词语(确定中文字符之间的关联概率,概率大的组成词组形成分词结果,用户可自定义添加词组);需额外安装(在cmd命令行输入pip install jieba,需在联网状态);提供三种分词模式,最简单只需掌握一个函数。

精确模式:把文本精确切分开,不存在冗余单词。最常用

全模式:把文本中所有可能的词语都扫描出来,有冗余。不同的角度来切分,变成不同的词语

搜索引擎模式:在精确模式基础上,对长词再次切分。更智能

jieba库常用函数  jieba.lcut(s)

实例10:文本词频统计

英文文本:Hamet  分析词频 https://python123.io/resources/pye/hamlet.txt

中文文本:《三国演义》分析人物出场次数  https://python123.io/resources/pye/threekingdoms.txt

1、文本噪音处理、归一化,大小写、单词间的:,!等符号.replace,.split方法分隔为列表words

2、建立空字典counts,单词和频次的映射,for in循环 + 字典的.get()方法获得所有单词及频次

3、转为列表items,sort函数的高级用法进行词频排序,for in循环输出前几的单词及词频

open("hamlet.txt","r").read()    #打开Hamlet文件+.read()方法

items.sort(key=lambda x:x[1],reverse=True)     #用.sort()方法进行排序,lambda函数:lambda +参数 + :+  函数体,用于定义简单的、能在一行内表示的函数,该代码中用来指定列表中使用哪一个多元选项的列作为排序列;默认排序为从小到大,reverse=True返回的排序为从大到小。

for word in words: counts[word] = counts.get(word,0) + 1 #相当于新增键值对, 若返回word,返回的是word键对应的值。

print("{0:<10}{1:>5}".format(word,count))  #:后面数字---输出宽度,出现.---精度,出现,---千位分隔符,出现><^---对齐,出现字母---类型。

def getText(): #归一化处理
    txt = open("hamlet.txt","r").read()  #打开文件的方法 open("","r").read()
    txt = txt.lower() #将所有英文字符变成小写
    for ch in '!"$%&()*+,-./:;<=>?@[\\]^_{|}~': #for in的方式去掉文本中各种特殊符号
        txt = txt.replace(ch,"")  #用replace方法将特殊符号替换为空格
    return txt

hamletTxt = getText()
words = hamletTxt.split()  #.split方法默认用空格对字符串进行分隔,并以列表的形式返回变量,里边的每个元素就是空格分开的单词
counts = {} #单词与出现次数——映射,构建字典类型
for word in words:
    counts[word] = counts.get(word,0) + 1 #判断元素word(键)是否在counts中,字典的.get()方法获得键对应的值/给出默认值,在里边返回次数+1,若不在字典中就加到字典中并赋值为0  
items = list(counts.items()) #将字典类型转为列表类型便于操作,.items()方法返回字典中所有的键值对
items.sort(key=lambda x:x[1],reverse=True)  #用.sort()方法进行排序,lambda函数
for i in range (10):
    word,count = items[i]
    print("{0:<10}{1:>5}".format(word,count))
    
the        1137
and         963
to          736
of          669
you         546
i           540
a           527
my          513
hamlet      459
in          435

word,count = items[i],注意是列表中的一个元素返回两个值,而不是字典

《三国演义》人物出场统计(上)将词频与人物相关联,面向问题

import jieba
txt = open('threekingdoms.txt','r',encoding='utf-8').read()
words = jieba.lcut(txt) #分词处理,形成带所有单词的列表类型,jieba库可以不用删除特殊符号
counts = {}
for word in words:
    if len(word) == 1:
        continue  #结束循环,如果是单个的词就结束本轮循环,如曰,吾,也,标点符号等
    else:
        counts[word] = counts.get(word,0) + 1
items = list(counts.items()) #一定要记得字典转为列表时,要用方法.items()
items.sort(key = lambda x:x[1],reverse = True)
for i in range(15):
    word,count = items[i]
    print("{0:<10}{1:>5}".format(word,count))
曹操          953
孔明          836
将军          772
却说          656
玄德          585
关公          510
丞相          491
二人          469
不可          440
荆州          425
玄德曰         390
孔明曰         390
不能          384
如此          378
张飞          358

但结果中“孔明”和“孔明曰”实际上是一个人,只是由于分词的原因,将其做为两个不同的单词;“二人”和“却说”不是人名而是单词的组合,要给出排除词库

《三国演义》人物出场统计

import jieba
txt = open('threekingdoms.txt','r',encoding='utf-8').read()
excludes = {"将军","却说","荆州","二人","不可","不能","如此"} #确定不是人名,排序靠前的单词列进去,不断运行程序根据结果
words = jieba.lcut(txt)
counts = {}
for word in words:
    if len(word) == 1:
        continue
    elif word == '诸葛亮' or word == '孔明曰': #人名的关联
        rword = '孔明'
    elif word == '关公' or word == '云长':
        rword = '关羽'
    elif word == '玄德' or word == '玄德曰':
        rword = '刘备'
    elif word == '孟德' or word == '丞相':
        rword = '曹操'
    else:
        rword = word
    counts[rword] = counts.get(rword,0) + 1
for word in excludes:
    del counts[word]
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(10):
    word,count = items[i]
    print("{0:<10}{1:>5}".format(word,count))
曹操         1451
孔明         1383
刘备         1252
关羽          784
张飞          358
商议          344
如何          338
主公          331
军士          317
吕布          300

文本词频统计举一反三:其他书籍,对政府工作报告、科研论文、新闻报道…进一步,绘制词云有更直观的展示效果



文件的使用和数据可视化

文件使用方式:打开open()---操作 文件内容读取:.read()  .readline()  .readlines(),数据的文件写入:.write()   .writelines()  .seek() ---关闭.close()

数据维度:一维、二维、多维、高维。一维:表示 ---列表和集合,存储---空格、逗号、特殊符号分隔,处理 --- .split()方法和.join()方法二维:表示---列表类型,每个元素也是一个列表,CSV格式,逗号分隔表示一维,按行分隔表示二维,处理 --- for循环 + .split()和.join()

文件:是数据的抽象和集合,文件的展示形态有:文本文件和二进制文件。

文本文件:数据是由单一特定编码组成的,如UTF-8编码;由于存在编码,文本文件也被看成是存储着的长字符串(文本文件就是一个字符串),如txt文件、py文件

二进制文件:由0和1按特定方式组织,没有统一的字符编码,如png图片文件、avi视频文件。任何类型的文件都可以以二进制方式打开。

文件处理的步骤打开---操作---关闭

打开:a = open( , ) 文件从存储状态转为占用状态  关闭:a.close( )文件从占用状态转为存储状态

操作:1.读文件 a.read(size)  a.readline(size)   a.readlines(hint)     2.写文件 a.write(s)   a.writelines(lines)   a.seek(offset)

文件的打开

 

 文件的关闭

<变量名>.close( ),若程序中只有打开文件,没有调用close()关闭文件,程序运行过程中,文件始终都是打开状态,但当程序退出,python的解释器会自动关闭文件。

文件内容的读取:  打开文件.read() / for line in 打开文件

 

 

方法1:.read()读入全部信息,变成一个大的字符串,采用字符串的处理方法,直接, 但若文本文件体量很大,一次性将文件读入内存,会耗费很多时间和资源。方法2:.read(2)从文件中读入2个字节,对字节进行相关处理,只要读进来的信息不为空,就将持续处理下去,直到为空最后退出。对于分行存储的文件,逐行遍历:方法3:.readlines()为列表,列表中的每一个元素是一行。方法4:逐行读出大文件中的信息  for in 文件句柄

数据的文件写入 打开文件.write() / 打开文件.writelines() 

.write()必须写入字符串,而.writelines()必须写入的是全为字符串的列表

fo = open("output.txt","w+")
ls = ["中国","法国","美国"]
fo.writelines(ls)
fo.seek(0)
for line in fo:
    print(line)
fo.close()

>>>中国法国美国

实例11:自动轨迹绘制

问题分析:需要根据脚本来绘制图形,不是写代码而是写数据绘制轨迹。之前用turtle库绘制图形是通过程序写代码的方式绘制图形。而是写程序去读取数据,并根据数据来绘制轨迹。数据脚本是自动化最重要的第一步。要程序能自动化或模块化,设计相关的脚本或数据接口是很重要的过程。

基本思路:定义数据文件格式(接口)文件 —— 编写程序,根据文件接口解析参数绘制图形 —— 编制数据文件。数据接口定义非常具有个性色彩!只需要打开文本文件,不需要读取文件!

map函数是python的内嵌函数,作用是将第一个参数的功能作用于第二个参数的每一个元素。对一个列表或一个集合这种组合数据类型的每一个元素都执行一次第一个参数所对应的函数。map函数返回的数据类型是<class 'map'>,是iterators类型而不是list,要用list函数进行转换即可。

txt = open("001.txt","r")
for line in txt:
    line = line.replace("\n","")
    line = list(map(eval,line.split(",")))
    print(line)

#1,2,3,4,5   for in 后直接print(line)会有空行

#6,7,8,9,10

#1,2,3,4,5   for in 后,.replace("\n","")用空格代替换行符,print(line)
#6,7,8,9,10

#['1', '2', '3', '4', '5'] for in 后,.replace("\n",""),再用.split(",")将字符串分隔形成列表,print(line)
#['6', '7', '8', '9', '10'] 注意:因为是for循环,逐行遍历,所以每一行都会形成一个列表

#[1, 2, 3, 4, 5]
#[6, 7, 8, 9, 10]

#<map object at 0x000002D23D737CF8>  line = map(eval,line.split(","))
#<map object at 0x000002D23D737DD8>
#<class 'map'>

#[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]] datals.append(list(map(eval,line.split(","))))
import turtle as t
t.title('自动轨迹绘制')
t.setup(800,600,0,0)
t.pencolor("red")
t.pensize(5)
#数据读取
datals = []  #用列表存储读取的数据,列表中的每个元素都是一个小列表
f = open("data.txt")  #不需要运用.read()方法
for line in f:   #for in 文件句柄,形成列表,每个元素为每一行
    line = line.replace("\n","") #将换行符转换为空字符串,去掉换行
    datals.append(list(map(eval,line.split(",")))) #将一个字符串分隔成若干个字符串生成一个列表,map函数是python提供的内嵌函数,无需import可直接使用,作用是将第一个参数的功能作用于第二个参数的每一个元素
f.close()
#自动绘制
for i in range(len(datals)):
    t.pencolor(datals[i][3],datals[i][4],datals[i][5]) #datals[i][3]指获得当前datals的一个元素,并找到元素的第三个参数
    t.fd(datals[i][0]) #获取当前这一行中的第一个元素,表示行进距离,赋值给fd
    if datals[i][1]:  #如果datals[i][1]不等于0(是1),向右转,转向角度都是datals[i][2]
        t.right(datals[i][2])
    else:
        t.left(datals[i][2])

在python中若不知道变量是什么数据类型,可以用print(type(<变量>)),如print(type(line)),会显示<class 'str'>

if语句后直接加变量,而不是布尔什表达式:判断该变量是否为非空非0,若为空为0,返回False,执行else语句;若不为空不为0,返回True,执行if语句。编写程序时可直接写成         if datals[i][1] == 1:

a = 0
if a:
    print("123")
else:
    print("456")
>>>456

a = "I love you!"
if a:
    print("123")
else:
    print("456")
>>>123

举一反三:自动化思维(数据与功能分离,数据驱动的自动运行)接口化设计(设计一个清晰明了的格式化文件,使它与程序的交互变得容易,本例中用“,”分隔的数字)二维数据应用(应用维度 组织数据,二维数据最常用,本例中用二维列表表达数据文件,datals[i][3],简化程序与接口之间的操作关系) 扩展接口设计,增加更多控制接口;扩展功能设计,增加弧形等更多功能;拓展应用需求,发展自动轨迹绘制到动画绘制。

一组数据在组织过程中有一个重要概念——维度,线性方式?二维方式?

一维数据:由对等关系的有序或无序数据构成,采用线性方式组织,对应列表、数组和集合

二维数据:由多个一维数据构成,是一维数据的组合形式。表格是典型的二维数据,如2019年中国高校排行榜。其中表头可以是二维数据的一部分,也可以是二维数据之外的部分。

多维数据:由一维数据或二维数据在新维度上扩展形成,2016-2019年的排行榜,时间维度上扩展

高维数据:仅利用最基本的二元关系展示数据间的复杂结构,如键值对间有效组织表达更复杂的逻辑关系。

数据的操作周期:存储(数据存储格式) <-> 表示(数据类型) <-> 操作(与算法相关)

一维数据的表示:若数据间有序,使用列表类型,如ls = [3.1398,3.1349,3.1376];若数据间无序,使用集合类型,如st = {3.1398,3.1349,3.1376}。都可以用for in 循环遍历数据,进而对每个数据进行处理。

一维数据的存储:a.空格分隔,用一个或多个空格分隔进行存储,不换行,但数据中不能出现空格(否则无法判断空格在数据内部还是数据之间) 中国 美国 日本 b.逗号分隔,用英文半角逗号 中国,美国,日本 c.其他方式,需据数据特点定义,通用性较差  中国$美国$日本  

一维数据的处理:读出一个列表(.split()方法)、将一个列表写入 (.join()方法

.join()方法适用于元素为字符串的列表用特定格式将元素组织起来,形成字符串,与.writelines()方法相同,将元素全为字符串的列表变成字符串写入文件 

.read()方法读出列表,要先将字符串读出来,再用.split()方法变成列表

二维数据的表示二维列表。本身是一个列表,而列表中的每一个元素又是一个列表,其中每一个元素可以代表二维数据的一行或一列,若干行和若干列组织起来形成的外围列表构成了二维列表

使用两层for循环遍历每个元素:第一层for循环遍历列表的每个元素,每个元素又是一个列表,再一次for循环遍历其中的元素。外层列表中每个元素可以对应一行,也可以对应一列。

CSV:Comma-Separated Values 用逗号分割值的一种存储方式,国际通用的一二维数据存储格式,一般.csv扩展名;每行一个一维数据,采用逗号分隔,无空行;Excel和一般编辑软件都可以读入或另存维csv文件。

 二维数据的存储:按行存?按列存?都可以。一般索引习惯:获得ls二维列表类型中的一个数据,默认方法是先行后列,ls[row][column]。根据一般习惯,外层列表每个元素是一行,按行存(一个列表中的每一行作为大的列表类型中的一个元素,好处是达到一般的调用习惯,先行后列)

 二维数据的处理:读入、写入、逐一处理

 

wordcloud库

优秀的词云展示第三方库。以词语为基本单位,更加直观和艺术的展示文本。

安装:cmd命令行中输入 pip install wordcloud

w = wordcloud.WordCloud() 生成词云对象。使用库时,库是全小写的wordcloud,库中的具体词云是有大写有小写的WordCloud.它本身是一个对象 wordcloud.WordCloud()文本对应词云的对象。

w.generate()  加载文本

w.to_file()  输出图像

绘制词云三步:生成一个对象 ---- 加载文本 ---- 输出图片

import wordcloud
c = wordcloud.WordCloud() #生成一个词云对象赋给变量c
c.generate("wordcloud by Python") #将一段文本加载到词云中
c.to_file("pywordcloud.png") #将词云效果输出到png文件中,图片宽度默认400像素,高度为200像素

 文本变词云,wordcloud库的作用分隔,以空格为分割符号将文本分割(3个单词)--- 统计过滤,统计单词出现次数并过滤,次数多显示词云效果的字体大,将只有1到2个字母和字符的单词过滤 --- 字体,根据统计配置字号 --- 布局,颜色环境尺寸。

不需要对文本的单词数量进行统计,词云自己会做;不需要对文本单词进行分割,只需要给wordcloud库一个由空格分隔的大字符串。

配置对象参数

import wordcloud
txt = "life is short,you need python"
w = wordcloud.WordCloud( \
        background_color = "white")
w.generate(txt)
w.to_file("pywcloud.png")

 

用中文形成词云时,需先对中文文本进行分词,并组成空格分隔的字符串(jieba.lcut()生成列表)

w.generate(" ".join(jieba.lcut(txt)))  #将文本通过jieba.lcut()生成一个列表,用.join()方法将列表中的元素用空格字符串来分割构成一个长字符串(用空格将元素组织起来)长字符串赋给wordcloud对象

import jieba
import wordcloud
txt = "程序设计语言是计算机能够理解和\
识别用户操作意图的一种交互体系,它按照\
特定规则组织计算机指令,使计算机能够自\
动进行各种运算处理"
w = wordcloud.WordCloud( width=1000,\
    font_path="msyh.ttc",height=700)#指定高度、宽度、字体(微软雅黑)三个参数
w.generate(" ".join(jieba.lcut(txt))) #文本通过jieba.lcut()会生成一个列表,.join()方法用空格将元素组织起来
w.to_file("pywcloudd.png")

电脑上字体存放位置是C:\Windows\Fonts。若要下载新的字体:https://www.fontke.com/。注意,用wordcloud词云,不能将程序文件命名为wordcloud。可以将字体文件与程序文件放在相同文件夹中,或者绝对引用,绝对引用时要注意文中字体的文件名,可复制粘贴查看。

实例12:政府工作报告词云

需求:直观理解政府工作报告等政策文件,有效的展示词语

《决胜全面建成小康社会 夺取新时代中国特色社会主义伟大胜利》中国共产党第十九次全国代表大会上的报告      https://python123.io/resources/pye/新时代中国特色社会主义.txt 
《中共中央 国务院关于实施乡村振兴战略的意见》2018一号文件 中共中央 国务院
https://python123.io/resources/pye/关于实施乡村振兴战略的意见.txt

基本思路:1.读取文件、分词整理。2.设置并输出词云。3.观察结果,优化迭代

import jieba
import wordcloud
f = open('新时代中国特色社会主义.txt','r',encoding='utf-8')
t = f.read()
f.close()
ls = jieba.lcut(t) 
txt = " ".join(ls)
w = wordcloud.WordCloud(   font_path='msyh.ttc',\
    width=1000,height=700,background_color='white',\
    stopwords={'和','是','的','在'})  #参数stopwords中没有下划线,不需要的单词装在集合里
w.generate(txt) #注意txt不能加引号,否则加载的文本为“txt”字符串,而非txt文本
w.to_file('grwordcloud1.png')

最多出现的单词是发展、建设、制度、坚持、中国特色,可见新时代中国特色社会主义的论断是建立在我们坚持发展中国特色并进行制度建设的基础上。关心的重要问题是农村的建设问题、农业的发展问题和乡村的振兴问题,在这样的大问题中,又多次出现体系、服务、改革等相关字样。

import jieba
import wordcloud
f = open('新时代中国特色社会主义.txt','r',encoding='utf-8')
t = f.read()
f.close()
ls = jieba.lcut(t) 
txt = " ".join(ls)
w = wordcloud.WordCloud(   font_path='msyh.ttc',\
    width=1000,height=700,background_color='white',\
    stopwords={'和','是','的','在'},max_words=15) #限制词云展示单词数量
w.generate(txt) #注意txt不能加引号,否则加载的文本为“txt”字符串,而非txt文本
w.to_file('grwordcloud11.png')

更有形的词云,如果想生成五角星,需要提供一个背景是白色的五角星图片,要加载图片,需要引入一个库from imageio import imread imread方法能读取图片文件,并变成一个图片文件表达的内部变量。背景图片的画布一定要设置为白色,显示的形状区域不是白色。

import jieba
import wordcloud
from imageio import imread
f = open('关于做好2022年全面推进乡村振兴重点工作的意见.txt',encoding='utf-8').read()
ls = jieba.lcut(f)
' '.join(ls)
mask = imread('pkq2.png')
w = wordcloud.WordCloud(width=1000,height=700,background_color='white',\
    font_path='msyh.ttc',stopwords={'和','的','等'},mask=mask)
w.generate(txt)
w.to_file('2.png')

举一反三:wordcloud更多参数,扩展词云能力;设计一款属于自己特色词云风格(你的图片、你的头像来形成一个词云图形,修改背景色、字体)

f = open('latex.log')
s = 0
for line in f:
    line = line.replace('\n','')
    if len(line) == 0:
        continue
    else:
        s += 1
print('共{}行'.format(s))

注:line = line.replace('\n','')  与 if len(line) == 0: 作用的对象完全不同,前者只是把换行符去掉,后者是不管空行。若有一行是换行符,换行符在显示上是空行,但占内存,如果len(line) != 0



实例13 体育竞技分析

需求:“高手过招,只在毫厘之间”,毫厘是多少?如何科学分析体育竞技比赛?

输入:球员水平,输出:可预测的比赛成绩    计算思维:抽象 + 自动化的方式

模拟:抽象比赛过程 + 自动化执行N场比赛,当N越大结果越科学(不同队员的能力差值在比赛结果的显示中会变得收敛,收敛性即稳定性,给体育竞技带来可度量、可评价、可使用的结果)

比赛规则:双人击球比赛,A&B,回合制,5局3胜;开始时一方先发球,直至判分(一回合结束),接下来胜者发球;球员只能在发球局得分,15分胜一局。

自顶向下设计:解决复杂问题有效方法,将一个总问题表达为若干个小问题组成,分而治之,系统思维。

自底向上执行:逐步组建复杂系统的有效测试方法,分单元测试,逐步组装。模块化集成。

步骤:1.打印程序介绍性信息-printInfo()。2.获得程序运行参数:proA,proB,n(运动员能力信息,模拟次数)-getInputs()。3.利用球员A和B的能力值,模拟n局比赛-simNGames()。4.输出球员A和B获胜比赛的场次及概率-printSummary()。每个步骤可以自定义函数.

 

模拟n局比赛:作为一个总问题,分解为新问题:模拟一局比赛-simOneGame()并循环了n次。这个函数只需要获得选手A和B的能力值,并返回这一局比赛的分数。

模拟1局比赛:作为一个总问题,分析判断比赛结束,可封装成一个小模块。

结论:也许两个人的能力值只有微小的差距,但是竞争的结果会有非常大的悬殊。反过来,若比赛的胜负在微妙的变化,说明两位选手的能力值极其接近。

from random import random

def printIntro(): #介绍下内容,提高用户体验
    print("这个程序模拟两个选手A和B的某种竞技比赛")
    print("程序运行需要A和B的能力值(以0到1之间的小数表示)")
    
def getInputs():
    a = eval(input("请输入选手A的能力值(0-1):"))
    b = eval(input("请输入选手B的能力值(0-1):"))
    n = eval(input("模拟比赛的场次:"))
    return a,b,n

def printSummary(winsA,winsB):
    n = winsA + winsB
    print("竞技分析开始,共模拟{}场比赛".format(n))
    print("选手A获胜{}场比赛,占比{:0.1%}".format(winsA,winsA/n))
    print("选手B获胜{}场比赛,占比{:0.1%}".format(winsB,winsB/n))
    
def gameOver(a,b):
    return a==15 or b==15 #返回的是True或False
    
def simOneGame(probA,probB):#到底进行了多少个回合呢,不知道,用while循环
    scoreA,scoreB = 0,0
    serving = 'A' #从选手A开始罚球,用random函数生成随机变量,如果变量在A能力范围之内A获得1分,用这样的方式随机性表达A能力与A获得分数之间的关系
    while not gameOver(scoreA,scoreB):
        if serving == 'A':
            if random() < probA:
                scoreA += 1
            else:     #若超越A的能力范围,认为当前发球局换为B
                serving = 'B' 
        else:
            if random() < probB:
                scoreB += 1
            else:
                serving = 'A'
    return scoreA,scoreB 
    
def simNGames(n,probA,probB):#模拟n场比赛
    winsA,winsB = 0,0
    for i in range(n):
        scoreA,scoreB = simOneGame(probA,probB)
        if scoreA > scoreB:
            winsA += 1
        else:
            winsB += 1
    return winsA,winsB

def main():  
    printIntro() 
    probA,probB,n = getInputs()
    winsA,winsB =simNGames(n,probA,probB)
    printSummary(winsA,winsB)
    
main()
这个程序模拟两个选手A和B的某种竞技比赛
程序运行需要A和B的能力值(以0到1之间的小数表示)

请输入选手A的能力值(0-1):0.45

请输入选手B的能力值(0-1):0.55

模拟比赛的场次:1000
竞技分析开始,共模拟1000场比赛
选手A获胜229场比赛,占比22.9%
选手B获胜771场比赛,占比77.1%

举一反三:扩展比赛参数,增加对更多能力对比情况的判断;扩展比赛设计,增加真实比赛结果预测;扩展分析逻辑,反向推理,用胜率推算能力?



 

 

逻辑思维:靠数学推理形成公式来获得结果;计算思维:模拟运算过程并用计算机完成大量运算。计算思维基于计算机强大的算力及海量数据,抽象计算过程,关注设计和构造,而非因果;以计算机程序设计为实现的主要手段。

计算生态与python语言

以开源项目为代表的大量第三方库。python语言提供 > 15万个第三方库

库的建设经过野蛮生长和自然选择。同一个功能,有多个第三方库(如以网络爬虫为例,python早年提供了urlib2、urlib3等若干个第三方库,有一天有人提出了一个非常简单易懂的爬虫方法,叫封装成requests库,成为了爬虫领域非常标准常用的第三方库)

库之间相互关联使用,依存发展。python库间广泛联系,逐级封装。(在数据处理领域,python有一个非常基础的库Numpy,它在处理大数据时,可以达到跟C语言编程运行相当的效率,且Numpy的底层就是C语言编写的,接口是Python语言。正是由于Numpy搭好了非常高速、高效的数据处理能力,像Matplotlib、Pandas等一系列数据处理的第三方库都是基于Numpy来编写的上层功能)

社区庞大,新技术更迭迅速。(AlphaGo深度学习算法采用python语言开源)

API(应用程序编写接口)!=  生态  API是经过设计的产物,不是野蛮生长、发展出来的产物。(如微软操作系统,提供了很多Windows编程的API,通过调用这些函数来操作操作系统上的一些功能,但API是由一个人或组织通过顶层设计形成)

编程是一行一行的写代码——刀耕火种的编程模式,但在学习python语言要学会站在巨人的肩膀上去编写程序。编程的起点不是算法而是系统;编程如同搭积木,利用计算生态为主要模式(如在完成处理图片的应用需求,可找到 一个python第三方库,它能读取图片的信息,你去完成余下的工作即可);编程的目标是快速解决问题

优质的计算生态  http://python123.io 发布由老师及产业界人员共同筛选的优质的计算生态第三方库

实现功能  -> 关注体验,编程只是手段,不是目的,程序最终为人类服务。

提高用户体验的方法:1.进度展示(若程序需要计算时间,可能产生等待;程序由若干步骤,需提示用户;程序可能存在大量次数循环)2.异常处理(当获得用户输入,合规性检查;当读写文件,对结果进行判断;进行输入输出时,对运算结果进行判断)3.其他方法(打印输出,输出程序运行的过程信息;日志文件,对程序异常及用户使用进行定期记录;帮助信息,如体育竞技实例中有printIntro)

基本的程序设计模式:IPO、自顶向下、模块化(模块内紧耦合,模块间松耦合)、配置化(自动轨迹绘制,引擎+配置,程序执行与配置分离,关键在于接口设计)、应用开发四个步骤(产品定义—系统架构—设计与实现—用户体验)

全球的python社区PyPI > https://pypi.org/ 可搜索任何主题的python第三方库   Python Package Index(python包的索引)  实例:开发与区块链相关的程序。1.在pypi.org搜索blockchain 2.挑选适合开发目标的第三方库作为基础 3.完成自己需要的功能

(安装一批第三方库)。方法3:文件安装方法(安装特殊的第三方库)

第三方库的pip安装方法用python自带的pip安装工具。需要打开命令行(每个操作系统提供的命令行,而非IDLE的交互环境)输入pip -h可打出命令的帮助信息。

 

 

 主要安装方法,适合99%以上情况,需联网。

第三方库的集成安装方法:结合特定的python开发工具,批量安装一批库。

Anacoda https://www.continuum.io  支持近800个第三方库(只要下载安装Anaconda相关的开发程序,你的系统中就有了800个第三方库,可以使用它们而不需要安装)Anacoda安装环境中不只包含第三方库,还包含多种主流python开发工具;适合数据计算领域开发(数据分析、数据展示)。

第三方库的文件安装方法:为啥有些第三方库可以用pip下载,但安装过程会经常发生错误?因为一些第三方库提供的不是可执行的文件是第三方库的源代码,pip下载后,需要编译再安装。若操作系统没有编译环境,则能下载但不能安装。

UCI页面 http://www.lfd.uci.edu/~gohlke/pythonlibs/ 若发现用pip指令安装第三方库能下载但操作系统不具备编译环境,不能安装它,就可以利用网页提供的信息。(例,安装wordcloud库:1.在UCI页面上搜索wordcloud,2.下载对应版本文件 3.使用pip install <文件名>安装)

os库

提供通用的、基本的操作系统交互功能。是python的标准库,包含几百个函数

路径操作os.path子库以path为入口,用于操作和处理文件路径

import os.path 或 import os.path as op

 

 

import os
print(os.path.abspath('哈哈哈哈哈哈.txt')) #程序的绝对路径,文件不一定存在       F:\PYECourse\哈哈哈哈哈哈.txt
print(os.path.relpath('哈哈哈哈哈哈.txt')) #程序与文本的相对路径,文件不一定存在  哈哈哈哈哈哈.txt
print(os.path.exists('哈哈哈哈哈哈.txt'))  #判断是否存在文件或目录        False
print(os.path.isfile('哈哈哈哈哈哈.txt'))  #判断是否存在文件             False
print(os.path.isdir('F:\PYECourse'))     #判断是否存在目录              True

进程管理os.system(command) 通过调用cmd命令执行程序;在Windows系统中,返回值为cmd的调用返回信息。 所有要执行的命令以字符串的形式当作参数输入即可

import os
os.system("C:\\Windows\\System32\\calc.exe")
import os
os.system("C:\\Windows\\System32\\mspaint.exe\
          F:\\PYECourse\\wc_pkq.png")

 

环境参数:获取或改变系统环境信息

实例14:第三方库安装脚本

需求:批量安装第三方库需要人工干预,能都自动安装?如何自动执行一个程序?

 

 

 逐一取出第三方库的名称,并且用os.system( ) 里pip install <库名>逐一安装。

import os
libs = {'numpy','matplotlib','pillow','sklearn','requests',\
        'jieba','beautifulsoup4','wheel','networkx','sympy',\
        'pyinstaller','django','flask','werobot','pyqt5',\
        'pandas','pyopengl','pypdf2','docopt','pygame'}
try:
    for lib in libs:
        os.system("pip install " + lib)
    print("Successful")
except:
    print("Failed Somehow")

举一反三:自动化脚本+。编写各类自动化运行程序的脚本,调用已有程序;扩展应用,安装更多的第三方库,增加配置文件(引擎+自动化);扩展异常检测。



python计算生态 

python库之数据分析

Numpy:表达N维数组的最基础库。把n维数组看成简单的数据对象,可直接进行操作和运算。Pandas:python数据分析高层次应用库。操作索引即操作数据,扩展一维\二维数据的表示,简化数据分析运行,更高层次对数据操作。SciPy:数据、科学和工程计算功能库。

 

 

 

 python库之数据可视化

matplotlib:高质量的二维数据可视化功能库。Seaborn:统计类数据可视化功能库。Mayavi:三维科学数据可视化。

 

 

python库之文本处理

PyPDF2:用来处理pdf文件的工具集。NLTK:自然语言文本处理第三方库。Python-docx:创建或更新word文件

 

 

 python库之机器学习

Scikit-learn机器学习方法工具集。TensorFlow:AlphaGo背后的机器学习计算框架MXNet:基于神经网络的深度学习计算框架。

 

 

 

实例15:霍兰德人格分析雷达图

 

需求:雷达图方式验证霍兰德人格分析;输入:各职业人群结合兴趣的调研数据;输出:雷达图

霍兰德认为:人格兴趣与职业之间应有一种内在的对应关系。人格分类:研究型、艺术型、社会型、企业型、传统型、现实型。职业:工程师、实验员、艺术家、推销员、记事员、社会工作者。

通用雷达图绘制:matplotlib库,专业的多维数据表示:numpy

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.family'] = 'SimHei'
radar_labels = np.array(['研究型(I)','艺术型(A)','社会型(S)',\
                         '企业型(E)','常规型(C)','现实型(R)'])
data = np.array([[0.40,0.32,0.35,0.30,0.30,0.88],
                [0.85,0.35,0.30,0.40,0.40,0.30],
                [0.43,0.89,0.30,0.28,0.22,0.30],
                [0.30,0.25,0.48,0.85,0.45,0.40],
                [0.20,0.38,0.87,0.45,0.32,0.28],
                [0.34,0.31,0.38,0.40,0.92,0.28]])  #利用numpy中的array方法将多维数据组织起来
data_labels = ('艺术家','实验员','工程师','推销员','社会工作者','记事员')
angles = np.linspace(0,2*np.pi,6,endpoint=False)
data = np.concatenate((data,[data[0]]))
angles = np.concatenate((angles,[angles[0]]))
fig = plt.figure(facecolor='white')
plt.subplot(111,polar=True)
plt.plot(angles,data,'o-',linewidth=1,alpha=0.2)
plt.fill(angles,data,alpha=0.25)
plt.thetagrids(angles*180/np.pi,radar_labels,frac=1.2)
plt.figtext(0.52,0.95,'霍兰德人格分析',ha='center',size=20)
legend = plt.legend(data_labels,loc=(0.94,0.80),labelspacing=0.1)
plt.setp(legend.get_texts(),fontsize='large')
plt.grid(True)
plt.savefig('holland_radar.jpg')
plt.show()

举一反三:对于编程来讲,编写代码并不是重要的,重要的是要有编程的目标感编程的目标感寻找感兴趣的目标,寻(wa)(jue)之;编程的沉浸感:寻找可实现的方法,思(zuo)(mo)之;编程的熟练度:练习、练习、再练习,熟练之。

  • 10
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值