• python自动化学习笔记3-集合、函数、模块


    文件操作

    上次学习到文件的读写,为了高效的读写文件,我们可以用循环的方式,一行一行的进行读写操作,打开文件的方法是open的方法,打开文件执行完后还要进行关闭操作。

    一般的文件流操作都包含缓冲机制,write方法并不直接将数据写入文件,而是先写入内存中特定的缓冲区。

    正常情况下缓冲区满时,操作系统会自动将缓冲数据写入到文件中。

    至于close方法,原理是内部先调用flush方法来刷新缓冲区,再执行关闭操作,这样即使缓冲区数据未满也能保证数据的完整性。

    如果进程意外退出或正常退出时而未执行文件的close方法,缓冲区中的内容将会丢失。

    所以我们通常用flush方法刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区。如下:

    f=open('www','a+',encoding='utf-8')
    f.
    f.write('hahah ')
    f.flush()
    f.close()

    还有一种打开文件的方式,可以自动关闭文件,防止open方式忘记手动关闭文件。

    with open('aaa','a+',encoding='utf-8') as f:
    f.seek(0)
    f.write('haha ')
    f.flush()

    在 “with” 打开的代码块内,文件是打开的,而且可以自由读取。 然而,一旦Python代码从 “with” 负责的代码段退出,文件会自动关闭。

    用with打开文件的时候可以打开多个,用逗号分开就好:

    
    
    with open('aaa','a+',encoding='utf-8') as f,open('www','w',encoding='utf-8')as w:
    f.seek(0)
    f.write('haha ')
    f.flush()
    w.write('再见你好!')

    打开多个文件时,我们就可以对多个文件同时进行操作了。

    在文件操作时可能会遇到需要下载图片或视频的内容,如果我们要下载一个网站的图片,进行保存,由于图片地址时http协议的,所以我们需要用到request处理HTTP的功能。

    import requests
    url='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1515432257731&di=feaf94121db96dc3e315f6c170e0d5a0&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F1e30e924b899a901934d50551d950a7b0208f55d.jpg'
    img=requests.get(url).content
    f=open('ooo.jpg','wb')
    f.write(img)

    wb模式时文件的一种操作模式,wb代表以二进制的格式写文件,还有以下几种方式:

    "rb"   以二进制读方式打开,只能读文件 , 如果文件不存在,会发生异常      

    "wb" 以二进制写方式打开,只能写文件, 如果文件不存在,创建该文件

                                                         如果文件已存在,先清空,再打开文件

    "rt"   以文本读方式打开,只能读文件 , 如果文件不存在,会发生异常      

    "wt" 以文本写方式打开,只能写文件, 如果文件不存在,创建该文件

                                                         如果文件已存在,先清空,再打开文件

    "rb+"   以二进制读方式打开,可以读、写文件 , 如果文件不存在,会发生异常      

    "wb+" 以二进制写方式打开,可以读、写文件, 如果文件不存在,创建该文件

                                                         如果文件已存在,先清空,再打开文件

    实战练习:

    用学过的知识完成下面的小程序:

    将文件中的内容个别文字进行批量替换。

    with open('ttt','a+',encoding='utf-8')as f:
    f.seek(0)
    content=f.read()
    new_content=content.replace('终于','还好')
    f.seek(0)
    f.truncate()
    f.write(new_content)
    f.flush()

    上述方法我们直接取出所有内容,然后进行替换,清空源文件后再写入所有内容,这样的效率时不高的,文件小的时候还好,当文件有大量数据的时候,这种方法的效率就太低了。

    我还可以用for循环的方式,进行逐行读取,逐行修改的方式,但在文件中我们没办法在原文件中取读完每一行就立马进行修改

    所以可以分为以下几个步骤进行:

    1、逐行高效读取文件,进行修改

    2、将修改后的内容写入一个新的文件中

    3、修改完成后删除原有文件

    4、将新文件的名称修改为目标文件的名称

    import os#导入文件操作模块
    with open('ttt','r',encoding='utf-8')as f,open('new','a+',encoding='utf-8')as newf:#打开要修改的文件和一个新文件
    for content in f:#遍历文件内容
    new_content=content.replace('还好','终于')#替换文字
    newf.write(new_content)#写入新文件
    newf.flush()#立即刷新
    os.remove('ttt')#删除原有文件
    os.rename('new','ttt')#重命名文件

    集合

    在Python中集合set是基本数据类型的一种,它有可变集合(set)和不可变集合(frozenset)两种。创建集合set、集合set添加、集合删除、交集、并集、差集的操作都是非常实用的方法。

     集合的一个特点是天生去重

    创建集合:

    
    
    s=set()#空集合
    s2={'1','2','3','3','3'}
    list=[1,2,3,4,5,5,5,5,5,5]
    s3=set(list)
    #list 去重的话,需要循环取出比较
    print(list)
    print(s2)
    print(s3)

    查看执行结果:

    [1, 2, 3, 4, 5, 5, 5, 5, 5, 5]
    {'2', '3', '1'}
    {1, 2, 3, 4, 5}

    取集合的数据

    s2={'1','2','3','3','3'}
    #集合是无序的,没有办法通过下标来取数据
    print(s2[2])

    查看执行结果:

    添加元素

     s2={'1','2','3','3','3'}
    s2.add('5')#add方法可以添加一个元素
    print(s2)

     查看执行结果:

    {'5', '2', '1', '3'}

    如果想添加多个元素的话,可以用update

     s2={'1','2','3','3','3'}
    s2.update([7,8,9]) # 添加多个元素
    print(s2)

     执行查看结果:

    {7, '2', 8, 9, '1', '3'}

    删除元素

    删除元素可以用pop()随机删除一个元素:

    s2={'1','2','3','4','8','9'}
    print(s2.pop())
    print(s2)

    查看执行结果:

    2
    {'9', '1', '8', '4', '3'}

    集合的运算操作:

    交集、并集、差集、子集、包含

    s2={'1','2','3','5'}
    s3={'1','2','3','4','8','9'}


    #交集
    print(s2.intersection(s3))#intersection
    print(s2&s3)#&f符号是取交集

    查看执行结果:

    {'1', '3', '2'}
    {'1', '3', '2'}

    #并集
    print(s2.union(s3))#union取并集
    print(s2|s3)#|取并集

    查看执行结果:

    {'8', '3', '5', '2', '1', '4', '9'}
    {'8', '3', '5', '2', '1', '4', '9'}

    # #差集
    print(s2.difference(s3))#S2中有,但是S3中没有的
    print(s3.difference(s2))#s3中有,但是s2中没有的
    print(s2-s3)#-代表差集,S2中有,但是S3中没有的

    查看执行结果:

    {'5'}
    {'4', '8', '9'}
    {'5'}

    子集、包含关系:

    s2={'1','2','3'}
    s3={'1','2','3','4','8','9'}
    print(s2.issubset(s3)) #S2是S3的子集
    print(s3.issuperset(s2))#S3包含S2

    查看执行结果

    True
    True

    函数

    函数是把一堆代码合到一起,变成一个整体,是一个方法或者功能的代码段,可以重复使用。

    定义一个函数的规则:

    • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()
    • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
    • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
    • 函数内容以冒号起始,并且缩进。
    • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

    定义一个函数,并调用:hello world!

    def hello():
    print('hello world!')
    hello() #函数的调用

    查看执行结果:

    hello world!

    再来看一个实例:

    
    
    def hello():
    f=open('sss','a+')
    f.seek(0)
    f.write('www')
    f.close()
    hello()

    查看执行结果:SSS文件中写入了www

    参数传递

    在 python 中,类型属于对象,变量是没有类型的

    a=[1,2,3]
    
    a="Runoob"

    以上代码中,[1,2,3] 是 List 类型,"Runoob" 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是 List 类型对象,也可以指向 String 类型对象。

    实例:def hello(filename,content=''):#形参,形式参数
    f = open(filename, 'a+',encoding='utf-8')
    #return #函数中添加return时,结束后边的代码
    if content:
    f.seek(0)
    f.write(content)
    res=''
    else:
    f.seek(0)
    res=f.read()
    #return res return以后文件就不会被关闭了,所以要把return写到后边
    f.close()
    return res
    print(hello('www','乒乒乓乓乒乒乓乓乒乒乓乓'))#实参,实际的参数
    users=hello('aaa')
    print(users)


    上述代码我们可以看到,当content为空或不为空的时候会有一个判断,一个用来读文件,一个用来写文件
    形参,实参
    #形参,位置参数也叫必填参数
    #默认参数,定义是有一个默认值
    #默认值参数是不必填的
    #函数里边的变量只能在函数里边用,出了函数里边就不能用了,如果想获取到函数的处理结果,必须return
    #没有return的话,返回的是none,return是非必填的,需要返回值的时候再写
    #函数中遇到return,函数运行结束
    #所以return的两个作用:1、返回函数值,2、结束运行

    可变参数,默认参数,扩展参数(不定长参数)
    def test(a,b=1,*args):#b=1为默认参数,默认参数为非必填
    print('a',a)
    print('b',b)
    print('args',args)
    test('hhh')
    test('aaa','222','22233','44444','5555')#位置调用,根据参数的位置指定
    test(b=5,a=10)#关键字参数,关键字调用,与位置调用不能混用
    查看执行结果:
    a hhh
    b 1
    args ()
    a aaa
    b 222
    args ('22233', '44444', '5555')
    a 10
    b 5
    args ()
    *args是可扩展参数,
    可扩展参数为非必填参数,会把多传的参数放到一个元祖中,可以自己定义名字。

    参数为字典表的时候:
    def test2(**kwargs):#keargs 字典
    print(kwargs)
    test2(name='222',sex='eee')#kwargs方式必须用关键字调用的方法

    def test3(a,**kwargs):
    print(a)
    print(kwargs)
    test3(a=10000,s='sss',d='ssss3')
    查看执行结果:
    {'sex': 'eee', 'name': '222'}
    10000
    {'d': 'ssss3', 's': 'sss'}

    全局变量和局部变量

    定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

    局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

    如下实例:

    
    
    a=100      #全局变量
    def test():
    a=5 #局部变量
    print('函数内部:',a)
    def test2():
    b=1
    print(a)#获取的全局变量100
    test()
    test2()
    print('函数外部',a)#直接打印的外部的全局变量
    查看执行结果:
    函数内部: 5
    100
    函数外部 100

    如果函数内部要使用全局变量的话,可以单独进行声明:例如:
    #
    d=100
    def test():
    global d#声明一下这是全局变量
    print('libian',d)
    d=6
    test()
    print('waibian',d)

    查看执行结果:
    libian 100
    waibian 6
    我们看到函数内部因为生命了d为全局变量,所以执行的时候首先取全局变量d=100,然后对d进行了修改为d=6,所以全局变量变为6,再次打印的时候显示为6.
    我们看一下下边这个例子:
    money = 899
    def test(consume):
    return money-consume
    def test1(money):
    return test(money)+test(money)
    money=test1(money)
    print(money)
    可以先预计一下执行结果,money=test1(money),先调用test1,money=899,执行test1又会调用test,传参都是money,所以test执行后是0,test1执行是0+0=0;
    我们执行一下看预期结果:0 #执行结果是0,预期正确
    再看一下下边的例子:
    def test():
    global f
    f=5
    print(f)
    def test1():
    c=f+5
    return c
    res=test1()
    print(res)
    看上边的例子,有的朋友会预期,调用test1,c=f+5,f=5,所以结果应该是10,我们执行看一下结果:

    从执行结果看到报错了,因为没有f没有定义,那是因为我们调用的时候只调用了test1,没有调用test,所以系统是不知道f的值的,只有调用的时候才会进行运算。
    正确的是:
    def test():
    global f
    f=5
    print(f)
    def test1():
    c=f+5
    return c
    test()#需要调用才会执行test,不调用不执行
    res=test1()
    print(res)
    查看执行结果:10
    实例演练:
    写一个小程序,校验输入的字符串是否是一个合法的小数。
    分析:1、小数分为正小数和负小数:例3.3,-2.33
    2、小数有且只有一个小数点
    3、校验字符串就要先把输入的内容强制类型转换成字符串类型
    
    
    def check_float(number):
    if number.count('.') == 1:#判断小数点的个数
    num_left=number.split('.')[0]#以小数点为分割点
    num_rigth=number.split('.')[1]
    if num_left.isdigit() and num_rigth.isdigit():#小数点左边和右边都是数字,则为正小数
    print('您输入的是正小数')
    elif number.count('-')==1 and number.startswith('-'):#判断符号的个数,且以负号开头
    if num_left.split('-')[1].isdigit() and num_rigth.isdigit():#小数点左边,负号右边都是数字,小数点右边都是数字
    print('您输入的是负小数')
    else:
    print('您输入的不是小数')
    else:
    print('您输入的不是小数')
    else:
    print('您输入的不是小数!')

    str=input('请输入要校验的字符串:')#input输入的就是字符串类型
    check_float(str)#调用函数
    大家可以自己试一下执行一下结果。

    递归
    在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
    下面看一个例子:
    def test1():
    num =int(input('请输入数字:'))
    if num%2==0:
    return True
    else:
    print('不是偶数请重新输入:')
    return test1()
    test1()
    上述代码,表达了输入一个数字,如果是偶数,返回True ,如果是计数再次调用test1,知道输入的是偶数返回True为止。这种我们就叫它递归函数。
    递归函数的优点是定义简单,逻辑清晰。
    但是使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,
    每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。递归最多调用999次;

    比较两个字典的key和value:
    ########################################
    #对比两个报文中不一样值
    #1、循环第一个字典,取出key
    #2、拿第一个的key去第二个的字典中去取值

    d1={'a':'1','b':'2'}
    d2={'a':'1','b':'3'}
    def compare(d1,d2):
    for key in d1:
    v1=d1.get(key)
    v2=d2.get(key)
    if v2:
    if v1==v2:
    pass
    else:
    print('两个值不一样,不一样的key:%s,v1的值:%s,v2的值:%s'%(key,v1,v2))
    compare(d1,d2)
    查看执行结果:
    两个值不一样,不一样的key:b,v1的值:2,v2的值:3

    判断对象的数据类型方法,可以用type()方法,如:


    def print_var_type(var):
    if type(var)==str:#字符串类型
    print('string')
    elif type(var)==dict:#字典类型
    print('dict')
    elif type(var)==list:#列表类型
    print('list')


    s={'name':'pei'}
    print_var_type(s)

    执行查看结果:

    dict

    模块

    在Python中用关键字import来引入某个模块,比如要引用模块math,就可以在文件最开始的地方用import math来引入。

    如果需要调用模块中的函数的话,需要用   模块名.函数名  进行调用。

    #一个python文件就是一个模块
    #1、标准模块
    # python自带的,不需要安装的
    #2、第三方模块
    # 别人写的,只要安装就能使用
    #3、自己写的模块
    # pip install radis #直接pip install 就可以 在 python安装目录下的scripts,加到环境变量中
    #下载好安装包手动安装,解压,在命令行里边进入到解压后的目录,在执行python setup.py install
    #或者进入到目录中,shift+右键,在当前窗口打开命令,输入python setup.py install

    例如上面的校验是否是小数的函数,存放在check.py文件中,如果需要直接调用函数,则需要导入这个模块,如下:


    import cheak
    print(cheak.check_float('1.6'))

    执行的话就会直接调用check中的check_float 函数。

    #导入python文件的实质是从头到尾运行一次
    #
    #import play
    #import 导入文件的时候是在当前目录下找文件,
    #当前目录找不到的话,从环境变量里面找
    #环境变量就是让一个命令在任何目录下都能执行
    #查看当前系统的环境变量目录
    import sys
    print(sys.path)

    实战演练:

    需求:access.log日志

    60S内同一个IP地址访问超过200次,IP加入黑名单
    #60s读一次文件
    #以空格切割,取第一个元素,获取到IP
    #把IP地址存入list,如果大于200次,则加入黑名单


    import time
    point = 0#文件指针

    while True:
    ips=[]#空列表,用于存放所有IP
    bip = set()#定义一个空集合,用于存放需要加入黑名单的
    with open('access.log') as f:
    f.seek(point)
    for line in f:
    ip=line.split()[0]#分割每一行,默认split是以空格分隔
    ips.append(ip)#添加到list
    if ips.count(ip)>199:#判断
    bip.add(ip)
    for i in bip:#bip为集合,存入的去重的ip
    print('已经把%s加入黑名单'%i)
    point=f.tell()
    time.sleep(60)
    else:
    print('没有被攻击')







  • 相关阅读:
    设计模式之适配器模式温故知新(九)
    设计模式之策略模式总结(八)
    设计模式之观察者模式, 个人感觉相当的重要(七)
    设计模式之抽象工厂模式读后(六)
    设计模式之工厂模式详细读后感TT!(五)
    设计模式之简单工厂模式, 加速(四)
    设计模式之代理模式笔记(三)
    设计模式之单例模式读后思考(二)
    为什么要用设计模式?先看看6大原则(一)
    Codeforces_835
  • 原文地址:https://www.cnblogs.com/phoebes/p/8245535.html
Copyright © 2020-2023  润新知