精华内容
下载资源
问答
  • Python语言中的缩进在程序中长度统一且强制使用,只要统一即可,不一定是4个空格(尽管这是惯例) IPO模型指:Input Process Output 字符串的正向递增和反向递减序号体系:正向是从左到右,0到n-1,反向是从右到左...

    测验1:Python基本语法元素

    知识点概要:

    • 普遍认为Python语言诞生于1991
    • Python语言中的缩进在程序中长度统一且强制使用,只要统一即可,不一定是4个空格(尽管这是惯例)
    • IPO模型指:Input Process Output
    • 字符串的正向递增和反向递减序号体系:正向是从左到右,0到n-1,反向是从右到左,-1到-n,举例
    str = "csdn" 
    #str[0]就表示字符串c, str[-1]表示"n"
    
    • Python的合法命名规则:命名包含字母,数字,下划线,但是首字符不能是数字
    • Python中获得用户输入的方式为:input()
    • Python中的保留字:type不是,是内置函数,def elif import 都是保留字
    • Python的数据类型有整数、列表、字符串等,但是不包括实数,实数是数学概念,在Python中对应着浮点数
    • 保留字if-elif-else用于表示分支结构,in用来进行成员判断
    • print()格式化输出,控制浮点数的小数点后两位输出应为:print("{:.2f}".format(XX)) :.2f哪一个都不能少

    编程测试:

    • Hello World 的条件输出:获得用户输入的一个整数,参考该整数值,打印输出"Hello World",要求:‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      如果输入值是0,直接输出"Hello World"‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      如果输入值大于0,以两个字符一行方式输出"Hello World"(空格也是字符)‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      如果输入值小于0,以垂直方式输出"Hello World"
    # eval()函数可以将默认输入的字符串去掉双引号并进行表达式运算,如输入500+20,默认
    #得到的输入为一个字符串“500+20”,但是使用eval()函数我们得到的是一个整型数字:520
    Number = eval(input())
    if Number == 0:
        print("Hello World")
    elif Number > 0:
        print("He\nll\no \nWo\nrl\nd")
    else:
        for c in "Hello World":
            print(c)
    
    • 数值运算:获得用户输入的一个字符串,格式如下:M OP N ,其中,M和N是任何数字,OP代表一种操作,表示为如下四种:+, -, *, /(加减乘除)‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬根据OP,输出M OP N的运算结果,统一保存小数点后2位。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      注意:M和OP、OP和N之间可以存在多个空格,不考虑输入错误情况。
    print("{:.2f}".format(eval(input())))
    

    测验2:Python基本图形绘制

    知识点概要:

    • 正确引用turtle库的方式:
    import turtle
    #t是别名,可以更换其他名称
    import turtle as t 
    from turtle import setup
    from turtle import *
    

    import setup from turtle是不正确的

    • turtle库是一个直观有趣的图形绘制函数库,最早成功应用于LOGO编程语言,turtle绘图体系以水平右侧为绝对方位的0度,turtle坐标系的原点****默认在屏幕正中间
    • turtle.circle(-90,90)表示绘制一个半径为90像素的弧形,圆心在小海龟当前行进的右侧
    # circle(x,y)表示以x长度为半径,y为角度,
    #当前方向左侧x处为圆心画圆,其中x,y都可以是负数,相应取反
    #当前方向是水平向右的,对应直角坐标系中的x轴正方向
    #x为正,则圆心在y轴正方向上,y为正,逆时针画圆,圆弧角度为y
    #x为负则相反,圆心在y轴负方向上,y为正,顺时针画圆,圆弧角度为y
    
    • turtle.seth(to_angle)函数的作用是设置小海龟当前行进方向为to_angle,to_angle是角度的整数值
    • turtle.fd(distance)函数的作用是向小海龟当前行进方向前进distance距离
    • turtle.pensize(size)函数的作用是改变画笔的宽度为size像素
    • turtle**.circle**()函数不能绘制椭圆形
    • turtle.circle(x,y)函数绘制半圆,第二个参数y是180的奇数倍
    • turtle.penup()的别名有turtle.pu(),turtle.up()
    • turtle.colormode()的作用是设置画笔RGB颜色的表示模式
    • turtle.width()和turtle.pensize()都可以用来设置画笔尺寸
    • turtle.pendown()只是放下画笔,并不绘制任何内容
    • 改变turtle画笔的运行方向有left()、right()和seth()函数,bk()只能后退,但是不改变方向
    • turtle.done()用来停止画笔绘制,但绘图窗体不关闭,建议在每个turtle绘图最后增加turtle.done()
    • 循环相关保留字是:for…in和while,def用于定义函数

    编程测试:

    • turtle八边形绘制:使用turtle库,绘制一个八边形
    import turtle as t
    t.pensize(2)
    for i in range(8):
        t.fd(100)
        t.left(45)
    
    • turtle八角图形绘制:使用turtle库,绘制一个八角图形
    import turtle as t
    t.pensize(2)
    for i in range(8):
        t.fd(150)
        t.left(135)
    

    测验3:基本数据类型

    知识点概要:

    • pow(x,0.5)能够计算x的平方根,计算负数的平方根将产生复数
    • 字符串.strip()方法的功能是去掉字符串两侧指定的字符
    • 字符串.split()方法的功能是按照指定字符分隔字符串为数组
    • 字符串.repalce()方法的功能是替换字符串中特定字符
    • +操作符用来连接两个字符串序列
    • 字符串是一个连续的字符序列,使用\n可以实现打印字符信息的换行
    • val = pow(2,1000)
      #返回val结果的长度值要使用 len(str(val)),因为整型没有len()方法,要通过str()函数
      #将数字类型转换为字符串
    • 正确引用time库的方式如下:
    import time
    from time import strftime
    from time import *
    
    • Python语言的整数类型表示十进制(一般表示)二进制(0b或0B开头)八进制(0o或0O开头)十六进制(0x或0X开头)
    • %运算符的意思是取余数
    • 字符串切片操作:s[N:M],从N到M,但是不包括M
    name="Python语言程序设计课程"
    print(name[0],name[2:-2],name[-1])
    #输出结果为:P thon语言程序设计 程
    
    • print("{0:3}".format('PYTHON'))代码执行的结果是PYTHON,{0:3}表示输出的宽度是3,但是如果字符串长度超过3就以字符串长度显示

    编程测试:

    • 平方根格式化:获得用户输入的一个整数a,计算a的平方根,保留小数点后3位,并打印输出。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬输出结果采用宽度30个字符、右对齐输出、多余字符采用加号(+)填充,‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬如果结果超过30个字符,则以结果宽度为准
    a = eval(input())
    print("{:+>30.3f}".format(a**0.5)) 
    # +是填充字符 >是右对齐 30是宽度 .3f是保留小数点后3位
    #若平凡根后是一个复数,复数的实部和虚部都是浮点数,.3f可以将实部和虚部分别取三位小数
    
    • 字符串分段组合:获得输入的一个字符串s,以字符减号(-)分割s,将其中首尾两段用加号(+)组合后输出
    InputStr = input()
    strs = InputStr.split('-')
    print(strs[0]+'+'+strs[-1])
    print("{}+{}".format(strs[0], strs[-1]))
    #s.split(k)以k为标记分割s,产生一个列表
    #通过该题目,掌握split()方法的使用,注意:k可以是单字符,也可以是字符串
    

    测验4:程序的控制结构

    知识点概要:

    • for…in…中in的后面需要的是一个迭代类型(组合类型),{1;2;3;4;5}不是Python的有效数据类型
    • range(x,y)
    for i in range(0,2):
    	print(i)
    #输出结果为:0 1
    
    • 程序的三种基本结构:顺序结构,循环结构和分支结构
    • 循环是程序根据条件判断结果向后反复执行的一种运行方式,是一种程序的基本控制结构,条件循环和遍历循环结构都是基本的循环结构,死循环能够用于测试性能,形式上的死循环可以用break来退出,例如
    x = 10
    while True:
    	x = x -1
    	if x == 1:
    		break
    
    • p = -p #表示给p赋值为它的负数,Python中的=是赋值符号
    • 缩进表达层次关系,同时用来判断当前Python语句在分支结构
    • continue结束当次循环,但是不跳出循环
    • random库中用于生产随机小数的函数是random(),而randint()/getrandbits()/randrange()都产生随机整数
    • 程序错误是一个大的概念,不仅指代码运行错误,更代表功能逻辑错误。使用异常处理try-excepy,可以对程序的异常进行捕捉和处理,程序运行可能不会出错,但逻辑上可能会出错

    编程测试:

    • 四位玫瑰数:四位玫瑰数是4位数的自幂数。自幂数是指一个 n 位数,它的每个位上的数字的 n 次幂之和等于它本身‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬
      例如:当n为3时,有1^3 + 5^3 + 3^3 = 153,153即是n为3时的一个自幂数,3位数的自幂数被称为水仙花数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‮‬‫
      请输出所有4位数的四位玫瑰数,按照从小到大顺序,每个数字一行
    #个人思路:求四位数的各个位数abcd
    for i in range(1000,10000):
        a = i%10
        b = (i//10)%10
        c = (i//100)%10
        d = (i//1000)%10
        if a**4 + b**4 + c**4 + d**4 == i:
            print(i)
    #参考答案:字符串+eval()
    s = ""
    for i in range(1000, 10000):
        t = str(i)
        if pow(eval(t[0]),4) + pow(eval(t[1]),4) + pow(eval(t[2]),4) + pow(eval(t[3]),4) == i :
            print(i)
    
    • 100以内素数之和:求100以内所有素数之和并输出‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      素数指从大于1,且仅能被1和自己整除的整数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬,提示:可以逐一判断100以内每个数是否为素数,然后求和
    sum = 0
    for i in range(2,100):
        isFlag = 1 #判断是否为素数
        for j in range(2,i): #遍历2-i-1,看是否能被i整除
            if i%j == 0: #被整除说明不是素数
                isFlag = 0
                break
        if isFlag == 1:
            sum += i
    print(sum)
    #参考答案:将判断是否为素数封装为一个函数,倾向于这种解题思路
    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)
    

    测验5:函数和代码复用

    知识点概要:

    • 函数作用:增强代码可读性、降低编程复杂度、复用代码,函数不能直接提高代码的执行速度
    • 全局变量与局部变量:函数的参数一般为局部变量,函数内使用global s 表示变量s为全局变量
    • 函数调用前必须已经存在函数定义,否则无法执行,Python内置函数直接使用,不需要引用任何模块
    • 模块内高耦合,模块间低耦合:高耦合的特点是复用较为困难,模块间关系应尽可能简单,模块之间耦合度低,尽可能合理划分功能块,功能块内部耦合度高
    • 递归不会提高程序的执行效率,任何递归程序都可以通过堆栈或队列变为非递归程序
    • 函数是一段具有特定功能的、可重用的语句组,可以看做是一段具有名字的程序,通过函数名来调用,同时不需要知道函数的内部实现原理,只需要知道调用方法(接口)即可
    • def func(*a,b):是错误的函数定义,*a表示可变参数,可变参数只能放在函数参数的最后,即def func(a,*b):
    • 函数可以包含0个或多个return语句
    • 每个递归函数至少存在一个基例,但可能存在多个基例,基例表示不再进行递归,同时决定了递归的深度

    编程测试:

    • 随机密码生成:以整数17为随机数种子,获取用户输入整数N为长度,产生3个长度为N位的密码,密码的每位是一个数字。每个密码单独一行输出,产生密码采用random.randint()函数
    import random
    def genpwd(length):
        a = 10**(length-1)
        b = 10**length - 1
        return "{}".format(random.randint(a, b))
    length = eval(input())
    random.seed(17)
    for i in range(3):
        print(genpwd(length))
    
    #思路类似,同样过了
    def genpwd(length):
        high = 10**length
        low = 10**(length-1)
        return random.randrange(low,high)
    
    • 连续质数计算:获得用户输入数字N,计算并输出从N开始的5个质数,单行输出,质数间用逗号,分割。
      注意:需要考虑用户输入的数字N可能是浮点数,应对输入取整数;最后一个输出后不用逗号
    def prime(m): #判断是否为质数
        for i in range(2,m):
            if m%i == 0:
                return False
        return True
        
    n = eval(input())
    if n != int(n): #考虑输入为浮点数的情况
        n = int(n) + 1
    else:
        n = int(n)   
        
    times = 0 #统计质数的次数
    res = [] #存放输出结果
    while times < 5:
        if prime(n):
            res.append(n)
            times += 1
        n += 1
    for i in res[:len(res)-1]:
        print(i,end=",")
    print(res[-1]) #最后一个不输出逗号
    
    #参考答案
    def prime(m):
        for i in range(2,m):
            if m % i == 0:
                return False
        return True
    #需要对输入小数情况进行判断,获取超过该输入的最小整数(这里没用floor()函数)
    n = eval(input())
    n_ = int(n)
    n_ = n_+1 if n_ < n else n_
    count = 5
    #对输出格式进行判断,最后一个输出后不增加逗号(这里没用.join()方法)
    while count > 0:
        if prime(n_):
            if count > 1:
                print(n_, end=",")
            else:
                print(n_, end="")
            count -= 1 
        n_ += 1
    

    测验6:组合数据类型

    知识点概要:

    • 列表ls,ls.append(x)表示只能向列表最后增加一个元素,如果x是一个列表,则该列表作为一个元素增加到ls中
    • 集合“交并差补”四种运算分别对应的运算符是:& | - ^
    • 字典d,d.values()返回的是dict_values类型,包括字典中的所有值,通常与for…in组合使用
    • Python的元组类型:元组采用逗号和圆括号(可选)来表示,一旦创建就不能修改,一个元组可以作为另一个元祖的元素,可用多级索引获取信息,序列类型(元组、列表)中的元素都可以是不同类型
    • 创建字典时,如果相同键对应不同值,字典采用最后一个"键值对"
    d= {'a': 1, 'b': 2, 'b': '3'}
    print(d['b'])
    #输出结果:3
    
    • 集合与字典类型最外侧都用{}表示,不同在于集合类型元素是普通元素,字典类型元素是键值对。字典在程序设计中非常常用,因此直接采用{}默认生成一个空字典
    • 对于字典d:x in d表示判断x是否是字典d中的键,键是值的序号,也是字典中值的索引方式
    • Python序列类型有:列表类型、元组类型、字符串类型(Python内置数据类型中没有数组类型)
    • 组合数据类型能够将多个相同类型或不同类型的数据组织起来,通过单一的表示使数据操作更有序、更容易
    • 组合数据类型可以分为3类:序列类型、集合类型和映射类型;
    • Python的字符串元组列表类型都属于序列类型,序列类型总体上可以看成一维向量,如果其元素都是序列,则可被当作二维向量
    • 对于序列s:s.index(x)返回序列s中元素x第一次出现的序号,并不返回全部序号

    编程测试:

    • 数字不同数之和:获得用户输入的一个整数N,输出N中所出现不同数字的和‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      例如:用户输入 123123123,其中所出现的不同数字为:1、2、3,这几个数字和为6
    #参考答案:字符串可以通过list()直接变成列表,或通过set()直接变成集合
    n = input()
    ss = set(n)
    s = 0
    for i in ss:
        s += eval(i)
        #s += int(i) #同样可以
    print(s)
    
    • 人名最多数统计:给出了一个字符串,其中包含了含有重复的人名,请直接输出出现最多的人名
    #先使用字典建立"姓名与出现次数"的关系,然后找出现次数最多数对应的姓名
    s = '''双儿 洪七公 赵敏 赵敏 逍遥子 鳌拜 殷天正 金轮法王 乔峰 杨过 洪七公 郭靖 
           杨逍 鳌拜 殷天正 段誉 杨逍 慕容复 阿紫 慕容复 郭芙 乔峰 令狐冲 郭芙 
           金轮法王 小龙女 杨过 慕容复 梅超风 李莫愁 洪七公 张无忌 梅超风 杨逍 
           鳌拜 岳不群 黄药师 黄蓉 段誉 金轮法王 忽必烈 忽必烈 张三丰 乔峰 乔峰 
           阿紫 乔峰 金轮法王 袁冠南 张无忌 郭襄 黄蓉 李莫愁 赵敏 赵敏 郭芙 张三丰 
           乔峰 赵敏 梅超风 双儿 鳌拜 陈家洛 袁冠南 郭芙 郭芙 杨逍 赵敏 金轮法王 
           忽必烈 慕容复 张三丰 赵敏 杨逍 令狐冲 黄药师 袁冠南 杨逍 完颜洪烈 殷天正 
           李莫愁 阿紫 逍遥子 乔峰 逍遥子 完颜洪烈 郭芙 杨逍 张无忌 杨过 慕容复 
           逍遥子 虚竹 双儿 乔峰 郭芙 黄蓉 李莫愁 陈家洛 杨过 忽必烈 鳌拜 王语嫣 
           洪七公 韦小宝 阿朱 梅超风 段誉 岳灵珊 完颜洪烈 乔峰 段誉 杨过 杨过 慕容复 
           黄蓉 杨过 阿紫 杨逍 张三丰 张三丰 赵敏 张三丰 杨逍 黄蓉 金轮法王 郭襄 
           张三丰 令狐冲 赵敏 郭芙 韦小宝 黄药师 阿紫 韦小宝 金轮法王 杨逍 令狐冲 阿紫 
           洪七公 袁冠南 双儿 郭靖 鳌拜 谢逊 阿紫 郭襄 梅超风 张无忌 段誉 忽必烈 
           完颜洪烈 双儿 逍遥子 谢逊 完颜洪烈 殷天正 金轮法王 张三丰 双儿 郭襄 阿朱 
           郭襄 双儿 李莫愁 郭襄 忽必烈 金轮法王 张无忌 鳌拜 忽必烈 郭襄 令狐冲 
           谢逊 梅超风 殷天正 段誉 袁冠南 张三丰 王语嫣 阿紫 谢逊 杨过 郭靖 黄蓉 
           双儿 灭绝师太 段誉 张无忌 陈家洛 黄蓉 鳌拜 黄药师 逍遥子 忽必烈 赵敏 
           逍遥子 完颜洪烈 金轮法王 双儿 鳌拜 洪七公 郭芙 郭襄 赵敏'''
           
    names = s.split()
    d = {}
    for name in names:
        d[name] = d.get(name, 0) + 1
    Maxkey = ""
    MaxValue = 0
    for k in d:
        if d[k] > MaxValue:
            Maxkey = k
            MaxValue = d[k]
    print(Maxkey)
    #参考答案
    ls = s.split()
    d = {}
    for i in ls:
        d[i] = d.get(i, 0) + 1
    max_name, max_cnt = "", 0
    for k in d:
        if d[k] > max_cnt:
            max_name, max_cnt = k, d[k]
    print(max_name)
    

    测验7:文件和数据格式化

    知识点概要:

    • 数据组织纬度一维数据采用线性方式组织,对应于数学中的数组和集合等概念;二维数据采用表格方式组织,对应于数学中的矩阵;高维数据由键值对类型的数据构成,采用对象方式组织,字典就用来表示高维数据,一般不用来表示一二纬数据
    • Python对文件操作采用的统一步骤是:打开-操作-关闭(其中关闭可以省略)
    • CSV文件格式是一种通用的、相对简单的文件格式,应用于程序之间转移表格数据,CSV文件的每一行是一维数据,可以使用Python中的列表类型表示,整个CSV文件是一个二维数据,一般来说,CSV文件都是文本文件,由相同的编码字符组成
    • 二维列表切片ls = [[1,2,3],[4,5,6],[7,8,9]]获取其中的元素5要使用:ls[1][1]
    • 文件可以包含任何内容,是数据的集合和抽象,是存储在辅助存储器上的数据序列,而函数或类才是程序的集合和抽象
    • 打开文件后采用close()关闭文件是一个好习惯。如果不调用close(),当前Python程序完全运行退出时,该文件引用被释放,即程序退出时,相当于调用了close(),默认关闭
    • Python文件的"+"打开模式,与r/w/a/x一同使用,在原功能基础上同时增加了读写功能,同时赋予文件的读写权限
    • 同一个文件既可以用文本方式打卡,也可以用二进制方式打开
    • 列表元素如果都是列表,其可能表示二维数据,如[[1,2],[3,4],[5,6]],如果列表元素不都是列表,则它表示一维数据
    • Python文件读操作有:read()、readline()、readlines(),没有readtext()方法

    编程测试:

    • 文本的平均列数:打印输出附件文件的平均列数,计算方法如下:‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      (1)有效行指包含至少一个字符的行,不计算空行‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      (2)每行的列数为其有效字符数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬
      (3)平均列数为有效行的列数平均值,采用四舍五入方式取整数进位
    #for line in f 获取的line包含每行最后的换行符(\n),所以去掉该换行符再进行统计
    f = open("latex.log", "r", encoding="utf-8")
    lines = 0
    columns = 0
    for line in f:
        line = line.strip("\n")
        if len(line):
            lines += 1
            columns += len(line)
    print("{:.0f}".format(columns/lines))
    f.close()
    
    #参考答案如下:
    f = open("latex.log")
    s, c = 0, 0
    for line in f:
        line = line.strip("\n")
        if line == "":
            continue
        s += len(line)
        c += 1
    print(round(s/c))
    

    -CSV格式清洗与转换:附件是一个CSV格式文件,提取数据进行如下格式转换:‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
    (1)按行进行倒序排列‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮
    (2)每行数据倒序排列‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
    (3)使用分号(;)代替逗号(,)分割数据,无空格‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
    按照上述要求转换后将数据输出

    f = open("data.csv", "r", encoding="utf-8")
    txt = f.readlines()
    txt.reverse() #按行进行倒序排列
    for line in txt:
        #line = line.strip("\n") #去除末尾换行符
        #line = line.replace(" ","") #去空格
        line = line.strip("\n").replace(" ", "")
        #ls = line.split(",") 
        #ls = ls[::-1]
        ls = line.split(",")[::-1] #逗号分隔并将分隔后的元素倒序
        print(";".join(ls)) #元素间插入分号
    f.close()
    
    #参考答案(使用strip()方法去掉每行最后的回车,使用replace()去掉每行元素两侧的空格)
    f = open("data.csv")
    ls = f.readlines()
    ls = ls[::-1]
    lt = []
    for item in ls:
        item = item.strip("\n")
        item = item.replace(" ", "")
        lt = item.split(",")
        lt = lt[::-1]
        print(";".join(lt))
    f.close()
    

    测验8:程序设计方法学

    知识点概要:

    • 用户体验:编程只是手段,程序最终为人类服务,用户体验很重要,一个提醒进度的进度条、一个永不抛出异常的程序、一个快速的响应、一个漂亮的图标、一个合适尺寸的界面等都是用户体验的组成部分。总的来说,用户体验是一切能够提升程序用户感受的组成
    • 计算思维是基于计算机的思维模式,计算机出现之前,由于没有快速计算装置,计算所反映的思维模式主要是数学思维,即通过公式来求解问题。当快速计算装置出现后,计算思维才真正形成
    • 软件产品 = 程序功能 + 用户体验 ;产品不仅需要功能,更需要更好的用户体验。往往,产品都需要综合考虑技术功能和人文设计,这源于产品的商业特性。即,商业竞争要求产品不能只关心技术功能,更要关心用户易用和喜好需求
    • os库os.system()可以启动进程执行程序
    • 函数自顶向下设计的关键元素,通过定义函数及其参数逐层开展程序设计
    • os.path子库os.path.relpath(path)用来计算相对路径
    • Python第三方库安装:使用pip命令、使用集成安装工具或访问UCI网站下载安装文件,请不要直接联系作者索要第三方库
    • 计算思维的本质是:抽象自动化
    • os库是Python重要的标准库之一,提供了路径操作、进程管理等几百个函数功能,覆盖与操作系统、文件操作等相关的众多功能;os库适合所有操作系统
    • 计算生态以竞争发展、相互依存和迅速更迭为特点,在开源项目间不存在顶层设计,以类自然界"适者生存"的方式形成技术演进路径

    编程测试:

    • 英文字符的鲁棒输入:获得用户的任何可能输入,将其中的英文字符进行打印输出,程序不出现错误
    inputStr = input()
    for i in inputStr:
        if i.islower() or i.isupper():
            print(i,end="")
         
    #参考答案:采用遍历字符的方式实现,通过约束字母表达到鲁棒效果
    alpha = []
    for i in range(26):
        alpha.append(chr(ord('a') + i))
        alpha.append(chr(ord('A') + i))
    s = input()
    for c in s:
        if c in alpha:
            print(c, end="")
    
    • 数字的鲁棒输入:获得用户输入的一个数字,可能是浮点数或复数,如果是整数仅接收十进制形式,且只能是数字。对输入数字进行平方运算,输出结果,要求:
      1)无论用户输入何种内容,程序无错误‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬
      2)如果输入有误,请输出"输入有误"
    number = input()
    try:
        #complex()和complex(eval())之间的比较
        #将能够排除非数字类型的输入
        if complex(number) == complex(eval(number)):
            print(eval(number) ** 2)
    except:
        print("输入有误") 
        
    '''
    不能直接使用eval(),否则用户可以通过输入表达式(如100**2)输入数字
    与要求不同(在实际应用中会带来安全隐患)
    '''
    

    测验9:Python计算生态纵览

    知识点概要:

    • Python网络爬虫方向第三方库有:Requests、Scrapy、pyspider
    • Python数据可视化方向第三方库有:Mayavi、Matplotlib、Seaborn
    • Python Web信息提取方向第三方库有:Beautiful Soup、Python-Goose、Re
    • Python游戏开发第三方库有:Panda3D、cocos2d、PyGame
    • Python数据分析方向第三方库有:Numpy、Pandas、Scipy
    • Python图形用户界面方向(GUI)第三方库有:PyQt5、wxPython、PyGObject
    • Python网站开发框架方向第三方库有:Django、Pyramid、Flask
    • Python文本处理方向第三方库有:NLTK、python-docx、PyPDF2
    • Python网络应用开发方向第三方库有:aip、MyQR、WeRobot
    • aip是百度的人工智能功能Python访问接口
    • Python人工智能方向第三方库有:TensorFlow、Scikit-learn、MXNet
    • Vizard是虚拟现实第三方库
    • pyovr是增强现实开发库
    • redis-py是redis数据的Python访问接口

    编程测试:

    • 系统基本信息获取:获取系统的递归深度、当前执行文件路径、系统最大UNICODE编码值等3个信息,并打印输出;输出格式如下:‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬
      RECLIMIT:<深度>, EXEPATH:<文件路径>, UNICODE:<最大编码值>‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮
      提示:请在sys标准库中寻找上述功能
    import sys
    print("RECLIMIT:{}, EXEPATH:{}, UNICODE:{}".format(sys.getrecursionlimit(), sys.executable, sys.maxunicode))
    
    • 二维数据表格输出:tabulate能够对二维数据进行表格输出,是Python优秀的第三方计算生态。‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬编写程序,能够输出如下风格效果的表格数据
      输出效果
    data = [ ["北京理工大学", "985", 2000], \
             ["清华大学", "985", 3000], \
             ["大连理工大学", "985", 4000], \
             ["深圳大学", "211", 2000], \
             ["沈阳大学", "省本", 2000], \
        ]
    from tabulate import tabulate
    print(tabulate(data, tablefmt="grid"))
    

    期末测验

    *编程测试:

    • 无空隙回声输出:获得用户输入,去掉其中全部空格,将其他字符按收入顺序打印输出
    print(input().replace(" ",""))
    
    • 文件关键行数:关键行指一个文件中包含的不重复行。关键行数指一个文件中包含的不重复行的数量。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬统计附件文件中关键行的数量
    f = open("latex.log", "r", encoding="utf-8")
    d = {}
    for line in f:
        d[line] = d.get(line, 0) + 1
    print("共{}关键行".format(len(d)))
    
    #参考答案:如果需要"去重"功能,请使用集合类型
    f = open("latex.log")
    ls = f.readlines()
    s = set(ls)
    print("共{}关键行".format(len(s)))
    
    • 剩余两题与测验九重复,不重复记录
    展开全文
  • (1)、设计一个学生类Student,包括数据成员:姓名、学号、二门课程(面向对象程序设计、高等数学)的成绩。 (2)、创建一个管理学生的类Management,包括实现学生的数据的增加、删除、修改、按课程成绩排序、保存...

    (1)、设计一个学生类Student,包括数据成员:姓名、学号、二门课程(面向对象程序设计、高等数学)的成绩。
    (2)、创建一个管理学生的类Management,包括实现学生的数据的增加、删除、修改、按课程成绩排序、保存学生数据到文件及加载文件中的数据等功能。
    (3)、创建一个基于对话框的MFC应用程序,程序窗口的标题上有你姓名、学号和应用程序名称。使用(1)和(2)中的类,实现对学生信息和成绩的输入和管理。
    (4)、创建一个单文档的MFC应用程序,读取(3)中保存的文件中的学生成绩,分别用直方图和折线方式显示所有学生某课程的成绩分布图。
    效果如图:

    //student.h
    #pragma once
    #include<iostream>
    using namespace std;
    class student
    {
    public:
    	student();
    	student(int id , const char* name , float oop , float math ,char sex,int age,const char*adress );
    	~student();
    
    	int GetId() const { return mId; }//获取学号
    	void SetId(int id) { mId = id; }//修改学号
    	const char* GetName() const { return mName; }//获取姓名
    	void SetName(const char* name) { strcpy_s(mName, 31, name); }//修改姓名
    	float GetOop() const { return mOop; }//获取c++成绩
    	void SetOop(float oop) { mOop = oop; }//修改c++成绩
    	float GetMath() const { return mMath; }//获取数学成绩
    	void SetMath(float math) { mMath = math; }//修改数学成绩
    	char Getsex() { return msex; }//获取性别
    	void Setsex(char sex) { msex = sex; }//修改性别	
    	int Getage() { return mage; }//获取年龄
    	void Setage(int age) { mage = age; }//修改年龄
    	const char* Getadress() const { return madress; }//获取地址
    	void Seadress(const char* adress) { strcpy_s(madress, 41, adress); }//修改地址
    
    	friend ostream& operator<<(ostream& os, const student& st);//输出学生信息
    	friend istream& operator>>(istream& is, student& st);//输入学生信息
    
    	friend bool LessOop(const student* st1, const student* st2);//判断c++成绩高低
    	friend bool LessMath(const student* st1, const student* st2);//判断数学成绩高低
    private:
    	int mId;//学号
    	char mName[31];//姓名
    	float mOop;//c++成绩
    	float mMath;//数学成绩
    	char msex;//性别
    	int mage;//年龄
    	char madress[40];//地址
    };
    //student.cpp
    #include "stdafx.h"
    #include "student.h"
    
    
    
    student::student(int id, const char* name, float oop, float math, char sex,int age, const char*adress)//初始化
    	:mId(id), mOop(oop), mMath(math),msex(sex),mage(age)
    {
    	strcpy_s(mName, name);
    	strcpy_s(madress,adress);
    
    }
    student::student()
    {
    }
    
    student::~student()
    {
    }
    ostream& operator<<(ostream& os, const student& st)//输入学生信息
    {
    	os << st.mId << '\t' << st.mName << '\t';
    	os << st.mOop << '\t' << st.mMath << '\t';
    	os << st.msex << '\t' << st.mage << '\t' << st.madress;
    	return os;
    }
    
    istream& operator>>(istream& is, student& st)//输出学生信息
    {
    	is >> st.mId >> st.mName >> st.mOop >> st.mMath>>st.msex>>st.mage>>st.madress;
    	return is;
    }
    
    bool LessOop(const student* st1, const student* st2)//判断c++成绩高低
    {
    	return st1->mOop < st2->mOop;
    }
    bool LessMath(const student* st1, const student* st2)//判断数学成绩高低
    {
    	return st1->mMath < st2->mMath;
    }
    //Managerment.h
    #pragma once
    #include "student.h"
    #include <list>
    class managerment
    {
    public:
    	managerment();
    	~managerment();
    
    	list<student*>* GetStudents() { return &mstudents; }//student类引入	
    	void Clear();//清除内存
    	void Add(student *pSt);//添加数据
    	student *Delete(int id);//删除数据
    	void Modify(int id, const char* name, float oop, float math, char sex, int age, const char*adress);//修改数据
    	void oopsort();//c++排序	
    	void mathsort();//数学排序
    	bool Save(const char*filename);//保存文件
    	bool Open(const char*filename);//打开文件
    private:
    	list<student*> mstudents;//建立链表
    };
    
    //managerment.cpp
    #include "stdafx.h"
    #include "managerment.h"
    #include <fstream>
    
    
    managerment::managerment()
    {
    }
    
    
    managerment::~managerment()
    {
    	for (auto iter = mstudents.begin(); iter != mstudents.end(); ++iter)
    	{
    		delete *iter;
    	}
    }
    
    void managerment::Clear()
    {
    	for (auto iter = mstudents.begin(); iter != mstudents.end(); ++iter)
    	{
    		delete *iter;
    	}
    	mstudents.clear();//清除该数据
    }
    
    void managerment::Add(student *pSt)
    {
    	mstudents.push_back(pSt);//链表尾部加入数据
    }
    
    student* managerment::Delete(int id)
    {
    	student *pSt = nullptr;
    	for (auto iter = mstudents.begin(); iter != mstudents.end(); ++iter)//寻找是否有此id
    	{
    		if ((*iter)->GetId() == id)
    		{
    			pSt = *iter;
    			break;
    		}
    	}
    	if (pSt != nullptr) mstudents.remove(pSt);//将其删除
    	return pSt;
    }
    
    void managerment::Modify(int id, const char* name, float oop, float math, char sex, int age, const char*adress)
    {
    	student *pSt = nullptr;
    	for (auto iter = mstudents.begin(); iter != mstudents.end(); ++iter)//寻找id
    	{
    		if ((*iter)->GetId() == id)
    		{
    			pSt = *iter;
    			break;
    		}
    	}
    	if (pSt != nullptr)//若能找到对应id
    	{
    		pSt->SetName(name);
    		if (oop >= 0.0) pSt->SetOop(oop);//修改c++成绩	
    		if (math >= 0.0) pSt->SetMath(math);//修改数学成绩
    		pSt->Setsex(sex);//修改性别
    		pSt->Setage(age);//修改年龄
    		pSt->Seadress(adress);//修改地址
    	}
    }
    
    void managerment::oopsort()
    {
    	mstudents.sort(LessOop);//c++成绩排序
    }
    
    void managerment::mathsort()
    {
    	mstudents.sort(LessMath);//数学成绩排序
    }
    
    bool managerment::Save(const char*filename)
    {
    	ofstream file(filename, ios::out);
    	if (!file) return false;
    	file << mstudents.size() << '\n';//文件字符串长度
    	for (auto iter = mstudents.begin(); iter != mstudents.end(); ++iter)//向文件输入数据
    	{
    		file << (**iter) << '\n';
    	}
    	file.close();
    	return true;
    }
    
    bool managerment::Open(const char*filename)
    {
    	Clear();
    	ifstream file(filename, ios::in);
    	if (!file) return false;
    	int n = 0;
    	file >> n;
    	for (int k = 0; k < n; ++k)//文件内容输入并置于链表后
    	{
    		student* pSt = new student();
    		file >> *pSt;
    		mstudents.push_back(pSt);
    	}
    	file.close();
    	return true;
    }
    //Doc.h
    #pragma once
    #include "managerment.h"
    
    
    
    class CMy0601Doc : public CDocument
    {
    protected: // 仅从序列化创建
    	CMy0601Doc() noexcept;
    	DECLARE_DYNCREATE(CMy0601Doc)
    
    	managerment mManagerment;
    
    // 特性
    public:
    	managerment *Getmanagerment() { return &mManagerment; }
    // 操作
    public:
    
    // 重写
    public:
    	virtual BOOL OnNewDocument();
    	virtual void Serialize(CArchive& ar);
    #ifdef SHARED_HANDLERS
    	virtual void InitializeSearchContent();
    	virtual void OnDrawThumbnail(CDC& dc, LPRECT lprcBounds);
    #endif // SHARED_HANDLERS
    
    // 实现
    public:
    	virtual ~CMy0601Doc();
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    
    // 生成的消息映射函数
    protected:
    	DECLARE_MESSAGE_MAP()
    
    #ifdef SHARED_HANDLERS
    	// 用于为搜索处理程序设置搜索内容的 Helper 函数
    	void SetSearchContent(const CString& value);
    #endif // SHARED_HANDLERS
    public:
    	
    	afx_msg void On32771();//链接对话框
    	virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);//打开文件
    	virtual BOOL OnSaveDocument(LPCTSTR lpszPathName);//保存文件
    };
    //Doc.cpp
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    // CMy0601Doc
    
    IMPLEMENT_DYNCREATE(CMy0601Doc, CDocument)
    
    BEGIN_MESSAGE_MAP(CMy0601Doc, CDocument)
    	ON_COMMAND(ID_32771, &CMy0601Doc::On32771)
    	
    END_MESSAGE_MAP()
    
    
    // CMy0601Doc 构造/析构
    
    CMy0601Doc::CMy0601Doc() noexcept
    {
    	// TODO: 在此添加一次性构造代码
    
    }
    
    CMy0601Doc::~CMy0601Doc()
    {
    }
    
    BOOL CMy0601Doc::OnNewDocument()//新建文档后初始化
    {
    	if (!CDocument::OnNewDocument())
    		return FALSE;
    
    	// TODO: 在此添加重新初始化代码
    	// (SDI 文档将重用该文档)
    	srand((unsigned int)(time(NULL)));
    	this->mManagerment.Clear();//先做清除
    	const int n = 46;
    	for (int k = 0; k < n; ++k)//利用随机函数对数据初始化
    	{
    		int id = 18060000 + rand() % 1000;
    		char name[7] = { 0 };
    		char adress[7] = { 0 };
    		for (int i = 0; i < 6; ++i)
    		{
    			name[i] = 'A' + rand() % 26;
    			adress[i] = 'A' + rand() % 26;
    		}
    		char c;
    		if (k%2==0) c = 'm';
    		else c = 'w';
    		auto st = new student(id, name, 40 + rand() % 61, 30 + rand() % 71,c,15+rand()%10,adress);
    		this->mManagerment.Add(st);//添加进链表	
    	}
    	this->mManagerment.oopsort();//c++排序
    	return TRUE;
    }
    
    
    
    
    // CMy0601Doc 序列化
    
    void CMy0601Doc::Serialize(CArchive& ar)
    {
    	if (ar.IsStoring())
    	{
    		// TODO: 在此添加存储代码
    	}
    	else
    	{
    		// TODO: 在此添加加载代码
    	}
    }
    
    #ifdef SHARED_HANDLERS
    
    // 缩略图的支持
    void CMy0601Doc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
    {
    	// 修改此代码以绘制文档数据
    	dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));
    
    	CString strText = _T("TODO: implement thumbnail drawing here");
    	LOGFONT lf;
    
    	CFont* pDefaultGUIFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT));
    	pDefaultGUIFont->GetLogFont(&lf);
    	lf.lfHeight = 36;
    
    	CFont fontDraw;
    	fontDraw.CreateFontIndirect(&lf);
    
    	CFont* pOldFont = dc.SelectObject(&fontDraw);
    	dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);
    	dc.SelectObject(pOldFont);
    }
    
    // 搜索处理程序的支持
    void CMy0601Doc::InitializeSearchContent()
    {
    	CString strSearchContent;
    	// 从文档数据设置搜索内容。
    	// 内容部分应由“;”分隔
    
    	// 例如:     strSearchContent = _T("point;rectangle;circle;ole object;");
    	SetSearchContent(strSearchContent);
    }
    
    void CMy0601Doc::SetSearchContent(const CString& value)
    {
    	if (value.IsEmpty())
    	{
    		RemoveChunk(PKEY_Search_Contents.fmtid, PKEY_Search_Contents.pid);
    	}
    	else
    	{
    		CMFCFilterChunkValueImpl *pChunk = nullptr;
    		ATLTRY(pChunk = new CMFCFilterChunkValueImpl);
    		if (pChunk != nullptr)
    		{
    			pChunk->SetTextValue(PKEY_Search_Contents, value, CHUNK_TEXT);
    			SetChunkValue(pChunk);
    		}
    	}
    }
    
    #endif // SHARED_HANDLERS
    
    // CMy0601Doc 诊断
    
    #ifdef _DEBUG
    void CMy0601Doc::AssertValid() const
    {
    	CDocument::AssertValid();
    }
    
    void CMy0601Doc::Dump(CDumpContext& dc) const
    {
    	CDocument::Dump(dc);
    }
    #endif //_DEBUG
    
    
    // CMy0601Doc 命令
    
    
    void CMy0601Doc::On32771()//对话框响应
    {
    	// TODO: 在此添加命令处理程序代码
    	Dlg dlg;
    	dlg.pDoc = this;
    	dlg.DoModal();//显示对话框,关闭后返回程序
    }
    
    BOOL CMy0601Doc::OnOpenDocument(LPCTSTR lpszPathName)
    {
    	//	if (!CDocument::OnOpenDocument(lpszPathName))
    	//		return FALSE;
    
    		// TODO:  在此添加您专用的创建代码
    	return this->mManagerment.Open(lpszPathName);
    	//	return TRUE;
    }
    
    BOOL CMy0601Doc::OnSaveDocument(LPCTSTR lpszPathName)
    {
    	// TODO: 在此添加专用代码和/或调用基类
    	return this->mManagerment.Save(lpszPathName);
    
    	//	return CDocument::OnSaveDocument(lpszPathName);
    }
    //View.h
    #pragma once
    #define IDC_HIGGER_MATH 130
    #define IDC_C_PROGRAM 131
    #define IDC_HIGGER_MATH_LINE 132
    #define IDC_C_PROGRAM_LINE 133
    
    class CMy0601View : public CView
    {
    protected: // 仅从序列化创建
    	CMy0601View() noexcept;
    	DECLARE_DYNCREATE(CMy0601View)
    
    	LOGFONT font;
    // 特性
    public:
    	CMy0601Doc* GetDocument() const;
    	CButton m_button1;//数学直方图按钮
    	CButton m_button2;//数学折线图按钮
    	CButton m_button3;//c++直方图按钮
    	CButton m_button4;//c++折线图按钮
    // 操作
    public:
    
    // 重写
    public:
    	virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图
    	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    	void Draw(CDC* pDC,int i);//绘画直方图和折线图
    protected:
    	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
    	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
    	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
    	void OnClickbutton1();//点击绘画数学成绩直方图
    	void OnClickbutton2();//点击绘画c++成绩直方图
    	void OnClickbutton3();//点击绘画数学成绩折线图
    	void OnClickbutton4();//点击绘画c++成绩折线图
    // 实现
    public:
    	virtual ~CMy0601View();
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    	afx_msg void OnFilePrintPreview();
    	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    // 生成的消息映射函数
    protected:
    	DECLARE_MESSAGE_MAP()
    public:
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);//创建按钮
    };
    
    #ifndef _DEBUG  // 06  01View.cpp 中的调试版本
    inline CMy0601Doc* CMy0601View::GetDocument() const
       { return reinterpret_cast<CMy0601Doc*>(m_pDocument); }
    #endif
    //View.cpp
    #include "stdafx.h"
    // SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
    // ATL 项目中进行定义,并允许与该项目共享文档代码。
    #ifndef SHARED_HANDLERS
    #include "06  01.h"
    #endif
    
    #include "06  01Doc.h"
    #include "06  01View.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    
    #endif
    
    
    // CMy0601View
    
    IMPLEMENT_DYNCREATE(CMy0601View, CView)
    
    BEGIN_MESSAGE_MAP(CMy0601View, CView)
    	// 标准打印命令
    	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
    	ON_WM_CREATE()
    	ON_WM_RBUTTONUP()
    	ON_BN_CLICKED(IDC_HIGGER_MATH,OnClickbutton1)
    	ON_BN_CLICKED(IDC_C_PROGRAM, OnClickbutton2)
    	ON_BN_CLICKED(IDC_HIGGER_MATH_LINE, OnClickbutton3)
    	ON_BN_CLICKED(IDC_C_PROGRAM_LINE, OnClickbutton4)
    END_MESSAGE_MAP()
    
    // CMy0601View 构造/析构
    
    CMy0601View::CMy0601View() noexcept//初始化字体
    {
    	// TODO: 在此处添加构造代码
    	//逻辑设备单位高度,>0—上高+下高,<0—上高+下高-内部Leading.
    	font.lfHeight = 18;
    	//逻辑设备单位的宽度,等于零选择方形。
    	font.lfWidth = 0;
    	//指定文本的基线与设备x轴间的角度,十分之一度为单位。
    	font.lfEscapement = 0;
    	//字体的黑体度(0-1000)FW_NORMAL=400,FW_BOLD=700
    	font.lfWeight = FW_BOLD;
    	//是否斜体
    	font.lfItalic = 0;
    	//是否绘制下划线
    	font.lfUnderline = 0;
    	//是否划删除线
    	font.lfStrikeOut = 0;
    	//指定每个字符的基线与设备x轴间的角度,十分之一度为单位(NT/2000)。
    	font.lfOrientation = 0;
    	//字体的字符集 GB2312_CHARSET
    	font.lfCharSet = DEFAULT_CHARSET;
    	//指定匹配字体时的一些偏好。
    	font.lfOutPrecision = OUT_DEFAULT_PRECIS;
    	//字符被裁剪时,指定如何裁剪。
    	font.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    	//指定图元输出质量。
    	font.lfQuality = DEFAULT_QUALITY;
    	//字体间距和族
    	font.lfPitchAndFamily = DEFAULT_PITCH;
    	//字体名称
    	strcpy_s(font.lfFaceName, _T("隶书"));
    
    }
    
    CMy0601View::~CMy0601View()
    {
    }
    
    BOOL CMy0601View::PreCreateWindow(CREATESTRUCT& cs)
    {
    	// TODO: 在此处通过修改
    	//  CREATESTRUCT cs 来修改窗口类或样式
    
    	return CView::PreCreateWindow(cs);
    }
    
    
    // CMy0601View 绘图
    
    void CMy0601View::OnDraw(CDC* pDC)
    {
    	CMy0601Doc * pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	// TODO: 在此处为本机数据添加绘制代码
    
    	
    }
    
    
    // CMy0601View 打印
    
    BOOL CMy0601View::OnPreparePrinting(CPrintInfo* pInfo)
    {
    	// 默认准备
    	return DoPreparePrinting(pInfo);
    }
    
    void CMy0601View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: 添加额外的打印前进行的初始化过程
    
    }
    
    void CMy0601View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: 添加打印后进行的清理过程
    }
    
    
    
    // CMy0601View 诊断
    
    #ifdef _DEBUG
    void CMy0601View::AssertValid() const
    {
    	CView::AssertValid();
    }
    
    void CMy0601View::Dump(CDumpContext& dc) const
    {
    	CView::Dump(dc);
    }
    
    CMy0601Doc* CMy0601View::GetDocument() const // 非调试版本是内联的
    {
    	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMy0601Doc)));
    	return (CMy0601Doc*)m_pDocument;
    }
    #endif //_DEBUG
    
    
    // CMy0601View 消息处理程序
    
    
    int CMy0601View::OnCreate(LPCREATESTRUCT lpCreateStruct)//创建按钮
    {
    	if (CView::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	m_button1.Create((CString)"高数直方图",//按钮标题
    		WS_CHILD | WS_VISIBLE | WS_BORDER,//按钮风格
    		CRect(10, 10, 120, 50),            //按钮大小
    		this,                          //按钮父指针
    		IDC_HIGGER_MATH);                      //该按钮对应的ID号
    	m_button1.ShowWindow(SW_SHOWNORMAL);
    	m_button2.Create((CString)"c++直方图",//按钮标题
    		WS_CHILD | WS_VISIBLE | WS_BORDER,//按钮风格
    		CRect(10, 110, 120, 150),            //按钮大小
    		this,                          //按钮父指针
    		IDC_C_PROGRAM);                      //该按钮对应的ID号
    	m_button2.ShowWindow(SW_SHOWNORMAL);
    	m_button3.Create((CString)"(折线)",//按钮标题
    		WS_CHILD | WS_VISIBLE | WS_BORDER,//按钮风格
    		CRect(120, 10, 180, 50),            //按钮大小
    		this,                          //按钮父指针
    		IDC_HIGGER_MATH_LINE);                      //该按钮对应的ID号
    	m_button3.ShowWindow(SW_SHOWNORMAL);
    	m_button4.Create((CString)"(折线)",//按钮标题
    		WS_CHILD | WS_VISIBLE | WS_BORDER,//按钮风格
    		CRect(120, 110, 180, 150),            //按钮大小
    		this,                          //按钮父指针
    		IDC_C_PROGRAM_LINE);                      //该按钮对应的ID号
    	m_button4.ShowWindow(SW_SHOWNORMAL);
    	// TODO:  在此添加您专用的创建代码
    	return 0;
    }
    
    
    
    
    
    void  CMy0601View::Draw(CDC* pDC ,int i)//绘画直方图和折线图
    {
    	CMy0601Doc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	int count[2][5] = { {0},{0} };
    	auto sts = pDoc->Getmanagerment()->GetStudents();
    	int k = 0;
    	for (auto iter = sts->begin(); iter != sts->end(); ++iter)//得到各分组的人数
    	{
    		auto st = *iter;
    		float m = st->GetMath();
    		if (m < 60.0f) ++count[0][0];
    		else if (m < 70.0f) ++count[0][1];
    		else if (m < 80.0f) ++count[0][2];
    		else if (m < 90.0f) ++count[0][3];
    		else ++count[0][4];
    		float c = st->GetOop();
    		if (c < 60.0f) ++count[1][0];
    		else if (c < 70.0f) ++count[1][1];
    		else if (c < 80.0f) ++count[1][2];
    		else if (c < 90.0f) ++count[1][3];
    		else ++count[1][4];
    	}
    	CString msg[2][5];
    	for (int i = 0; i < 2; ++i)
    	{
    		for (int j = 0; j < 5; ++j)
    		{
    			msg[i][j].Format(_T("%d人"), count[i][j]);
    		}
    	}
    	CString s[5] = { _T("<60"),_T("60-69"),_T("70-79"),_T("80-89"),_T("90-100") };//设定添加字符
    	CFont f;
    	f.CreateFontIndirect(&font);//设置环境字体
    	auto oldFont = pDC->SelectObject(&f);
    	auto color = pDC->SetTextColor(RGB(0, 0, 255));
    	CRect rect;
    	this->GetClientRect(&rect);//获取客户区大小
    	int w = rect.Width(), h = rect.Height();//宽高
    	int nw = (w -200)/ 5;
    	int nh = 20;//单位宽度和长度
    	if (i == 0)//数学直方图
    	{
    		pDC->SetBkMode(TRANSPARENT);//设置文字透明背景
    		CPen pen;
    		pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
    		auto oldPen = pDC->SelectObject(&pen);
    		for (int k = 0; k < 5; ++k)
    		{
    			CBrush brush;
    			if (k % 2 == 0) brush.CreateHatchBrush(2, RGB(0, 0, 255));
    			else brush.CreateHatchBrush(3, RGB(0, 0, 255));//设置两种填充斜线
    			auto oldBrush = pDC->SelectObject(&brush);
    			CRect rt(180 + k * nw,h-50-count[i][k]*nh, 180 + (k+1) * nw, h-50);
    			pDC->Rectangle(rt);//画条形图
    			pDC->DrawText(msg[i][k], rt, DT_SINGLELINE | DT_CENTER | DT_VCENTER);//矩形中心写入文字
    			CRect r(180 + k * nw, h - 50 - count[i][k] * nh, 180 + (k + 1) * nw, h - 50);
    			pDC->DrawText(s[k], r, DT_SINGLELINE | DT_CENTER);//矩形底部写入文字
    		}
    		pDC->TextOutA(140, 50, "数学直方图");//上方显示“数学直方图”
    		pDC->SelectObject(oldPen);
    		pDC->SelectObject(oldFont);
    	}
    	else if (i == 1)//c++直方图
    	{
    		pDC->SetBkMode(TRANSPARENT);//设置文字透明背景
    		CPen pen;
    		pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
    		auto oldPen = pDC->SelectObject(&pen);
    		for (int k = 0; k < 5; ++k)
    		{
    			CBrush brush;
    			if (k % 2 == 0) brush.CreateHatchBrush(2, RGB(0, 0, 255));
    			else brush.CreateHatchBrush(3, RGB(0, 0, 255));//设置两种填充斜线
    			auto oldBrush = pDC->SelectObject(&brush);
    			CRect rt(180 + k * nw, h - 50 - count[i][k] * nh, 180 + (k + 1) * nw, h - 50);
    			pDC->Rectangle(rt);//画条形图
    			pDC->DrawText(msg[i][k], rt, DT_SINGLELINE | DT_CENTER | DT_VCENTER);//矩形中心写入文字
    			CRect r(180 + k * nw, h - 50 - count[i][k] * nh, 180 + (k + 1) * nw, h - 50);
    			pDC->DrawText(s[k], r, DT_SINGLELINE | DT_CENTER);//矩形底部写入文字
    		}
    		pDC->TextOutA(140, 50, "c++直方图");//上方显示“c++直方图”
    		pDC->SelectObject(oldPen);
    		pDC->SelectObject(oldFont);
    	}
    	else//折线图
    	{
    		pDC->MoveTo(120,h-50);
    		pDC->LineTo(120,50);//画y轴
    		pDC->MoveTo(120,h-50);
    		pDC->LineTo(w - 50, h - 50);//画x轴
    		if (i == 2)//数学折线图
    		{
    			pDC->MoveTo(120,h-50);//原点开始
    			for (int k = 0; k < 5; k++)
    			{
    				pDC->LineTo(120 + (k + 1) * nw, h - 50 - count[i - 2][k] * nh);//起点和终点连接
    				if (k != 4)
    				{
    					pDC->MoveTo(120 + (k + 1)* nw, h - 50 - count[i - 2][k] * nh);//将终点设置为起点
    				}
    				pDC->TextOutA(140 + (k + 1)* nw, h - 70 - count[i - 2][k] * nh, msg[i - 2][k]);//显示人数
    				pDC->TextOutA(140 + (k + 1)* nw, h - 30, s[k]);//显示分数间断
    			}
    			pDC->TextOutA(140, 50, "数学折线图");
    		}
    		else if (i == 3)//c++折线图
    		{
    			pDC->MoveTo(120, h - 50);
    			for (int k = 0; k < 5; k++)
    			{
    				pDC->LineTo(120 + (k + 1) * nw, h - 50 - count[i - 2][k] * nh);//起点和终点连接
    				if (k != 4)
    				{
    					pDC->MoveTo(120 + (k + 1) * nw, h - 50 - count[i - 2][k] * nh);//将终点设置为起点
    				}
    				pDC->TextOutA(140 + (k + 1)* nw, h - 70 - count[i - 2][k] * nh, msg[i - 2][k]);//显示人数
    				pDC->TextOutA(140 + (k + 1)* nw, h - 30, s[k]);//显示分数间断
    			}
    			pDC->TextOutA(140, 50, "c++折线图"); //上方显示“c++折线图”
    		}
    	}
    }
    void CMy0601View::OnClickbutton1()
    {
    	InvalidateRect(NULL);//加入线程
    	UpdateWindow();//立即显示
    	Draw(GetDC(), 0);//画图
    }
    void CMy0601View::OnClickbutton2()
    {
    	InvalidateRect(NULL);//加入线程
    	UpdateWindow();//立即显示
    	Draw(GetDC(), 1);//画图
    }
    void CMy0601View::OnClickbutton3()
    {
    	InvalidateRect(NULL);//加入线程
    	UpdateWindow();//立即显示
    	Draw(GetDC(), 2);//画图
    }
    void CMy0601View::OnClickbutton4()
    {
    	InvalidateRect(NULL);//加入线程
    	UpdateWindow();//立即显示
    	Draw(GetDC(), 3);//画图
    }
    
    
    //Dlg.h
    class CMy0601Doc;
    class Dlg : public CDialogEx
    {
    	DECLARE_DYNAMIC(Dlg)
    
    public:
    	Dlg(CWnd* pParent = nullptr);   // 标准构造函数
    	virtual ~Dlg();
    	CMy0601Doc *pDoc;
    // 对话框数据
    #ifdef AFX_DESIGN_TIME
    	enum { IDD = IDD_DIALOG1 };
    #endif
    
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    	 
    	DECLARE_MESSAGE_MAP()
    public:
    	int m_id;
    	CString m_name;
    	float m_math;
    	float m_oop;
    	afx_msg void OnClickedAdd(); //增加响应
    	afx_msg void OnClickedDelete();//删除响应
    	afx_msg void OnClickedModify();//修改响应
    	afx_msg void OnSelchangeList2();//添加后链表响应
    	virtual BOOL OnInitDialog();//初始化链表
    	CListBox m_listBox;//列表
    	int m_age;//年龄
    	CString m_adress;//地址
    	BOOL m_sex;//性别
    	//BOOL m_sex1;
    };
    
    
    //Dlg.cpp
    #include "stdafx.h"
    #include "06  01.h"
    #include "Dlg.h"
    #include "afxdialogex.h"
    #include"student.h"
    #include"06  01Doc.h"
    #include<vector>
    
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // Dlg 对话框
    
    IMPLEMENT_DYNAMIC(Dlg, CDialogEx)
    
    Dlg::Dlg(CWnd* pParent /*=nullptr*/)
    	: CDialogEx(IDD_DIALOG1, pParent)
    	, m_id(0)
    	, m_name(_T(""))
    	, m_math(0)
    	, m_oop(0)
    	, m_age(0)
    	, m_adress(_T(""))
    	, m_sex(FALSE)
    //	, m_sex1(FALSE)
    {
    
    }
    
    Dlg::~Dlg()
    {
    }
    
    void Dlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT2, m_id);
    	DDX_Text(pDX, IDC_EDIT1, m_name);
    	DDX_Text(pDX, IDC_EDIT4, m_math);
    	DDX_Text(pDX, IDC_EDIT6, m_oop);
    	DDX_Control(pDX, IDC_LIST2, m_listBox);
    
    	DDX_Text(pDX, IDC_EDIT3, m_age);
    	DDX_Text(pDX, IDC_EDIT5, m_adress);
    	DDX_Radio(pDX, IDC_RADIO1, m_sex);
    	//DDX_Radio(pDX, IDC_RADIO2, m_sex1);
    }
    
    
    BEGIN_MESSAGE_MAP(Dlg, CDialogEx)
    	ON_BN_CLICKED(IDC_BUTTON1, &Dlg::OnClickedAdd)
    	ON_BN_CLICKED(IDC_BUTTON2, &Dlg::OnClickedDelete)
    	ON_BN_CLICKED(IDC_BUTTON3, &Dlg::OnClickedModify)
    	ON_LBN_SELCHANGE(IDC_LIST2, &Dlg::OnSelchangeList2)
    END_MESSAGE_MAP()
    
    
    // Dlg 消息处理程序
    
    
    void Dlg::OnClickedAdd()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	UpdateData(TRUE);//更新框中数据
    	char m_sex2;//性别
    	if (m_sex==TRUE) m_sex2 = 'm';
    	else m_sex2 = 'w';
    	student* pSt = new student(m_id, m_name, m_oop, m_math,m_sex2,m_age,m_adress);//创建对象初始化
    	pDoc->Getmanagerment()->Add(pSt);//添加数据
    	CString msg;
    	msg.Format("%d %s %f,%f %c %d %s", m_id, m_name,m_oop, m_math, m_sex2, m_age, m_adress);//将数据转化为CString
    	m_listBox.AddString(msg);//添加进链表框
    	m_listBox.SetItemDataPtr(m_listBox.GetCount() - 1, pSt); //将序号与内容关联
    }
    
    
    void Dlg::OnClickedDelete()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	int index = m_listBox.GetCurSel();//获取鼠标选中项下标
    	if (index == LB_ERR) return;
    	student* pSt = (student*)m_listBox.GetItemDataPtr(index);//获取下标成功后返回该指针
    	pDoc->Getmanagerment()->Delete(pSt->GetId());//删除数据
    	delete pSt;//释放该内存
    	m_listBox.DeleteString(index);//删除链表字符
    }
    
    
    void Dlg::OnClickedModify()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	int index = m_listBox.GetCurSel();//获取鼠标选中项下标
    	if (index == LB_ERR) return;
    	student* pSt = (student*)m_listBox.GetItemDataPtr(index);//获取下标成功后返回该指针
    	UpdateData(TRUE);//更新数据
    	char m_sex2;//性别
    	if (m_sex == TRUE) m_sex2 = 'm';
    	else m_sex2 = 'w';
    	pSt->SetId(m_id);
    	pSt->SetName(m_name);
    	pSt->SetOop(m_oop);
    	pSt->SetMath(m_math);
    	pSt->Setage(m_age);
    	pSt->Setsex(m_sex2);
    	pSt->Seadress(m_adress);//写入数据
    	m_listBox.DeleteString(index);//删除原数据
    	CString msg;
    	msg.Format("%d %s %f %f %c %d %s", m_id, m_name, m_oop, m_math, m_sex2, m_age, m_adress);
    	m_listBox.InsertString(index, msg);//链表指定位置插入数据
    	m_listBox.SetItemDataPtr(index, pSt);//将序号与内容关联
    }
    
    
    void Dlg::OnSelchangeList2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	int index = m_listBox.GetCurSel();//获取鼠标选中项下标
    	if (index == LB_ERR) return;
    	student* pSt = (student*)m_listBox.GetItemDataPtr(index);
    	m_id = pSt->GetId();
    	m_name = pSt->GetName();
    	m_oop = pSt->GetOop();
    	m_math = pSt->GetMath();
    	m_age = pSt->Getage();
    	m_adress = pSt->Getadress();//获取数据
    	UpdateData(FALSE);//更新到各个框中
    }
    BOOL Dlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    
    	// TODO:  在此添加额外的初始化
    
    	auto sts = pDoc->Getmanagerment()->GetStudents();
    	for (auto iter = sts->begin(); iter != sts->end(); ++iter)
    	{
    		auto st = *iter;
    		CString temp;
    		char m_sex2;//性别
    		if (m_sex == TRUE) m_sex2 = 'm';
    		else m_sex2 = 'w';
    		temp.Format("%d %s %f %f %c %d %s", st->GetId(), st->GetName(), st->GetOop(), st->GetMath(),st->Getsex(), st->Getage(), st->Getadress());//转化为字符串
    		m_listBox.AddString(temp);
    		m_listBox.SetItemDataPtr(m_listBox.GetCount() - 1, st);//将序号与内容关联
    	}
    
    	
    	return TRUE;  // return TRUE unless you set the focus to a control
    	// 异常: OCX 属性页应返回 FALSE
    }
    
    
    展开全文
  • 手把手教你利用爬虫爬网页(Python代码)

    万次阅读 多人点赞 2019-05-14 14:34:48
    网络爬虫(又被称为网页蜘蛛、网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。下面通过图3-1展示一下网络爬虫在互 联网中起到的作用: ▲图3-1 网络爬虫 网络爬虫按照系统结构和实现技术...

    640?wx_fmt=jpeg

    本文主要分为两个部分:一部分是网络爬虫的概述,帮助大家详细了解网络爬虫;另一部分是HTTP请求的Python实现,帮助大家了解Python中实现HTTP请求的各种方式,以便具备编写HTTP网络程序的能力。


    01

    网络爬虫概述


    接下来从网络爬虫的概念、用处与价值和结构等三个方面,让大家对网络爬虫有一个基本的了解。

    1. 网络爬虫及其应用

    随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战,网络爬虫应运而生。网络爬虫(又被称为网页蜘蛛、网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。下面通过图3-1展示一下网络爬虫在互联网中起到的作用:


    640?wx_fmt=png

    ▲图3-1 网络爬虫


    网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:通用网络爬虫、聚焦网络爬虫、增量式网络爬虫、深层网络爬虫。实际的网络爬虫系统通常是几种爬虫技术相结合实现的。

    搜索引擎(Search Engine),例如传统的通用搜索引擎baidu、Yahoo和Google等,是一种大型复杂的网络爬虫,属于通用性网络爬虫的范畴。但是通用性搜索引擎存在着一定的局限性:

    1. 不同领域、不同背景的用户往往具有不同的检索目的和需求,通用搜索引擎所返回的结果包含大量用户不关心的网页。

    2. 通用搜索引擎的目标是尽可能大的网络覆盖率,有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。

    3. 万维网数据形式的丰富和网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力,不能很好地发现和获取。

    4. 通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询。

    为了解决上述问题,定向抓取相关网页资源的聚焦爬虫应运而生。

    聚焦爬虫是一个自动下载网页的程序,它根据既定的抓取目标,有选择地访问万维网上的网页与相关的链接,获取所需要的信息。与通用爬虫不同,聚焦爬虫并不追求大的覆盖,而将目标定为抓取与某一特定主题内容相关的网页,为面向主题的用户查询准备数据资源。

    说完了聚焦爬虫,接下来再说一下增量式网络爬虫。增量式网络爬虫是指对已下载网页采取增量式更新和只爬行新产生的或者已经发生变化网页的爬虫,它能够在一定程度上保证所爬行的页面是尽可能新的页面。

    和周期性爬行和刷新页面的网络爬虫相比,增量式爬虫只会在需要的时候爬行新产生或发生更新的页面,并不重新下载没有发生变化的页面,可有效减少数据下载量,及时更新已爬行的网页,减小时间和空间上的耗费,但是增加了爬行算法的复杂度和实现难度。

    例如:想获取赶集网的招聘信息,以前爬取过的数据没有必要重复爬取,只需要获取更新的招聘数据,这时候就要用到增量式爬虫。

    最后说一下深层网络爬虫。Web页面按存在方式可以分为表层网页和深层网页。表层网页是指传统搜索引擎可以索引的页面,以超链接可以到达的静态网页为主构成的Web页面。深层网络是那些大部分内容不能通过静态链接获取的、隐藏在搜索表单后的,只有用户提交一些关键词才能获得的Web页面。

    例如用户登录或者注册才能访问的页面。可以想象这样一个场景:爬取贴吧或者论坛中的数据,必须在用户登录后,有权限的情况下才能获取完整的数据。

    2. 网络爬虫结构

    下面用一个通用的网络爬虫结构来说明网络爬虫的基本工作流程,如图3-4所示。


    640?wx_fmt=png

    ▲图3-4 网络爬虫结构

    网络爬虫的基本工作流程如下:

    1. 首先选取一部分精心挑选的种子URL。

    2. 将这些URL放入待抓取URL队列。

    3. 从待抓取URL队列中读取待抓取队列的URL,解析DNS,并且得到主机的IP,并将URL对应的网页下载下来,存储进已下载网页库中。此外,将这些URL放进已抓取URL队列。

    4. 分析已抓取URL队列中的URL,从已下载的网页数据中分析出其他URL,并和已抓取的URL进行比较去重,最后将去重过的URL放入待抓取URL队列,从而进入下一个循环。

    02

    HTTP请求的Python实现


    通过上面的网络爬虫结构,我们可以看到读取URL、下载网页是每一个爬虫必备而且关键的功能,这就需要和HTTP请求打交道。接下来讲解Python中实现HTTP请求的三种方式:urllib2/urllib、httplib/urllib以及Requests。

    1. urllib2/urllib实现

    urllib2和urllib是Python中的两个内置模块,要实现HTTP功能,实现方式是以urllib2为主,urllib为辅。

    1.1 首先实现一个完整的请求与响应模型

    urllib2提供一个基础函数urlopen,通过向指定的URL发出请求来获取数据。最简单的形式是:

    
     

    import urllib2
    response=urllib2.urlopen('http://www.zhihu.com')
    html=response.read()
    print html

    其实可以将上面对http://www.zhihu.com的请求响应分为两步,一步是请求,一步是响应,形式如下:

    
     

    import urllib2
    # 请求
    request=urllib2.Request('http://www.zhihu.com')
    # 响应
    response = urllib2.urlopen(request)
    html=response.read()
    print html

    上面这两种形式都是GET请求,接下来演示一下POST请求,其实大同小异,只是增加了请求数据,这时候用到了urllib。示例如下:

    
     

    import urllib
    import urllib2
    url = 'http://www.xxxxxx.com/login'
    postdata = {'username' : 'qiye',
        'password' : 'qiye_pass'}
    # info 需要被编码为urllib2能理解的格式,这里用到的是urllib
    data = urllib.urlencode(postdata)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req)
    html = response.read()

    但是有时会出现这种情况:即使POST请求的数据是对的,但是服务器拒绝你的访问。这是为什么呢?问题出在请求中的头信息,服务器会检验请求头,来判断是否是来自浏览器的访问,这也是反爬虫的常用手段。

    1.2 请求头headers处理

    将上面的例子改写一下,加上请求头信息,设置一下请求头中的User-Agent域和Referer域信息。

    
     

    import urllib
    import urllib2
    url = 'http://www.xxxxxx.com/login'
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    referer='http://www.xxxxxx.com/'
    postdata = {'username' : 'qiye',
        'password' : 'qiye_pass'}
    # 将user_agent,referer写入头信息
    headers={'User-Agent':user_agent,'Referer':referer}
    data = urllib.urlencode(postdata)
    req = urllib2.Request(url, data,headers)
    response = urllib2.urlopen(req)
    html = response.read()

    也可以这样写,使用add_header来添加请求头信息,修改如下:

    
     

    import urllib
    import urllib2
    url = 'http://www.xxxxxx.com/login'
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    referer='http://www.xxxxxx.com/'
    postdata = {'username' : 'qiye',
        'password' : 'qiye_pass'}
    data = urllib.urlencode(postdata)
    req = urllib2.Request(url)
    # 将user_agent,referer写入头信息
    req.add_header('User-Agent',user_agent)
    req.add_header('Referer',referer)
    req.add_data(data)
    response = urllib2.urlopen(req)
    html = response.read()

    对有些header要特别留意,服务器会针对这些header做检查,例如:

    • User-Agent:有些服务器或Proxy会通过该值来判断是否是浏览器发出的请求。

    • Content-Type:在使用REST接口时,服务器会检查该值,用来确定HTTP Body中的内容该怎样解析。在使用服务器提供的RESTful或SOAP服务时,Content-Type设置错误会导致服务器拒绝服务。常见的取值有:application/xml(在XML RPC,如RESTful/SOAP调用时使用)、application/json(在JSON RPC调用时使用)、application/x-www-form-urlencoded(浏览器提交Web表单时使用)。

    • Referer:服务器有时候会检查防盗链。

    1.3 Cookie处理

    urllib2对Cookie的处理也是自动的,使用CookieJar函数进行Cookie的管理。如果需要得到某个Cookie项的值,可以这么做:

    
     

    import urllib2
    import cookielib
    cookie = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
    response = opener.open('http://www.zhihu.com')
    for item in cookie:
        print item.name+':'+item.value

    但是有时候会遇到这种情况,我们不想让urllib2自动处理,我们想自己添加Cookie的内容,可以通过设置请求头中的Cookie域来做:

    
     

    import  urllib2
    opener = urllib2.build_opener()
    opener.addheaders.append( ( 'Cookie''email=' + "xxxxxxx@163.com" ) )
    req = urllib2.Request( "http://www.zhihu.com/" )
    response = opener.open(req)
    print response.headers
    retdata = response.read()

    1.4 Timeout设置超时

    在Python2.6之前的版本,urllib2的API并没有暴露Timeout的设置,要设置Timeout值,只能更改Socket的全局Timeout值。示例如下:

    
     

    import urllib2
    import socket
    socket.setdefaulttimeout(10# 10 秒钟后超时
    urllib2.socket.setdefaulttimeout(10# 另一种方式

    在Python2.6及新的版本中,urlopen函数提供了对Timeout的设置,示例如下:

    
     

    import urllib2
    request=urllib2.Request('http://www.zhihu.com')
    response = urllib2.urlopen(request,timeout=2)
    html=response.read()
    print html

    1.5 获取HTTP响应码

    对于200 OK来说,只要使用urlopen返回的response对象的getcode()方法就可以得到HTTP的返回码。但对其他返回码来说,urlopen会抛出异常。这时候,就要检查异常对象的code属性了,示例如下:

    
     

    import urllib2
    try:
        response = urllib2.urlopen('http://www.google.com')
        print response
    except urllib2.HTTPError as e:
        if hasattr(e, 'code'):
            print 'Error code:',e.code

    1.6 重定向

    urllib2默认情况下会针对HTTP 3XX返回码自动进行重定向动作。要检测是否发生了重定向动作,只要检查一下Response的URL和Request的URL是否一致就可以了,示例如下:

    
     

    import urllib2
    response = urllib2.urlopen('http://www.zhihu.cn')
    isRedirected = response.geturl() == 'http://www.zhihu.cn'

    如果不想自动重定向,可以自定义HTTPRedirectHandler类,示例如下:

    
     

    import urllib2
    class RedirectHandler(urllib2.HTTPRedirectHandler):
        def http_error_301(self, req, fp, code, msg, headers):
            pass
        def http_error_302(self, req, fp, code, msg, headers):
            result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, 
            msg, headers)
            result.status = code
            result.newurl = result.geturl()
            return result
    opener = urllib2.build_opener(RedirectHandler)
    opener.open('http://www.zhihu.cn')

    1.7 Proxy的设置

    在做爬虫开发中,必不可少地会用到代理。urllib2默认会使用环境变量http_proxy来设置HTTP Proxy。但是我们一般不采用这种方式,而是使用ProxyHandler在程序中动态设置代理,示例代码如下:

    
     

    import urllib2
    proxy = urllib2.ProxyHandler({'http''127.0.0.1:8087'})
    opener = urllib2.build_opener([proxy,])
    urllib2.install_opener(opener)
    response = urllib2.urlopen('http://www.zhihu.com/')
    print response.read()

    这里要注意的一个细节,使用urllib2.install_opener()会设置urllib2的全局opener,之后所有的HTTP访问都会使用这个代理。这样使用会很方便,但不能做更细粒度的控制,比如想在程序中使用两个不同的Proxy设置,这种场景在爬虫中很常见。比较好的做法是不使用install_opener去更改全局的设置,而只是直接调用opener的open方法代替全局的urlopen方法,修改如下:

    
     

    import urllib2
    proxy = urllib2.ProxyHandler({'http''127.0.0.1:8087'})
    opener = urllib2.build_opener(proxy,)
    response = opener.open("http://www.zhihu.com/")
    print response.read()


    2. httplib/urllib实现

    httplib模块是一个底层基础模块,可以看到建立HTTP请求的每一步,但是实现的功能比较少,正常情况下比较少用到。在Python爬虫开发中基本上用不到,所以在此只是进行一下知识普及。下面介绍一下常用的对象和函数:


    • 创建HTTPConnection对象:

      class httplib.HTTPConnection(host[, port[, strict[, timeout[, source_address]]]])。

    • 发送请求:

      HTTPConnection.request(method, url[, body[, headers]])。

    • 获得响应:

      HTTPConnection.getresponse()。

    • 读取响应信息:

      HTTPResponse.read([amt])。

    • 获得指定头信息:

      HTTPResponse.getheader(name[, default])。

    • 获得响应头(header, value)元组的列表:

      HTTPResponse.getheaders()。

    • 获得底层socket文件描述符:

      HTTPResponse.fileno()。

    • 获得头内容:

      HTTPResponse.msg。

    • 获得头http版本:

      HTTPResponse.version。

    • 获得返回状态码:

      HTTPResponse.status。

    • 获得返回说明:

      HTTPResponse.reason。

    接下来演示一下GET请求和POST请求的发送,首先是GET请求的示例,如下所示:

    
     

    import httplib
    conn =None
    try:
        conn = httplib.HTTPConnection("www.zhihu.com")
        conn.request("GET""/")
        response = conn.getresponse()
        print response.status, response.reason
        print '-' * 40
        headers = response.getheaders()
        for h in headers:
            print h
        print '-' * 40
        print response.msg
    except Exception,e:
        print e
    finally:
        if conn:
            conn.close()

    POST请求的示例如下:

    
     

    import httplib, urllib
    conn = None
    try:
        params = urllib.urlencode({'name''qiye''age'22})
        headers = {"Content-type""application/x-www-form-urlencoded"
        , "Accept""text/plain"}
        conn = httplib.HTTPConnection("www.zhihu.com"80, timeout=3)
        conn.request("POST""/login", params, headers)
        response = conn.getresponse()
        print response.getheaders() # 获取头信息
        print response.status
        print response.read()
    except Exception, e:
        print e
        finally:
        if conn:
            conn.close()

    3. 更人性化的Requests

    Python中Requests实现HTTP请求的方式,是本人极力推荐的,也是在Python爬虫开发中最为常用的方式。Requests实现HTTP请求非常简单,操作更加人性化。

    Requests库是第三方模块,需要额外进行安装。Requests是一个开源库,源码位于:

    GitHub: https://github.com/kennethreitz/requests

    希望大家多多支持作者。

    使用Requests库需要先进行安装,一般有两种安装方式:

    • 使用pip进行安装,安装命令为:pip install requests,不过可能不是最新版。

    • 直接到GitHub上下载Requests的源代码,下载链接为:

      https://github.com/kennethreitz/requests/releases

      将源代码压缩包进行解压,然后进入解压后的文件夹,运行setup.py文件即可。

    如何验证Requests模块安装是否成功呢?在Python的shell中输入import requests,如果不报错,则是安装成功。如图3-5所示。

    640?wx_fmt=png

    ▲图3-5 验证Requests安装

    3.1 首先还是实现一个完整的请求与响应模型

    以GET请求为例,最简单的形式如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    print r.content

    大家可以看到比urllib2实现方式的代码量少。接下来演示一下POST请求,同样是非常简短,更加具有Python风格。示例如下:

    
     

    import requests
    postdata={'key':'value'}
    r = requests.post('http://www.xxxxxx.com/login',data=postdata)
    print r.content

    HTTP中的其他请求方式也可以用Requests来实现,示例如下:

    
     

    r = requests.put('http://www.xxxxxx.com/put', data = {'key':'value'})
    r = requests.delete('http://www.xxxxxx.com/delete')
    r = requests.head('http://www.xxxxxx.com/get')
    r = requests.options('http://www.xxxxxx.com/get')

    接着讲解一下稍微复杂的方式,大家肯定见过类似这样的URL:

    http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1

    就是在网址后面紧跟着“?”,“?”后面还有参数。那么这样的GET请求该如何发送呢?肯定有人会说,直接将完整的URL带入即可,不过Requests还提供了其他方式,示例如下:

    
     

    import requests
        payload = {'Keywords''blog:qiyeboy','pageindex':1}
    r = requests.get('http://zzk.cnblogs.com/s/blogpost', params=payload)
    print r.url

    通过打印结果,我们看到最终的URL变成了:

    http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1

    3.2 响应与编码

    还是从代码入手,示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    print 'content-->'+r.content
    print 'text-->'+r.text
    print 'encoding-->'+r.encoding
    r.encoding='utf-8'
    print 'new text-->'+r.text

    其中r.content返回的是字节形式,r.text返回的是文本形式,r.encoding返回的是根据HTTP头猜测的网页编码格式。

    输出结果中:“text-->”之后的内容在控制台看到的是乱码,“encoding-->”之后的内容是ISO-8859-1(实际上的编码格式是UTF-8),由于Requests猜测编码错误,导致解析文本出现了乱码。Requests提供了解决方案,可以自行设置编码格式,r.encoding='utf-8'设置成UTF-8之后,“new text-->”的内容就不会出现乱码。

    但是这种手动的方式略显笨拙,下面提供一种更加简便的方式:chardet,这是一个非常优秀的字符串/文件编码检测模块。安装方式如下:

    
     

    pip install chardet

    安装完成后,使用chardet.detect()返回字典,其中confidence是检测精确度,encoding是编码形式。示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    print chardet.detect(r.content)
    r.encoding = chardet.detect(r.content)['encoding']
    print r.text

    直接将chardet探测到的编码,赋给r.encoding实现解码,r.text输出就不会有乱码了。

    除了上面那种直接获取全部响应的方式,还有一种流模式,示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com',stream=True)
    print r.raw.read(10)

    设置stream=True标志位,使响应以字节流方式进行读取,r.raw.read函数指定读取的字节数。

    3.3 请求头headers处理

    Requests对headers的处理和urllib2非常相似,在Requests的get函数中添加headers参数即可。示例如下:

    
     

    import requests
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers={'User-Agent':user_agent}
    r = requests.get('http://www.baidu.com',headers=headers)
    print r.content

    3.4 响应码code和响应头headers处理

    获取响应码是使用Requests中的status_code字段,获取响应头使用Requests中的headers字段。示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    if r.status_code == requests.codes.ok:
        print r.status_code# 响应码
        print r.headers# 响应头
        print r.headers.get('content-type')# 推荐使用这种获取方式,获取其中的某个字段
        print r.headers['content-type']# 不推荐使用这种获取方式
    else:
        r.raise_for_status()

    上述程序中,r.headers包含所有的响应头信息,可以通过get函数获取其中的某一个字段,也可以通过字典引用的方式获取字典值,但是不推荐,因为如果字段中没有这个字段,第二种方式会抛出异常,第一种方式会返回None。

    r.raise_for_status()是用来主动地产生一个异常,当响应码是4XX或5XX时,raise_for_status()函数会抛出异常,而响应码为200时,raise_for_status()函数返回None。

    3.5 Cookie处理

    如果响应中包含Cookie的值,可以如下方式获取Cookie字段的值,示例如下:

    
     

    import requests
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers={'User-Agent':user_agent}
    r = requests.get('http://www.baidu.com',headers=headers)
    # 遍历出所有的cookie字段的值
    for cookie in r.cookies.keys():
        print cookie+':'+r.cookies.get(cookie)

    如果想自定义Cookie值发送出去,可以使用以下方式,示例如下:

    
     

    import requests
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers={'User-Agent':user_agent}
    cookies = dict(name='qiye',age='10')
    r = requests.get('http://www.baidu.com',headers=headers,cookies=cookies)
    print r.text

    还有一种更加高级,且能自动处理Cookie的方式,有时候我们不需要关心Cookie值是多少,只是希望每次访问的时候,程序自动把Cookie的值带上,像浏览器一样。Requests提供了一个session的概念,在连续访问网页,处理登录跳转时特别方便,不需要关注具体细节。使用方法示例如下:

    
     

    import Requests
    oginUrl = 'http://www.xxxxxxx.com/login'
    s = requests.Session()
    #首先访问登录界面,作为游客,服务器会先分配一个cookie
    r = s.get(loginUrl,allow_redirects=True)
    datas={'name':'qiye','passwd':'qiye'}
    #向登录链接发送post请求,验证成功,游客权限转为会员权限
    r = s.post(loginUrl, data=datas,allow_redirects= True)
    print r.text

    上面的这段程序,其实是正式做Python开发中遇到的问题,如果没有第一步访问登录的页面,而是直接向登录链接发送Post请求,系统会把你当做非法用户,因为访问登录界面时会分配一个Cookie,需要将这个Cookie在发送Post请求时带上,这种使用Session函数处理Cookie的方式之后会很常用。

    3.6 重定向与历史信息

    处理重定向只是需要设置一下allow_redirects字段即可,例如:

    r=requests.get('http://www.baidu.com',allow_redirects=True)

    将allow_redirects设置为True,则是允许重定向;设置为False,则是禁止重定向。如果是允许重定向,可以通过r.history字段查看历史信息,即访问成功之前的所有请求跳转信息。示例如下:

    
     

    import requests
    r = requests.get('http://github.com')
    print r.url
    print r.status_code
    print r.history

    打印结果如下:

    
     

    https://github.com/
    200
    (<Response [301]>,)

    上面的示例代码显示的效果是访问GitHub网址时,会将所有的HTTP请求全部重定向为HTTPS。

    3.7 超时设置

    超时选项是通过参数timeout来进行设置的,示例如下:

    
     

    requests.get('http://github.com', timeout=2)

    3.8 代理设置

    使用代理Proxy,你可以为任意请求方法通过设置proxies参数来配置单个请求:

    
     

    import requests
    proxies = {
        "http""http://0.10.1.10:3128",
        "https""http://10.10.1.10:1080",
    }
    requests.get("http://example.org", proxies=proxies)

    也可以通过环境变量HTTP_PROXY和HTTPS_PROXY?来配置代理,但是在爬虫开发中不常用。你的代理需要使用HTTP Basic Auth,可以使用http://user:password@host/语法:

    
     

    proxies = {
        "http""http://user:pass@10.10.1.10:3128/",
    }


    03

    小结


    本文主要讲解了网络爬虫的结构和应用,以及Python实现HTTP请求的几种方法。希望大家对本文中的网络爬虫工作流程和Requests实现HTTP请求的方式重点吸收消化。

    本文摘编自《Python爬虫开发与项目实战》,经出版方授权发布。

    关于作者:范传辉,资深网虫,Python开发者,参与开发了多项网络应用,在实际开发中积累了丰富的实战经验,并善于总结,贡献了多篇技术文章广受好评。研究兴趣是网络安全、爬虫技术、数据分析、驱动开发等技术。

    640?wx_fmt=jpeg

    Python爬虫开发与项目实战

    扫码购买

    640?wx_fmt=png


    本书特色:

    • 由浅入深,从Python和Web前端基础开始讲起,逐步加深难度,层层递进。

    • 内容详实,从静态网站到动态网站,从单机爬虫到分布式爬虫,既包含基础知识点,又讲解了关键问题和难点分析,方便读者完成进阶。

    • 实用性强,本书共有9个爬虫项目,以系统的实战项目为驱动,由浅及深地讲解爬虫开发中所需的知识和技能。

    • 难点详析,对js加密的分析、反爬虫措施的突破、去重方案的设计、分布式爬虫的开发进行了细致的讲解。

    扫码购买

    640?wx_fmt=png

    展开全文
  • 面向对象程序设计概念

    千次阅读 2019-09-26 17:03:28
    程序设计范型是设计程序的规范、模型和风格,它是一类程序设计语言的基础。 面向对象设计范型的主要特征是:  程序=对象+消息   面向对象程序的基本元素是对象。面向对象程序的主要结构特点是:一、程序...

    一. 程序设计范型

      面向对象程序设计(object-oriented programming,OOP)是一种新的程序设计的范型。程序设计范型是设计程序的规范、模型和风格,它是一类程序设计语言的基础。
    面向对象设计范型的主要特征是:

     程序=对象+消息

      面向对象程序的基本元素是对象。面向对象程序的主要结构特点是:一、程序一般由类的定义和类的使用两部分组成;二、程序中的一切操作都是向对象发送消息来实现的,对象收到消息后,启动有关方法完成相应的操作。
      需要说明的是,某一种程序设计语言不一定与一种程序设计范型相对应。实际上具有两种或多种范型特征的程序设计语言,即混合型语言。例如,C++就不是纯粹的面向对象程序设计范型的语言,而是具有面向过程程序设计范型和面向对象设计范型的混合性设计语言。

    二. 面向对象程序设计的基本概念

    1. 对象
     现实中的对象,具有以下特征:

    1. 每个对象必须有一个名字以区别其他对象;
    2. 用属性来描述对象的耨些特征;
    3. 有一组操作,每一组操作决定对象的一种行为;
    4. 对象的行为可以分为两类:一类作用于自身的行为,另一类作用与其他对象的行为。

    2. 类
      类是一组具有相同属性和行为的对象的抽象。类与对象之间的关系是抽象与具体的关系。类是对多个对象进行综合抽象的结果。

    3. 消息与方法
      面向对象程序设计中,对象之间也需要联系,称为对象的交互。面向对象程序设计技术必须提供一种机制允许一个对象与另一个对象的交互。这种机制称为消息传递。
      对象所能实现的行为(操作),在程序设计方法中称为方法。它们是通过调用相应的函数来实现的,在C++语言中方法是通过成员函数来实现的。方法包括界面和方法体两部分。方法的界面给出了方法名和调用协议(相对于C++中的成员函数的函数名和参数表);方法体则是实现某种操作的一系列计算步骤,也就是一段程序(相对于C++中成员函数的函数体)。

    三. 面向对象程序设计的基本特征

    1. 抽象
      抽象是通过特定的实例(对象)抽取共同性质后形成概念的过程。面向对象程序设计中的抽象包括两个方面:数据抽象和代码抽象(或称为行为抽象)。前者描述某类对象的属性或状态,也就是此类对象区别于彼类对象的特征物理量:后者描述了某类对象的共同行为特征或具有的共同功能。对于一组具有相同属性和行为的对象,可以抽象成一种类型,在C++中,这种类型就称为类(class),类是对象的抽象,而对象是类的实例。
      抽象在系统分析、系统设计以及程序设计的发展中一直起着重要的作用。在面向对象程序设计方法中,对一个具体问题的抽象分析的结果,是通过类来描述和实现的。

    2. 封装
      在现实世界中,所谓封装就是把某个事物包围起来,使外界不知道该事物的具体内容。在面向对象程序设计中,封装是指把数据和实现操作的代码集中起来放在对象内部,并尽可能隐蔽对象的内部细节。对象好像是一个不透明的黑盒子.表示对象属性的数据和实现各个操作的代码都被封装在黑盒子里,从外面是看不见的,更不能从外面直接访问或修改这些数据及代码。使用一个对象的时候,只需知道它向外界提供的接口而无需知道它的数据结构细节和实现操作的算法。
      C++对象中的函数名就是对象的对外接口,外界可以通过函数名来调用这些函数来实现某些行为(功能)。封装的好处是可以将对象的使用者与设计者分开,大大降低了人们操作对象的复杂度。使用者不必知道对象行为实现的细节,只需要使用设计者提供的接口的功能即可自由地操作对象。封装的结果实际上隐藏了复杂性,并提供了代码重用性,从而减轻了开发软件系统的难度。
      封装是面向对象程序设计方法的一个重要特性,封装具有两方面的含义:一是将有的数据和操作代码封装在一个对象中,各个对象相对独立、互不干扰;二是将对象中某此据与操作代码对外隐蔽,即隐蔽其内部细节,只留下少量接口,以便与外界联系,接收外界消息,这种对外界隐蔽的做法称为信息隐蔽。信息隐蔽有利于数据安全,防止无关人员访和修改数据。

    3. 继承
      继承是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 从继承源上分,继承又分为单继承和多继承。

    4. 多态
      面向对象系统的多态性是指不同的对象收到相同的消息时执行不同的操作。
      C++语言支持两种多态性即编译时的多 态性和运行时的多态性。 编译时的多态性是通过函数重载(包括运算符重载)来实现的,运行时的多态性是通过虚函数来实现的。
      多态性增强了软件的灵活性和重用性,为软件的开发与维护提供了极大的便利。尤其是采用了虚函数和动态联编机制后,允许用户以更为明确、易懂的方式建立通用的软件。

    展开全文
  • 但是,我们在实际应用中发现,SpringMVC可以完全替代Struts,配合注解的方式,编程非常快捷,而且通过restful风格定义url,让地址看起来非常优雅。 另外,MyBatis也可以替换Hibernate,正因为MyBatis的半自动特点,...
  • 网页设计\网页制作常用软件大全

    千次阅读 多人点赞 2014-03-04 12:08:26
    网页设计\网页制作常用软件 一、专业的网页设计、网页制作软件: 1、CorelDraw:通过CorelDRAW9的全方面的设计及网页功能融合到现有的设计方案中,制作矢量的插图、设计及图像,出色地设计公司标志、简报、彩页、...
  • 人工智能时代,所需要了解人工智能的基本常识

    万次阅读 多人点赞 2018-12-10 22:49:44
     算法是解决一个设计程序或完成任务的路径方法。最近几年,新算法的发展极大提高了机器学习的能力,这些算法本身很重要,同时也是其他技术的推动者,比如计算机视觉(这项科技将会在后文描述)。机器学习算法目前被...
  • 良好的编程风格(一)

    千次阅读 2010-10-16 19:33:00
    大多数程序员只是关注程序的可行性,而忽略了可读性,可移植性和健壮性,其实我个人认为,程序的可行性和健壮性与程序的可读性有很大的关系,能写出可读性很好的程序的程序员,他写的程序的可行性和健壮性必然不会差,也会...
  • C#基础教程-c#实例教程,适合初学者

    万次阅读 多人点赞 2016-08-22 11:13:24
    本章介绍C#语言的基础知识,希望具有C语言的读者能够基本掌握C#语言,并以此为基础,能够进一步学习用C#语言编写window应用程序和Web应用程序。当然仅靠一章的内容就完全掌握C#语言是不可能的,如需进一步学习C#语言...
  • 工具栏是标准的Windows应用程序风格。 标准工具栏: 视图工具栏: 图13.1-3是主工具栏及按钮名称,图13.1-4是元器件工具栏及按钮名称,图13.1-5是虚拟仪器工具栏及仪器名称。 图13.1-3 Multisim主工具栏 图...
  • 史上最全面Java面试汇总(面试题+答案)

    万次阅读 多人点赞 2018-07-06 14:09:25
    可以设计出低耦合的系统,使系统更加灵活、更加易于维护 缺点:性能比面向过程低 2.Java的四个基本特性(抽象、封装、继承,多态) 抽象:就是把现实生活中的某一类东西提取出来,用程序代码表示,我们通常叫做类...
  • 基于协同过滤算法的电影推荐系统

    千次阅读 2019-08-23 23:34:19
    目录前言R语言 电影推荐系统案例及代码数据准备数据预处理建立模型 前言 电影推荐系统是数学建模培训中一次例题,网上对相同类型的模型已有答案,但相关代码跑起来仍然存在些许bug,本文基于同类型的基础上能帮助...
  • 程序设计语言诞生  1946冯·诺依曼提出了冯·诺依曼原理:  CPU逐条从存储器中取出指令执行,按指令取出存储的数据经运算后送回。  数据和指令(存储地址码、操作码)都统一按二进制编码输入。数据值的改变是重新...
  • Linux程序设计 第4版 mobi格式

    热门讨论 2014-01-18 21:35:54
    为x视窗系统建立图形化用户界面等 《Linux程序设计 第4版 》通过先介绍程序设计理论 再以适当的例子和清晰的解释来阐明它的方式 帮助读者迅速掌握相关的知识 《Linux程序设计 第4版 》适合Linux的初学者及希望利用...
  • WPF开发教程

    万次阅读 多人点赞 2019-07-02 23:13:20
    在 WPF 的早期设计阶段,曾有过大量关于如何界定系统的托管组件和非托管组件的争论。CLR 提供一系列的功能,可以令开发效率更高并且更加可靠(包括内存管理、错误处理和通用类型系统等),但这是需要付出代价的。 ...
  • 体系结构设计风格

    千次阅读 2016-04-05 17:28:07
    调用/返回风格:主程序/子程序、层次结构,客户机/服务器,面向对象风格 独立部件风格:进程通讯、事件驱动 虚拟机风格:解释器、基于规则的系统 数据共享风格:数据库系统、黑板系统二、管道-过滤器风格(Pipe-...
  • Python程序设计题库

    万次阅读 多人点赞 2020-03-28 17:39:40
    《Python程序设计》题库 一、 填空题 1、 Python安装扩展库常用的是_工具。(pip) 2、 Python标准库math中用来计算平方根的函数是____。(sqrt) 3、 Python程序文件扩展名主要有__和两种,其中后者常用于GUI程序...
  • 软件测试入门知识了解

    万次阅读 多人点赞 2018-09-05 14:59:58
    需求评审和设计评审是验证软件产品的需求定义和设计实现,验证所定义的产品特性是否符合客户的期望、系统的设计是否合理、是否具有可测试性以及满足非功能质量特性的要求。这个阶段主要通过对需求文档、设计文档等...
  • 程序设计语言简史

    千次阅读 2016-12-03 16:53:31
    程序设计语言诞生  1946冯·诺依曼提出了冯·诺依曼原理:  CPU逐条从存储器中取出指令执行,按指令取出存储的数据经运算后送回。  数据和指令(存储地址码、操作码)都统一按二进制编码输入。数据值的改变是重新...
  • 【面试笔试】程序设计基础

    千次阅读 2016-05-05 17:35:48
    一.程序设计方法与风格 ...对建立良好程序设计风格,下面的描述正确的是(A ) A.程序应简单、清晰、可读性好 B.符号名的命名只要符合语法 C.充分考虑程序的执行效率 D.程序的注释可有可无 在设计程序时.应采纳的
  • 软件系统架构是关于软件系统的 结构、行为和属性 的高级抽象。指定了软件系统的组织结构和拓扑结构。 软件架构是可传递可复用的模型,架构就是体系结构。架构设计介于需求分析和软件设计之间。架构设计就是需求分配...
  • •javaScript程序(用于提高页面与用户的交互能力,其最大的特点就是可以读/写浏览器建立的DOM树,可以对浏览器端的鼠标键盘事件作响应,可以对采集的数据作验证,可以检测浏览器的类型等。浏览器内嵌有JavaScr...
  • verilog 综合注意事项

    万次阅读 多人点赞 2016-07-29 15:46:40
    *看了5本书,居然没有一本书讲到能否综合,所以设计出来的程序完全不能用~~~ * *而且,书中都是讲语句的具体使用办法,例如always @(),但是什么时候用always,几个always之间、时序电路、逻辑电路、任务与函数...
  • 软件工程期末复习总结

    万次阅读 多人点赞 2016-07-03 15:22:39
    只是一个开发过程,并没有涵盖软件过程的全部 内容,例如它缺少关于软件运行和支持等方面的内容;此外,它没有支持多项目的开发结构,这在一定程度上降低了在开发组织内大范围实现重用的可能性。可以说  RUP 是一...
  • 《图书管理系统》毕业论文

    万次阅读 多人点赞 2008-11-24 11:13:00
    图书管理系统毕业论文图书馆管理系统目录 0 前言 1系统设计1.1系统目标设计 1.2开发设计思想 1.3开发和运行环境选择 1.4系统功能分析 1.5系统功能模块设计 2数据库设计2.1数据库需求分析2.2数据库逻辑结构...
  • Linux程序设计中文版(第四版)

    热门讨论 2013-07-03 19:55:37
    《Linux程序设计(第4版)》讲述了Linux系统及其他IJNIX风格的操作系统上的程序开发,主要内容包括标准Linux c语言函数库和由不同的Linux或UNIX标准指定的各种工具的使用方法,大多数标准Linux开发工具的使用方法,...
  • 了解RESTful接口设计风格

    千次阅读 2018-10-03 21:20:13
    1、RESTful发展背景及简介 网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、...RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。 REST(Representati...
  • 全国计算机等级考试二级 C 语言 程序设计考试大纲

    千次阅读 多人点赞 2021-01-06 15:33:05
    2. 掌握结构化程序设计的方法,具有良好程序设计风格。 3. 掌握程序设计中简单的数据结构和算法并能阅读简单的程序。 4. 在Visual C++ 集成环境下,能够编写简单的 C 程序,并具有基本的纠错和调试程序的 ...
  • 《Windows程序设计》复习题

    万次阅读 多人点赞 2016-05-24 13:37:35
    《Windows程序设计》复习题,包含windows程序设计和MFC程序设计的众多知识点。
  • 基于物品的协同过滤算法实现图书推荐系统

    万次阅读 多人点赞 2019-09-14 21:20:24
    Python的程序设计和编写时间更短、出错更少也是基于此特性。 4)主机语言与其通信可以方便的被嵌入,可以用C语言编写对于一些对性能特别强调的地方,这些扩展在python中被调用以实现性能改进的目的。相反,Python解释...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 91,765
精华内容 36,706
关键字:

关于建立良好的程序设计风格