运维Python大全

运维Python大全

  • 运维Python大全
    • INSTALL PYTHONE3
    • Python syntax
      • 标题 合法的变量名,有三个要求
      • 1. 推荐采用的全名方法
      • 2. 标准算术运算符 + - * / // % **
      • 3. 比较运算符
      • 4. 逻辑运算符
    • 一 、python 数据类型
      • 1. 数字
      • 2. 字符串
      • 3.字符串切片
      • 4. 列表
      • 5. 元组
      • 6. 字典
    • 二、判断语句
      • 1. if 判断
      • 2. while循环
      • 3. 三元运算符,也叫条件表达式
      • 4. for循环
    • 三、实战案例应用
    • 四、文件对象
      • 1. 文件操作的基本步骤 -> 打开、读写、关闭
      • 2. 实操:在Linux服务器操作
      • 3. seek 和tell方法不常用,选修
      • 4. with
      • 练习:模拟cp操作
    • 五、函数
      • 1. 定义参数
      • 2. 模块:
      • 练习:生成随机密码
      • 3. shell 相关模块
      • 4. 变量赋值
      • 5. 多元赋值
      • 6. 合法标识符
      • 7. 关键字
      • 练习:查看有哪些关键字
      • 8. 内键
      • 9. 程序风格
      • 10. 编写程序的流程、步骤
      • 11. 序列类型操作符
      • 12. 内建函数(工厂函数)
      • 13. 字符串操作符
      • 14. 检查标识符
      • 15. 字符串格式化
      • 16. format函数
      • 练习:创建用户(Linux系统运行)
      • 17. 原始字符串操作符
      • 18. 字符串内建函数 (字符串操作)
      • 19. 字符串方法
      • 20. 创建及访问列表(列表list操作)
      • 20. 列表内建函数
      • 21. 单元素元组必须有逗号,否则不表示元组
      • 练习: 用列表构建栈结构
      • 22. 字典和集合/文件系统
      • 练习:通过key更新字典
      • 23. 字典内建方法
      • 24. Windows文本换行和Unix转换
      • 练习:编写类进度条程序
      • 25. 集合
      • 26. 集合类型操作符
      • 27. 集合内建方法
    • 六、简单模块
      • 1. time 模块
      • 2. datetime模块
      • 3. 异常
      • 异常处理 try - except 和try - finally
      • 4. OS模块
      • 5. pickle存储器
      • 练习:记账程序
    • 七、函数应用
      • 1. 函数定义
      • 2. 函数操作符
      • 2. 参数组
      • 练习:简单的加减法数学游戏
      • 4. lambda 匿名函数
      • 5. filter 函数
      • 6. map 函数
    • 八、函数高级应用
      • 1. 变量作用域
      • 2. 函数式编程
      • 3. 偏函数
      • 4. 递归函数
      • 5. 生成器
      • 生成器练习:每次获取文件10行数据
      • 6. 内部函数
      • 7. 闭包
      • 闭包练习:-->创建通用的计数器
      • 8. 装饰器
    • 九、什么是模块
      • 1. 模块导入方法
      • 2. hashlib 模块
      • 3. tarfile模块
      • 练习:备份程序
    • 十、OOP(面向对象编程)
      • 1. 基本概念
      • 2. 创建类
      • 2. 子类
      • 3. 多重继承
      • 3. 静态方法
      • 4. 类方法
    • 十一、 search 函数
      • 1. findall
      • 2. finditer
      • 3. split
      • 4. sub
      • 5. compile
      • 练习:分析Apache访问日志
    • 十二、 re模块(正则)
      • 1. 匹配单个字符
      • 2. 匹配一组字符
      • 3. 其他元字符
      • 4. 贪婪匹配
    • 十三、socket模块
      • 1. 套接字
      • 2. 面向连接与无连接
      • 3. Python字符串str和bytes类型转换
      • 3. TCP
      • 创建TCP服务器
      • 创建TCP客户端
      • 4. UDP
      • 创建UDP服务器
      • 创建UDP客户端
      • UPD服务器循环
      • UDP客户端循环

运维Python大全

INSTALL PYTHONE3

安装依赖包

yum  -y install gcc gcc-c++  zlib-devel openssl-devel readline-devel libffi-devel sqlite-devel tcl-devel tk-devel  
wget https://www.python.org/ftp/python/3.8.13/Python-3.8.13.tgz
tar zxf Python-3.8.13.tgz
cd Python-3.8.13
./configure --prefix=/usr/local  
make&&make install 

安装 Pycharm
Pycharm 设置中文

  1. baidu.com search Pycharm2017.3 汉化包
  2. 下载resource_cn.jar
  3. 把resource_cn.jar 拷贝到/root/bin/pycharm2017/lib中
  4. 如果经过第三步,仍然是英文界面,可以将lib目录中的resource_en.jar先剪切到别处
  5. 启动Pycharm,将报错
  6. 关闭pycharm后,把resource_en.jar再拷贝进去

Pycharm使用
加注释 : 选择行数 crtl +? 去掉注释:crtl+?
; 允许同一行但不推荐


Python syntax

例如;
分开写
a=3
b=4 推荐 这种写法

一行写(不推荐)
a=3;b=4 # 不推荐,可读性差
Python中 “字符串” 必须有引号,单双引号表示相同的含义,
如果不加引号,Python会把它当成一个名称,如果该名称没有定义将会报错

print('hello world')               #语句各项之间默认用空格分隔
print('hello','world')                
print('hello','world',sep='***')  #语句各项之间也可以自定义分隔符
print('hello'+'world')                #字符串可以使用+进行拼接 
print('hello world',end='AAA')  #print语句默认最后加入一个回车\n,可以用end来自定义结束

username = input('请输入用户名:')
print('欢迎登录',username)
print('欢迎登录'+ username)


标题 合法的变量名,有三个要求

  1. 首字符必须是字母或下划线
  2. 其他字符可以是字母、数字或下划线
  3. 区分大小写

1. 推荐采用的全名方法

-变量名全部采用小写字母
-简短、有意义
-多个单词间用下划线分隔
-变量名用名词,函数名用谓词(动词+名词)
-类名采用驼峰形式

n=n+1 或者n+=1 n*=1 #等价于n=n*1
赋值语句自右向左运算,首先取出n的值,再计算n+1的值得到11,最后11赋值给n

2. 标准算术运算符 + - * / // % **

5/2 值为2.5
5//2 值为2 取整除 - 返回商的整数部分(向下取整)
5%2 值为1 求余,也被称作模运算,结果为1
2**3 值为8 2的3次方,乘方、幂运算

3. 比较运算符

< <= > >= == != <>
10<20<30 支持连续比较
10<20>15 相当于10<20 and 20>15 不推荐10<20>15这样的写

4. 逻辑运算符

and not or
and 两边为true
not 假变正
or 一个为正就为正

今天写到   print()    input()
  https://www.jianshu.com/      搜索“ python百例 "  从下面开始做  1-5 
 print('hello world!')
if 3>0:
 print("ok")
 print("yes")
x = 4
y = 5
print("hello world!")                    
print("hello","world!")             # 逗号自动添加默认的分隔符:空格
print("hello"+"world")                # 加号表示字符拼接
print("hello","world",sep="***")  #单词间用 *** 分隔
print("#" * 50)                          #   *号表示重复50遍
print("how are you?",end="")  #   默认print会打印回车,end=“ ” 表示不要回车

number = input("请输入数字: ")  # input用于获取键盘输入
print(number)
print(type(number))  # input获得的数据是字符型
print(number + 10)  # 报错,不能把字符和数字做运算
print(int(number) + 10)  # int可将字符串10转换成数字10
print(number + str(10))  # str将10转换为字符串后实现字符串拼接

################################################################################################

一 、python 数据类型

1. 数字

(1)int整数(有符号整数,没有小数点)
(2)bool布尔值 :Ture/false Ture=1 , false=0
(3)float浮点数:有小数点
(4)complex复数:共轭复数
对于整数,没有任何前缀Python默认识别为10进制数
以0o开头表示8进制,0b开头表示2进制 , 以0x开头表示16进制

2. 字符串

在引号中一系列字符,单双引号没有区别
三引号:三个连续的单引号或者双引号。它能够保存输入的格式,允许多行输入

3.字符串切片

下标和切片操作
第一个字符索引是0 ,最后一个字符的索引是-1
索引下标运算符[ ] 切片运算符[:] [::2] 表示步长值

py_str="Python"
len(py_str)        #查询长度
print("len(py_str)")  #打印py_str变量的长度
py_str[0]           #下标从0开始"Python"[0] 意义一样
print(py_str[0])   #可以截取字符串第一个字符
py_str[6]            #索引超出范围,报错
py_str[len(py_str) -1]   #字符串总长度减一,得到最后一个字符的下标
py_str[-1]       #也可以得到最后一个下标

py_str[2:4]   #表示下标包含,结束下标不包含
py_str[2:6]   得到 ‘thon’  
py_str[2:600]  #下标超出范围,切片不报错 ‘thon’
py_str[2:]     #结束下标不写,表示取到结尾
py_str[0:2]   得到‘py’  
py_str[:2]    得到 ‘py’  #开始下标不写,表示从开头开始
py_str[2:5]   得到  "tho"  #从2开始到5结束 5-2=3
py_str[::2]   得到   "pto"    #表示步长值是2
py_str[1::2]   得到  "yhn"   #从1开始步长值是2
py_str[::-1]   得到  "nohtyp"  #表示从右向左取步长值为-1 

py_str + " is cool"    #+号表示简单拼接
print(py_str + " is cool" )  得到 Python is cool   
"*" * 50         # *号重复50次
print("*" * 50)  得到 **********************************
print(py_str * 3) 得到 PythonPythonPython



"t"  in py_str       
print("t"  in py_str )   得到 True
"to"  in py_str     
print("to"  in py_str  ) 得到 False 
print("to"  not in py_str  )   得到 True 

4. 列表

可以将列表当成普通的“数组" ,它能保存任意数量,任意类型的Python对象
列表: 它是一个容器,可以存放各种数据

列表

alist = [10 ,20 ,"li" ,"da",[1,2]]
print(len(alist))   得到5
alist[2:4]   
print(alist[2:4])  得到 ["li","da"]
alist[-1] =100     #列表项可以重新赋值
print(alist)   得到[10,20,"li","da","100"]
alist.append(200)    #向列表尾部增加一项
print(alist)   得到 [10,20,"li","da","100","200"]  

5. 元组

相当于是静态的列表,它的项目不可变

atuple =(10,20,"li","da")
atuple[-1]
print(atuple[-1])  得到  da
atuple[0] =100  #报错,元组不能修改

6. 字典

采用key:val 对存储的数据类型,key不能重复

adict={"name":"大锤","age":18}
adict["name"]          # 通过key取出value
print(adict["name"])  得到 大锤
18 in adict   得到 Flase  
"age" in adict  得到True
adict["sex"]="female"   #key不在字典中则增加一项   
print(adict)     得到{"name":"大锤","age":18,"sex":"female"}
adict["age"]=20            # age已是字典的key,修改age的值
print(adict)    得到{"name":"大锤","age":20,"sex":"female"}

—————————————————————————————

按数据类型比较 -----------------------重要、必须背下来
按存储模型分类
-标量类型 : 数值、字符串 标量:只有一种类型,不能存储其他类型。数字、字符串
-容器类型:列表、元组、字典 容器:能包含各种数据。列表、元组、字典

按更新模型分类
-可变类型:列表、字典
-不可变类型:数字、字符串、元组

按访问模型分类
-直接访问:数字
-顺序访问: 字符串、列表、元组
-映射访问:字典


例如:

alist = [10 ,20 ,"li" ,"da",[1,2]]   
blist = alist
blist.append(30)
print(alist) 得到[10 ,20 ,"li" ,"da",[1,2],30]
print(blist)  得到  [10 ,20 ,"li" ,"da",[1,2],30]   变得一样所以写程序容易出现bug

blist=alist.copy()
blist.append(30)
print(alist) 得到[10 ,20 ,"li" ,"da",[1,2]]
print(blist)  得到  [10 ,20 ,"li" ,"da",[1,2],30]  

二、判断语句

1. if 判断

words = "tom\njeff\njay\nmikes"
if "tom" in words :
    print("yes")
if "tom" not in words :
    print("not in")
else:
    print("tom in words")

if -0.0 : 
    print("0k")             #任何值为0的数字都是False,非0为True  //这里不打印

if -0.01 :
    print("-0.01 is ok")    #这里可以打印True
   
if  '  ' :
    print("space is true")   #任何非空对象都是True ,空位False ,打印   
if  '' :
    print("空字符串是False")  #False不打印  
if None:
    print("None也是False,表示空")   #False不打印

判断合法用户

  1. 创建login2.py
  2. 提示用户输入用户名和密码
  3. 获取相关信息后,将其保存存在变量中
  4. 如果用户的用户名为bob,密码为123456,则输出Login successful,否则输出Login inorrect

###############################################################################################

2. while循环

判断合法用户

  1. 创建login2.py文件
  2. 提示用户输入用户名和密码
  3. 获取相关信息后,将其保存在变量中
  4. 如果用户输的用户名为bob,密码为123456,则输出
    Login successful ,否则输出Login inorrect
import getpass   #导入名为getpass 的模块
username = input("username:")
password = getpass.getpass("password:")

if username == "bob" and password == "123456" :
     print("Login successful")
else:
     print("Login inorrect")

import random
number = random.randint(1,100)   #生成1-100间的随机数字,包含1和100
print("number ->",number)
answer = int (input("猜数1-100:"))    #将用户输入的字符数字转成真正的int数字

if answer > number:
    print("猜大了")
elif answer< number:
    print("猜小了")
else:
    print("猜对了")

import random
number = random.randint(1,100)
while True:
    answer = int(input("\033[34;1m猜数1-100:\033[0m"))
    if answer > number :
        print("\033[34;1m猜大了\033[0m")
    elif answer <number:
        print("\033[34;1m猜小了\033[0m")
    else:
        print("\033[31;1m猜对了[\033[0m")
        break

import random
all_choise = ['石头', "箭头", "布"]
win_list = [['石头', '剪刀'], ['布', '石头'], ['剪刀', '布']]

prompt = """1.石头
2.剪刀
3.布
请出拳(0/1/2):"""

computer = random.choice(all_choise)
index = int(input(prompt))
player = all_choise[index]
print("你的出拳:", player, "计算机出拳:", computer)
if player == computer:
    print("\033[32;1m平局\033[0m")
elif [player, computer] in win_list:
    print("\033[35;1m你赢了\033[0m")
else:
    print("\033[31;1m你输了\033[0m")
    

import random
tries = 0   #设置计数器,用户最多猜3次
number = random.randint(1,10)

while tries<3:
    answer = int(input("猜数(1-10):"))
    if answer > number:
        print("猜大了")
    elif answer < number:
        print("猜小了")
    else:
        print("猜对了")
        break
    tries +=1
else:
    print("数字是:",number)

————————————————————————————————————---------------

3. 三元运算符,也叫条件表达式

例如:

      a = 100
      b = 80 
if a<b:
           smaller = a
else:
           smaller =b

以上 写法,可简写为

smaller = a if a<b else b 

score = int(input("请输入你的成绩:"))

if 70>score>=60:
    print("及格")
elif 80>score>=70:
    print("良")
elif 90>score>=80:
    print("好")
elif score>=90:
    print("优秀")
else:
    print("你要努力了")

##################################################################################################

4. for循环

for i in  :
range(10)  生成列表[0,1,2,3,4,5,6,7,8,9,]
range(6,10)  生成[6,7,8,9,]

例如:
range(5)
print(list(range(5))) //用list函数 把range(5) 转换成列表
得到 [0, 1, 2, 3, 4]

for i in range(3):                  #[0,1,2]  外侧循环控制打印哪一行
    for j in range(i+1):            #[0] [0,1] [0,1,2] 内层循环控制行内打印几次
        print("hello",end=" ")     #多个hello打印到同一行
        print(j)
    print()                                 #每一行结尾需要打印回车,否则就成为一行
"%sX%s=%s"  %(1,2,2)    #得到 1X2=2   注释符里面不可以加变量可以加 字符串输出%s占位

打印9*9 乘法表

for i in range(1,10):
    for j in range(1,i+1):
        print("%sx%s=%s" %(j,i,i*j),end="\t")   
    print()


三、实战案例应用

列表解析:快速生成列表

[10]    #得到[10]
[10+5]  #得到[15]
[10+5 for i in range(1,11)]   #得到 [15, 15, 15, 15, 15, 15, 15, 15, 15, 15] 

[10+i  for i in range(1,11)]   #得到 [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

[10+i  for i in range(1,11) if i % 2 == 1]  #得到  [11, 13, 15, 17, 19]

["192.168.1."+str(i) for i in range(1,5)]   #得到  ['192.168.1.1', '192.168.1.2', '192.168.1.3', '192.168.1.4'] 


四、文件对象

1. 文件操作的基本步骤 -> 打开、读写、关闭

open及file file Python2才有,Python3已经不用了,用open
open read readline readlines close

2. 实操:在Linux服务器操作

cp /etc/hosts /tmp/hosts
#打开文件,没有指定打开方式,默认以r 读的方式打开,以r打开,不能写。文件不存在则报错
python3
f = open(“/tmp/hosts”) #默认加r打开了
data = f.read() # read 默认将全部内容读入内存
f.close() #关闭文件
print(data)
data #可以查看到原始数据,也就是\n 没有被转换成换行。

f = open("/tmp/hosts")         
f.read(10)              #读取10个字节
f.read(10)              #继续向后读10个字节
f.readline()            #读一行
f.readlines()           #所有的行读出来放到列表中,每一行是列表的一项
f.close()     

练习

f = open("/bin/ls","rb")   #打开文本文件,必须明确指定是b(bytes) 二进制文件要加b,要不会报错
f.wirte("jsdf")                   #报错  ,以r打开不能写入只能读
f.read(10)                        
f.close()  
f = open("/tmp/zhuji","w")     #以w打开文件,文件不存在则创建,存在则清空  (慎用)
f = open("/tmp/zhuji","wb")    #清空或者创建可以写入图片  
f.write("hello world!\n")            #写入13个字节
f.flush()                                    #立即将数据写入硬盘,否则将会暂存在缓冲区
f.wirtelines(["2nd line.\n","3rd line.\n"])      
f.wirte(100)                 #报错,只能将字符写到文件,不能是其他数据
f.close()

f =open("/tmp/zhuji","a"#a是追加方式打开(为了打开可以写入不清空)
f.wirte("new line.\n")

3. seek 和tell方法不常用,选修

f = open("/tmp/zhuji","r+")    #以读写方式打开 
f.write("abcde")                      #abcde 将会在开头把原文件覆盖
f.tell()                                    #获取文件指针的位置
f.read(8)                                 #从文件指针开始的位置向后读8个字符
f.seek(3,0)                               #将文件指针称动到开头偏移3个字节
f.read(2)                                   #读文件第4、5 个字符  
f.seek(0,2)                                 #移动指针到文件结尾
f.write("my test.\n")      
f.flush()                                               
f.read()                                     #因为已经到文件结尾,所有读到的是空串
f.seek(0,0)                                 #移动指针到文件开头
f.readline()      

#读第一行的内容

###########################################################################################

4. with

文件操作可以使用with语句,with语句结束时,文件自动关闭

whit open("/tmp/zhuji") as f:                     #相当于 f = open("/tmp/zhuji")
 ...      line  = f.readline()   
line                                                #文件第一行
f.readline()     

#出错,因为文件已经关闭
逐行处理文本文件,更常用的方法是for循环

>>> with open("/tmp/zhuji")  as f:
...   for line in f:    
...       print(line,end=" ")           

练习:模拟cp操作

  1. 创建cp.py 文件
  2. 将/bin/ls 拷贝 到/root/目录下
  3. 不要修改原始文件

参考代码:

src_fname = "/bin/ls"
dst_fname = "/tmp/list"

src_fobj = open(src_fname,"rb")
dst_fobj = open(dst_fname,"wb")

while True:
    data = src_fobj.read(4096)
    if not data:                 #读不到数据,意味着已经读完了
        break
    dst_fobj.write(data)     #读到数据,则写入目标文件
src_fobj.close()
dst_fobj.close()

或者

src_fname = "/bin/ls"
dst_fname = "/tmp/list"

with open(src_fname,"rb") as src_fobj:
    with open(dst_fname,"wb") as dst_fobj:
        while True:
            data = src_fobj.read(4096)
            if not data:
                 break
            dst_fobj.write(data)

#################################################################################################

五、函数

函数是用def 语句来创建的,语法如下:

def function_name(arguments):
"function_documentation_string"
function_body_suite   

例如:

def generate_fib():
    fib = [0,1]
    for i in range(8):
        fib.append(fib[-1]+fib[-2])
    return fib
generate_fib()                  #调用函数,即将函数内的代码运行一遍 
alist = generate_fib()  
print(alist)
blist = [i*2 for i in alist]
print(blist)   

def generate_fib(n):
    fib = [0,1]
    for i in range(n-2):
        fib.append(fib[-1]+fib[-2])
    return fib

a = generate_fib(10)
print(a)
b = generate_fib(20)
print(b)
x = int(input("length:"))
c = generate_fib(x) 
print(c)

——————————————————————————————————————

1. 定义参数

  1. 形式参数(形参)
  2. 实际参数(实参)
  3. 默认参数
    –函数定义时,紧跟在函数名后(圆括号内)的参数被称为形式参数,简称形参。
    由于它不是实际存在变量所以又称虚拟变量
    –实际参数
    –在主调函数中调用一个函数时,函数名后面包括弧中的参数(可以是一个表达式)
    “实际参数”,简称实参
    –默认参数,定义函数时的设置默认参数

import sys
                         
print(sys.argv)           #sys.argv是模块中名为argv的列表,用于存储位置参数

写一个cp命令 在Linux运行

import sys
def copy(src_fname,dst_fname):          
    with open(src_fname,"rb") as src_fobj:
        with open(dst_fname,"wb") as dst_fobj:
            while True:
                data = src_fobj.read(4096)
                if not data:
                    break
                dst_fobj.write(data)
copy(sys.argv[1],sys.argv[2])

def pstar(n=30)
     print("*"*n)

pstar()    #调用函数默认为打印30
pstar(50)  #打印50 

—————————————————————————————————————————

2. 模块:

模块就是一个.py的文件,把文件名的.py移除掉就是模块名
比如:一个文件夹有两个文件star.py 和test.py

star.py中:
  hi = "hello world!"
def pstar(n=30):
     print("*"*n)

test.py 中:
import star
print(star.hi)
star.pstar(10)
           在cp.py 中使用import star 就是使用star模块  

练习:生成随机密码

创建randpass.py 脚本,要求如下:

  1. 编写一个能生成8位随机密码的程序
  2. 使用random的choice函数随机取出字符
  3. 改进程序,用户可以自己决定生成多少位的密码

参考代码:

import random
import string
all_chs = string.ascii_letters+string.digits 

def randpass(n=8):
    result =""
    
    for i in range(n):
        ch = random.choice(all_chs)
        result+=ch         
    return result

if __name__ == '__main__':
    a = randpass()
    print(a)
    print(randpass(4))

################################################################################################

3. shell 相关模块

import shutil 

f1 = open("/etc/hosts")
f2 = open("/tmp/zj.txt")
shutil.copyfileobj(f1,f2)               #copy 文件对象  
f1.close
f2.close

shutil.copyfile("/etc/hosts","/tmp/abcd.txt")        #copy文件名

shutil.copy("/etc/hosts","/tmp/aaa.txt")      #目标可能是目录
shutil.copy("/etc/passwd","/tmp/")  

shutil.copy2("/etc/passwd","/tmp/")               #相当于cp -p 拷贝权限 

shutil.copytree("/etc/security","/tmp/anquan")      #  cp -r 

shutil.move("/tmp/zj.txt","/var/tmp/")                    #相当于mv

shutil.rmtree("/tmp/anquan")                                 #相当于rm -rf ,但只能删除目录不能删除单独文件
shutil.rmtree("/var/tmp/zj.txt")                                    # 不能删除单个文件
import os
os.remove("/var/tmp/zj.txt")                                           #这个可以删除单个文件

shutil.chown("/tmp/passwd",user="bob",group="bob")      #相当于chown

使用help可以查看更多
例: help(shutil.rmtree)


4. 变量赋值

Python支持链式多重赋值
x = y = 10
id(x)
9348224 #显示变量在内存的地址
id(y)
9348224
x = 20 #修改x = 20 x变了,y不变
y = 10 #y的值不变,数值是不可变的

a = b = [10,20]
a[0] = 100
a
[100,20]
b
[100,20] #列表是可变的


5. 多元赋值

a,b = 10,20 #相当于 a = 10;b = 20
a,b = b,a #a和b的值互换

——————————————————————————————————————————

6. 合法标识符

  1. 第一个字符必须是字母或下划线_
  2. 剩下的字符可以是字母和数字或下划线
  3. 大小写敏感区分

——————————————————————————————————————————

7. 关键字

['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue',
 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

练习:查看有哪些关键字

import keyword 
print(keyword.kwlist)
keyword.iskeyword("len")   #判断len是否是关键字  或 "len"   in  keyword.kwlist 等等  

——------------------------------------------------------------------------------------------

8. 内键

http://yiyibooks.cn/    -> python352文档 - > 库参考

9. 程序风格

编写程序时,应该建立一种统一且容易阅读的结构,并将它应用到每一个文件中去

#!/usr/bin/env python                      #起始行
"this is a test module"                     #模块文档字符串
import sys                          #导入模块
import os

debug = Ture                    #全局变量声明

class FooClass(object):         #类定义
      "Foo class"
     pass 

def test():                           #函数定义
       "test function"
      foo = FooClass()

if_name_ == '_main_':          #程序主体
       test()  

10. 编写程序的流程、步骤

  1. 发呆、思考:在脑海里像过电影一样,想想程序是怎么进行的(交互的?非交互的?)
    交互的:考虑屏幕上提示什么,用户回答什么
  2. 思考程序有哪些功能。将这些功能创建函数,编写程序框架
import os

def get_fname():
    while True:
        fname = input("filename:")          
        if not os.path.exists(fname):         #判断文件是否存在  
            break
        print("文件已存在,请重试")

    return fname
def get_content():
    content = []
    while True:
        line = input('("end" to quit)>')
        if line == "end":
            break
        content.append(line)

    return content

def wfile(fname,content):
    with open(fname,"w") as fobj:
        fobj.writelines(content)

if __name__ == '__main__':
    fname = get_fname()
    content = get_content()
    content = [line +"\n" for line in content]   #为每行加上回车
    wfile(fname,content)

#############################################################################################

11. 序列类型操作符


seq[ind] 获取下标为ind的元素 a = [“h”,“e”,“l”,“l”,“o”] a[3] = l
seq[ind1:ind2] 获取下标从ind1到ind2间的元素集合 a = [“h”,“e”,“l”,“l”,“o”] a[2:4] = [“l”,“l”]
seq*expr 序列重复expr次 print(“#”*5) 得到 #####
seq1+seq2 连接序列seq1和seq2 拼接(同类型) “abc”+“123” 或者

例:
“abc” +[10,20] 不可以不同类型 修改为 [“abc”] +[10,20]
obj in seq 判断obj元素是否包含在seq中
obj not in seq 判断obj元素是否不包含在seq中

12. 内建函数(工厂函数)


函数 意义
list(iter) 把可迭代对象转换为列表
str(obj) 把obj对象转换成字符串
tuple(iter) 把一个可迭代对象转换成一个元组对象
len(seq) 返回seq的长度
max(iter,key=None) 返回iter中的最大值
enumerate (枚举) 接受一个可迭代对象作为参数,返回一个enumerate对象 返回是元组
reversed(seq) (翻转) 接受一个序列作为参数,返回一个以逆序访问的迭代器
sorted(iter) (排序) 接受一个可迭代对象作为参数,返回一个有序的列表
------------------------------------------
list(10)          #无法装列表。数字无法转
 list("hello")    #列表
#结果得到 ["h","e","l","l","o"]

list(("hello","world"))
["hello","world"]

str(obj)           #字符串
str(10)
"10"

tuple(iter)       #元组
tuple(abc) 
("a","b","c")

a = "hello"
len(a)  得到5 

names = ["bob","alice","tom"]
max(name)    得到tom   按第一个字母排序
min(names)    得到alice 

hi = "hello"
alist = [10,20,30]

for ind in range(len(hi)):
    print(ind,hi[ind])

for item in enumerate(alist):
    print(item)

for ind,val in enumerate(alist):
    print(ind,val)

print(list(reversed(alist)))  #翻转
for i in reversed(alist)
     print(i)

print(sorted(alist))   #排序

13. 字符串操作符

比较操作符:字符串大小按 ASCII码值大小进行比较
切片操作符:[]、[:] 、[::]
成员关系操作:in 、not in

———————————————————————————————————————————

14. 检查标识符

  1. 程序接受用户输入
  2. 判断用户输入的标识符是否合法
  3. 用户输入的标识符不能使用关键字
  4. 有不合法字符,需要指明第几个字符不合法
import keyword
import string

first_chs = string.ascii_letters+"_"
other_chs = first_chs+string.digits
def check_id(idt):
    if keyword.iskeyword(idt):
        return "%s是关键字" %idt

    if idt[0] not in first_chs:
        return "首字符不合法"

    for ind,ch in enumerate(idt[1:]):
        if ch not in other_chs:
            return "第%s个字符不合法" %(ind+2)
    return "%s是合法的标识符" %idt

if __name__ == '__main__':
    idt = input("请输入字符串:")
    print(check_id(idt))

15. 字符串格式化

%c 
%s         #优先用str()函数进行字符串转换
%d /%i     #转成有符号十进制数
%#o        #转成无符号八进制数
%#x        #转成无符号十六进制数
%e /%E     #转成科学计数法
%f /%F      #转成浮点数
%10s%10s    #填充格式
%-10s%-10s   #左对齐
"" %()
print("%s" % a)

"%s: %s" % ("bob",22)      #%s  / %d   常用
"%s: %d" % ("bob",22)
"97 is %c" % 97              #  %c转换数字成为对应的ASCII码,
"97 is %#o" % 97             #不常用
"97 is %#x" % 97               #不常用
"10000 is %e "  %10000         #不常用
"10/3 is %f"  %(10/3)                #不常用

"%10s%10s" % ("name","age")    #常用,定义字段宽度为10个字节
"%-10s%-10s"  % ("name","age")   #常用,左对齐

16. format函数

(功能和上面%字符串格式化一样)

使用位置参数

-  "my name is{},age{}" .format("hoho",18)

使用关键字参数

- "my name is {name},age is {age}".format({"name":"bob","age":23})

填充与格式化

-{:[填充字符][对齐方式<^>][宽度]}
使用索引

- "name is {0[0]} age is {0[1]}" .format(["bob",23])

"{}: {}" .format("bob",22)
"bob: 22"

"{1}: {0}" .format("bob",22)
"bob: 22"

"{0[1]}: {0[0]}" .format([22,"bob"])

练习:创建用户(Linux系统运行)

  1. 编写一个程序,实现创建用户的功能
  2. 提示用户输入
  3. 随机生成8位密码
  4. 创建用户并设置密码
  5. 将用户相关信息写入指定文件

参考代码

import sys
import subprocess    
#import randpass
import random
import string
all_chs = string.ascii_letters+string.digits
def adduser(username,password,fname):
    info = """用户信息:
用户名:%s
密码:%s
""" %(username,password)
    subprocess.call("useradd %s" % username,shell=True)
    subprocess.call(
        "echo %s |passwd --stdin %s" %(password,username),shell=True
    )
    with open(fname,"a") as fobj:
        fobj.write(info)

def randpass(n=8):  #创建随机8位密码
    result=""

    for i in range(n):
        ch=random.choice(all_chs)
        result+=ch
    return result


if __name__ == '__main__':
    password = randpass()
    fname = "/tmp/mima.txt"
    adduser(sys.argv[1],password,fname)
    

17. 原始字符串操作符

.原始字符串操作符是为了对付那些在字符串中出现的特殊字符
.在原始字符串里,所有的字符都是直接按照字面的意思来使用,没有转义特殊或不能打印的字符

例:

 winPath = "c:\windows\new\temp" 
    print(winPath)                # \t 成为tab   \n成为回车
c:\windows
ew	emp
newPath = r"c:\windows\temp"     #  r表示真实字符串`原始字符串 
   print(newPath)                       
c:\windows\temp 

   newPath      #看到Python是如何存储的 其实 r 是加多\ 
c:\\windows\\temp    

——————————————————————————————————————

18. 字符串内建函数 (字符串操作)

string.capitalize():   # 把字符串的第一个字符大写  
string.center(width)  #返回一个原子符串居中,并使用空格填充至长度width 的新字符串
string.count(str,beg=0,end=len(string))  #返回str在string里面出现的次数,如果beg或者end指定则返回指定范围内str出现的次数
string.upper()                 #字符串变大写
string.strip()                   #删除两端空白字符,
string.lstrip()                   #删除左边空白字符                            
string.rstrip()                   #删除右边空白字符    
string.lower()                    #字符串变小写
string.startswith("he")           #是以he开头吗
string.endswith("abc")           #是以abc结尾吗
string.replace("l","m")           #  l 替换为m
string.ljust(50,"*")              #  宽度为50,左边对齐,空格补充为*
string.rjust(50,"*")                #宽度为50,右边对齐,空格补充为*
string.isdigit()                      #判断字符串是不是全部数字
string.islower()                       #判断是否全部小写
string.isupper()
string.isidentifier()               #判断是否符合合法标识符

19. 字符串方法

"     hello world    ".strip()       #删除两端空白字符

hi = "hello world"
hi.upper()                      #字符串变大写
hi.lower()                       #字符串变小写                           
hi.startswith("h")           #以h开头吗?
hi.startswith("he")      
hi.endswith("abc")         #以abc结尾吗?
hi.replace("l","m")         #替换
hi.center(50)                #居中
hi.center(50,"*")
hi.ljust(50,"*")
hi.rjust(50,"*")
"1234".isdigit()                 #判断是否是数字
True
"hao123".isdigit()
False
"hao123".islower()      #是否小写

————————————————————————————————————————————

20. 创建及访问列表(列表list操作)

·列表是有序、可变的数据类型
·列表中可以包含不同类型的对象
·列表可以由 [ ] 或工厂函数创建
·支持下标及切片操作

20. 列表内建函数

列表方法 操作
list.append(obj) 向列表中添加一个对象
list.count(obj) 返回一个对象obj在列表中出现的次数
list.extend(seq) 把序号seq的内容添加到列表中
list.index(obj) 返回obj对象的下标
list.insert(index,obj) 在索引量为index的位置插入对象obj
list.reverse() 原地翻转列表
alist = [10,20,30,"bob","alice"]
alist.remove("bob")          #删除第一个bob
alist.append("25")            #添加一个对象
alist.sort()                  #排序升序
alist.reverse()                #翻转
alist.pop()                     #默认删除最后一项   
alist.pop(1)                    #弹出
alist.insert(1,50)              #在下标为1的位置插入50
alist.extend([200,10,39])       #扩展列表
alist.extend("abc")              #会把abc 分开加到列表
alist.append("abc")              #注意和extend的区别
alist.index(50)                  #获取50的下标,没有50这个元素则报错

————————————————————————————————————————

atuple = (10,20,30,[1,2,3])
atuple.count(20)                  #统计有多少个20 
atuple.index(20)                   #第一个20的下标
atuple[-1].append(4)            #理解即可,很少有应用

21. 单元素元组必须有逗号,否则不表示元组

a= (10)
 len(a)               #报错
 type(a)        #整数

a =(10,)   #元组必须有逗号  
len (a)
1        
type(a)                         

练习: 用列表构建栈结构

  1. 栈是一个后进先出的结构
  2. 编写一个程序,用列表实现栈结构
  3. 需要支持压线、出栈、查询功能

参考代码

stack = []                    #全局变量从定义开始一直到程序结束,任何地方都可见、可用
def push_it():
    item = input("数据").strip()
    if item:
        stack.append(item)

def pop_it():
    if stack:
        print("从栈中弹出了%s" % stack.pop())
    else:
        print("\033[32;1m空栈\033[0m")

def view_it():
    print("\033[31;1m%s\033[0m" % stack)

def show_menu():
    cmds = {"0": push_it,"1":pop_it,"2":view_it}
    prompt = """(0)压栈
(1)出栈
(2)查询
(3)退出
请选择(0/1/2/3)"""
    while True:
        choice = input(prompt).strip()[0]
        if choice not in "0123":
            print("无效输入,请重试")
            continue
        if choice == "3":
            print("Bye-bye")
            break
        cmds[choice]()

if __name__ == '__main__':
    show_menu()

##############################################################################################

22. 字典和集合/文件系统

  1. 写入字典
adict = {"name":"bob","age"20}
dict = (["ab","cd",("name","niu")])
{}.fromkeys(["niu","wang","li"],"male")
  1. 查询字典
    判断代码
20 in adict 
False
"age" in adict
True

查询代码

for key in adict:
    print("%s:%s" % (key,adict[key)]))
print("%(name)s is %(age)s years old" %adict)

练习:通过key更新字典

通过key更新字典,如果key不在字典中则增加新增,在字典中则修改**

adict["email"] = "[email protected]"
print(adict)
{'name': 'bob', 'age': 20, 'email': '[email protected]'} 

adict["age"] = 22
print(adict)
{'name': 'bob', 'age': 22, 'email': '[email protected]'}

adict.keys()     #查询key的值或 直接adict 

for key in adict.keys():
      print(key)

或者

for key in adit:
      print(key)
list(adict.values())

for key,val in adict.items():
      print("%s: %s" % (key ,val) )

23. 字典内建方法

dict.copy()
dict.get(key,default = none)
dict.items()
adict[phone]                    #没有会报错
adict.get("phone")                #没有指定则none 获取key为phone的值  ,重点
adict.get("phone","110")            #获取key为phone的值,没有返回110
adict.popitem()                     #随机弹出一项
adict.pop("email")                   #弹出key是email的项
adict.update({"aaa":100,"bbb":200})
print(adict.get("phone") )            #获取获取key为phone的值 

24. Windows文本换行和Unix转换

要把Unix 文档换行转为windows文本换行,>>>> 使用命令Unix2dos  文件名  
要把windows 文档换行转为Unix文本换行,>>>> 使用命令dos2Unix  文件名  

————————————————————————————————————————

练习:编写类进度条程序

  1. 在屏幕上打印20个#号
  2. 符号@从20个#号穿过
  3. 当@符号到达尾部,再从头开始
import time
import sys
n = 0
print("#"*19,end="")
b = "\033[32;1m@\033[0m"
while True:
    print("\r%s%s%s" % ("#"*n,b,"#"*(19-n)),end="")     # \r 回车不换行 
    sys.stdout.flush()                    # 立即在屏幕上输出,不要放到缓冲区
    n+= 1
    time.sleep(0.3)
    if n == 20:
        n = 0

——————————————————————————————————————————

25. 集合

集合 :由不同元素组成的set,元素只能是不可变对象。相当于是无值的字典

集合类型操作符
集合支持用in 和not in 操作符检查成员
能够通过len() 检查集合大小
能够使用for 迭代集合成员
不能去切片,没有键

len(aset)
4
for ch in aset:
    print(ch)
    
打印结果:
l
e
o
h

26. 集合类型操作符

** | 联合,取并集
& 交集

  • 差补**

bset = set("how")
aset = set("hello")
aset
{"h","o","l","o"}
bset
{"h","w","o"}
aset | bset     #并集
{"w","e","h","

aset+bset      # 报错

aset & bset     #交集
{"h","0"}

aset - bset     #差补,aset中有,bset中没有的元素 

27. 集合内建方法

set.add() 添加成员
set.update() 批量添加成员
set.remove() 移除成员

实操

aset = set("hello")
aset.add("new")
aset
{"h","o","l","e","new"}

aset.update("new")
aset
{"h","o","l","e","new","n"}

aset.update(["hello","world"])
aset
{"h","o","l","e","new","n","hello","wolrd"}

aset.remove("n")
aset
{"h","o","l","e","new","hello","wolrd"}

cset = set("ho")
cset.issubset(aset)               #cset 是aset的子集吗
aset.issuperset(cset)            # aset 是cset的超集吗
aset.intersection(bset)          #aset & bset    交集
aset.union(bset)                  #aset | bset      并集
aset.difference(bset)             #aset - bset    补差

cp /etc/passwd /tmp/
cp /etc/passwd /tmp/mima

修改mima,使之与passwd不完全一样

with open("/tmp/mima")  as f:
    aset = set(f)
with open("/tmp/passwd") as f:
    bset = set(f)
with open("/tmp/result.txt","w") as f:
    f.wirtelines(aset - bset)

六、简单模块

1. time 模块

导入方式:
import time

常用方法
time.time() # 返回时间戳 ,自1970-1-1 0:00:00 到执行命令期间的秒数 (常用)
time.ctime() #当前日期、时间 (常用)
time.localtime() #返回九元组格式时间
time.sleep(3) #睡眠3秒 (常用)
time.strftime(“%Y-%m-%d %H:%M:%S”)

2. datetime模块

导入方式:
import datetime

实操:

from datetime import datetime ,timedelta 
t1 = datetime.now()      #把当前时间转换成时间对象
t1.year  
t1.month
t1.day
t1.hour
t1.minute
t1.second
t1.microsecond
t2 = datetime(2018,10,10)
  #转换字符串为datetime对象
t1 = datetime.strptime("Dec 12 2018","%b %d %Y")
t = datetime(2018,12,10)
t1>t

t = datetime.now()
days = timedelta(days = 100)
t1 = t -days
t2 = t +days

3. 异常

当程序运行时,因为遇到未解的错误而导致中止运行,便会出现traceback消息,打印异常

异常 描述
NameError 未声明/初始化对象
IndexError 序列中没有没有此索引
SyntaxError 语法错误
KeyboardInterrupt 用户中断执行
EOFError 没有内建输入,到达EOF标记
IOError 输入/输出操作失败

参考代码

try:
    num=int(input("number:"))          #把有可能发生异常的语句放到try中
    result=100/num
    print(result)
except (ValueError,ZeroDivisionError):       #捕获异常
    print("无效输入,必须输入非0数字")
except (KeyboardInterrupt,EOFError):
    print("\nBye-bye")

else:
    print(result)             #异常不发生才执行的语句,放到else中
finally:
    print("DONE")         #不管是否发生异常都要执行的语句,放到finally中

异常处理 try - except 和try - finally

这两种组合用的比较多


def set_age(name,age):
    if not 0<age<150:
        raise ValueError("年龄超过范围了(1-150)")
    print("%s现在是%s岁了" %(name,age))

def set_age2(name,age):
    assert 0<age<150,"年龄超过范围了(1-150)"
    print("%s现在是%s岁了" %(name,age))

if __name__ == '__main__':
    set_age("大牛",22)
    set_age2("神通",255)

#############################################################################################

4. OS模块

对文件系统的访问大多通过Python 的os模块实现
该模块是Python访问 —> 操作系统功能的主要接口
有些方法
如copy等,并没有提供,可以使用shutil模块作为补充


函数 作用
os.symlink() 创建符号链接(软连接)
os.listdir() 列出指定目录的文件
os.getcwd() 返回当前工作目录
os.mkdir() 创建目录
os.chmod() 改变权限模式
os.getatime() 返回最近访问时间
os.chdir() 改变工作目录
os.remove 删除文件(只能删除文件和空目录)
os.rmdir 删除空目录
os.rmtree
os.rename 重命名

参考代码

 **import os**                             
                                                 **相当于Linux命令**
os.getcwd()                            #pwd
os.mkdir("/tmp/demo")          #mkdir  /tmp/demo
os.chdir("/tmp/demo")            #cd   /tmp/demo
os.listdir()                                 # ls
os.listdir("/home")                      #ls /home
os.mknod("mytest.txt")                 # touch  mytest.txt
os.symlink("/etc/hosts","zhuji")      #ln -s /etc/hosts   zhuji
os.unlink("zhuji")                            #删除软连接
os.chmod("mytest.txt")                    #touch   mytest.txt
os.rename("mytest.txt","test.doc")      #mv  mytest.txt   test.doc 
os.remove("zhuji")                                # rm -f    zhuji
os.rmdir("/tmp/devops")                        #删除空目录 
os.path.basename("/etc/sysconfig/network")       #从/etc/sysconfig 切割network  
os.path.dirname("/etc/sysconfig/network")            #目录名称
os.path.join("/etc/sysconfig","network")
os.path.isfile("/etc/hosts")                         #是一个文件吗
os.path.isdir("/etc/hosts")                      #是一个目录吗
os.path.exists("/etc/hosts")                      #是否存在
os.path.islink("/etc/hosts")                         #是链接吗

5. pickle存储器

普通的文件只能把字符类型数据写入到文件中,pickle可以把任意类型的数据存储到文件中,
将来还能无损地取出。

f = open("/tmp/mydata","w")
f.write("hello world!\n")
f.write(100)                #不允许写入数字
f.write({"name:"bob"})      #不允许写入字典
f.close()  

import pickle as p           #导入模块时,为其取别名p
f = open("/tmp/data","wb")
adict = {"name":"bob","age":23}
p.dump(adict,f)              #将字典存入文件
f.close()

import pickle as p
f = open("/tmp/data","rb")
mydict = p.load(f)        #加载赋值   
f.close()

################################################################################################

练习:记账程序

  1. 假设在记账时,有一万元钱
  2. 无论是开销还是收入都要进行记账
  3. 记账内容包括时间、金额和说明等
  4. 记账数据要求永久存储

参考代码

  import os
import pickle
import time

def cost(record):
    amount = int(input('金额:'))
    comment = input('备注:')
    date = time.strftime('%Y-%m-%d')
    with open(record, 'rb') as fobj:
        data = pickle.load(fobj)
    balance = data[-1][-2] - amount
    data.append([date, 0, amount, balance, comment])
    with open(record, 'wb') as fobj:
        pickle.dump(data, fobj)

def save(record):
    amount = int(input('金额:'))
    comment = input('备注:')
    date = time.strftime('%Y-%m-%d')
    with open(record, 'rb') as fobj:
        data = pickle.load(fobj)
    balance = data[-1][-2] + amount
    data.append([date, amount, 0, balance, comment])
    with open(record, 'wb') as fobj:
        pickle.dump(data, fobj)

def query(record):
    print('%-12s%-10s%-10s%-10s%-20s' % ('date', 'save', 'cost', 'balance', 'comment'))
    with open(record, 'rb') as fobj:
        data = pickle.load(fobj)
    for item in data:
        print('%-12s%-10s%-10s%-10s%-20s' % tuple(item))

def show_menu():
    record = r'D:\a\record.data'
    if not os.path.exists(record):
        init_data = [
            [time.strftime('%Y-%m-%d'), 0, 0, 10000, '开始记账'],
        ]
        with open(record, 'wb') as fobj:
            pickle.dump(init_data, fobj)

    cmds = {'0': cost, '1': save, '2': query}
    prompt = """(0) 记录开销
(1) 记录收入
(2) 查询收支
(3) 退出
请选择(0/1/2/3): """
    while True:
        try:
            choice = input(prompt).strip()[0]
        except IndexError:
            continue
        except (KeyboardInterrupt, EOFError):
            choice = '3'

        if choice not in '0/1/2/3':
            print('无效输入,请重试')
            continue
        if choice == '3':
            print('\nBye-bye')
            break
        cmds[choice](record)

if __name__ == '__main__':
    show_menu()

七、函数应用

1. 函数定义

def foo():
       print("in foo")
       boo()    #可以先使用再定义

 def boo():
       print("in boo")

foo()
foo     #function foo at 0x7f18ce311b18

def get_age(name,age):
    print("%s is %s years old." % (name,age))

2. 函数操作符

使用一对圆括号() 调用函数,如果没有圆括号,只是对函数的引用
任何输入的参数都必须放置在括号中

操作
get_age() #error 没有加参数
get_age(“bob”,25,26) #error
get_age(“bob”,25) #正确
get_age(25,“bob”) #语法没有错误,语义不对
get_age(age = 25,name = “bob”) #正确
get_age(age = 25, “bob”) #语法错误,key = val 形式必须在后
get_age(25,name = “bob”) #错误,name得到多个值
get_age(“bob”,age = 25) #正确


2. 参数组

Python允许程序员执行一个没有显式定义参数的函数
相应的方法是通过一个把元组(非关键字参数)或字典(关键字参数)作为参数数组传递给函数

def myfunc(*args):       #    *标识args 是个元组
    print(args)

def myfunc2(**kwargs):    #  **标识kwargs 是字典
    print(kwargs)

if __name__ == '__main__':
    myfunc()                      #得到  () 
    myfunc(10)                    #得到 (10,)
    myfunc(10,20,30)              # 得到 (10, 20, 30)
    myfunc(10,20,30,"bob","tom")  #得到 (10, 20, 30, 'bob', 'tom')
    myfunc2(name="bob")          #得到 {'name': 'bob'}
    myfunc2(name="bob",age="23")   #得到  {'name': 'bob', 'age': '23'} 

def add(x,y):
    print(x+y)


if __name__ == '__main__':
    alist = [10,20]
    add(*alist)      #调用函数时,参数加上 * 表示将序列对象拆开
    add(*"ab")        #将字符串拆开  

练习:简单的加减法数学游戏

  1. 随机生成两个100以内的数字
  2. 随机选择加法或是减法
  3. 总是使用大的数字减去小的数字
  4. 如果用户错三次,程序给出正确的答案

import random

def add(x,y):
    return x +y

def sub(x,y):
    return x - y

def exam():
    cmds = {"+":add,"-":sub}
#cmds = {"+":lambda x,y:x+y,"-":lambda x,y:x-y}        #使用这个lambda可以忽略两个函数add和sub
    nums = [random.randint(1,100) for i in range(2)]
    nums.sort(reverse=True)    #降序排列
    op = random.choice("+-")
    prompt = "%s%s%s=" % (nums[0],op,nums[1])

    # if op == "+":
    #     result = nums[0] + nums[1]
    # else:
    #     result = nums[0] - nums[1]

    result = cmds[op](*nums)
    tries = 0
    while tries <3:
        try:
            answer=int(input(prompt))
        except (ValueError,UnboundLocalError):
            print("请输入数字")
            continue
        if answer == result:
            print("very good")
            break
        else:
            print("答错了")
            tries +=1
    else:
        print("%s%s" %(prompt,result))

if __name__ == '__main__':
    while True:
        exam()
        try:
            yn=input("continue(y/n|Y/N)").strip()[0]
        except IndexError:
            continue
        except (KeyboardInterrupt,EOFError):
            yn="n"
        if yn in "Nn":
            print("Bye-bye")
            brea

4. lambda 匿名函数

Python额允许用lambda 关键字创造匿名函数
匿名是因为不需要以标准的def 方式来声明
一个完整的lambda “语句” 代表了一个表达式,这个
表达式的定义体 必须和声明放在同一行

格式 lambda [arg1,[arg2,…argN]] : expression

a =lambda x,y :x+y 
print(a(3,4))
7

常规

def  add (x,y)
                  return x +y
add(10,20)
30

lambda函数

myadd = lambda x,y :x+y 
myadd(10,20)
30 

——————————————————————————————————————

5. filter 函数

filter(func,seq) :调用一个布尔函数 func来迭代遍历每个序列中的元素;
返回一个使func返回值为true的元素的序列
.如果布尔函数比较简单,直接使用lambda匿名函数就显得非常方便了

data = filter(lambda x :x %2,[num for num in range(10)])
print(data)                     #过滤出10以内的奇数
[1,3,5,7,9]

from random import randint

def func1(n):
    return n %2

if __name__ == '__main__':
    numbs = [randint(1,100) for i in range(10)]
    print(numbs)
    print(list(filter(func1,numbs)))
    print(list(filter(lambda n:n%2,numbs)))   #效果一样  可以省略def func1(n)

打印结果:
[29, 82, 30, 10, 60, 15, 100, 93, 88, 66]
[29, 15, 93]


6. map 函数

from random import randint

def func1(n):
    return n %2

if __name__ == '__main__':
    numbs = [randint(1,100) for i in range(10)]
    print(numbs)
    print(list(filter(func1,numbs)))
    print(list(filter(lambda n:n%2,numbs)))  
    print(list(map(func2,numbs)))         #加工一下
    print(list(map(lambda n:n+1,numbs)))  #组合lambda 使用


##################################################################################################

八、函数高级应用

1. 变量作用域

全局变量 # 从定义开始到程序结束
局部变量 #函数内的变量是局部变量,局部变量当函数调用结束后就消失
global语句 # 局部改变全局的值,
名字空间 # 名字空间,标识符搜索顺序依次是 局部 、全局、和内建

如果两个函数中有同名变量,两个同名变量没有关系
局部变量不会改变全局变量的值
函数作用域 —> 局部 、全局、内建 依次搜索

x = 10 
def test2(): 
    global   x      #声明这里的  x 是全局变量 x
    x = "zhangsan"
    print(x)
test2()

打印结果:
zhangsan #改变了原本全局变了 x =10

————————————————————————————————————————————

2. 函数式编程

四种形式

  1. 偏函数
  2. 递归函数
  3. 生成器
  4. 普通函数
def add(a,b,c,d):
    return a+b+c+d
add(10,20,30,40)              
add(10,20,30,123)                                    #每次10,20,30 都没有改变可以改以下偏函数

3. 偏函数

相当于是改造现有函数,将其一部分参数固定下来

from functools import partial 
    myadd = partial(add,10,20,30)

myadd(5)                                                    #得到是10+20+30+5 的值


from operator import add
from functools import partial
add10 = partial(add,10)
print(add10(25))                                       #得到10+25
35

import tkinter
from functools import partial

root = tkinter.Tk()    #相当于创建一个窗体
lb =tkinter.Label(root,text="hello world",font="arial 20")
b1 = tkinter.Button(root,bg="blue",fg="white",text="Button 1")
mybutton = partial(tkinter.Button,root,bg="blue",fg="white")       #使用偏函数
b2 = mybutton(text="Button 2")
b3 = mybutton(text="Button 3")
b4 = mybutton(text="Quit",command=root.quit)
for item in [lb,b1,b2,b3,b4]:
    item.pack()

root.mainloop()

————————————————————————————————————

4. 递归函数

如果函数包含了对其自身的调用,该函数就是递归的在操作系统中,
查看某一目录内所有文件、修改权限等都是递归的应用

def func1(n):
    if n == 1:
        return 1
    return n *func1(n-1)
                                                        # 5* func(4)
                                                         #5*4*func(3)
if __name__ == '__main__':
    print(func1(5))   

from random import randint

def quick_sort(seq):
    if len(seq)<2:
        return seq
    middle = seq[0]
    smaller = []
    larger = []
    for item in seq[1:]:
        if item<middle:
            smaller.append(item)
        else:
            larger.append(item)
    return quick_sort(smaller) +[middle]+quick_sort(larger)
if __name__ == '__main__':
    nums = [randint(1,100) for i in range(10)]
    print(nums)
    print(quick_sort(nums))

5. 生成器

从句法上讲,生成器是一个带yield语句的函数
一个函数或者子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果
yield语句返回一个值给调用者并暂停执行
当生成器的 next() 方法被调用的时候,它会准确地从离开地方继续

生成器
本质上是函数,但是它能生成多个中间值,而函数只有一个最终值
生成器节省内存,更加有效率

ips = ["192.168.1.%s" %i for i in range(1,255)]    #方括号是生成列表
print(ips)
hosts = ("192.168.1.%s" %i for i in range(1,255))  #圆括号变成生成器
print(hosts)     #得到  at 0x000001A07F3CBCC8>
for host in hosts:
    print(host)
    

生成器通过yield生成多个中间结果

def mygen():
    yield 100
    print("-------------------")
    yield 200
    print("####################")
    yield 300
a = mygen()
a.__next__()            #得到100
a.__next__()               #得到200
x = a.__next__()           #赋值给x
x                                #得到300
a.__next__()                   #没有数据将会抛出StopIteration 异常,生成器对象是一次性的
         
for item in b:           #for 可以遍历生成器,遇到StopIteration 自动停止
    print(item)

生成器练习:每次获取文件10行数据

参考代码:

def file_block(fobj):
    content = [ ]
    for line in fobj:
        content.append(line)
        if len(content) == 10:        # 10行生成一次  
            yield content
            content.clear()               #生成数据交给使用者用清空,以便存 下10行               

    if content:                      #如果循环结束后还有数据,生成最后不到10行的内容                        
        yield content
        
if __name__ == '__main__':
    fname = "/etc/passwd"
    fobj = open(fname)
    for block in file_block(fobj):
        print(block)
    fobj.close()

6. 内部函数

  1. 闭包
  2. 闭包实例
  3. 装饰器

——————————————————————————————————————————

7. 闭包

闭包将内部函数自己的代码和作用域以及外部函数的作用结合起来
闭包的词法变量不属于全局名字空间域或者局部的–而属于其他的名字空间,带着"流浪"的作用域
闭包对于安装计算,隐匿状态,以及在函数对象和作用域中随意地切换时很有用的
闭包也是函数,但是他们能携带一些额外的作用域


闭包练习:–>创建通用的计数器

import tkinter
from functools import partial

def pstar():
    print("*"*30)

#def hello():
#lb.config(text="Hello China")
#def welcome():               #使用了say_hi 代替
#lb.config(text="hello TEDU")

def say_hi(word):
    def greet():
        lb.config(text="Hello %s" % word)
    return greet

root=tkinter.Tk()         #相当于创建一个窗体
lb = tkinter.Label(root,text="Hello World!",font="Arial 20")
MyButton = partial(tkinter.Button,root,bg="blue",fg="white")
b1 = MyButton(text="Button 1",command=pstar)
b2=MyButton(text="Button 2",command=say_hi("China"))    #使用闭包函数
b3=MyButton(text="Button 3",command=say_hi("Tedu"))
b4=MyButton(text="Quit",command=root.quit)
for item in [lb,b1,b2,b3,b4]:
    item .pack()

root.mainloop()

————————————————————————————————————————

8. 装饰器

装饰器是在函数调用之上的修饰
这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用
使用装饰器的情形有:
-引入日志
-增加计时逻辑来检测性能
-给函数加入事务的能力


def set_color(func):
    def set_red():
        return "\033[31;1m%s\033[0m" % func()
    return set_red()

def hello():
    return "Hello World"

@set_color                 #装饰器使用
def welcome():
    return "Hello China"

@set_color
def mytest():
    a = 10+10
    return a

if __name__ == '__main__':
    # print(hello())
    # print(welcome())
    hello = set_color(hello)
    print(hello())
    print(welcome())
    print(mytest())


######################################################################################

九、什么是模块

模块支持从逻辑上组织Python代码
当代码量变得相当大的时候,最好把代码分成一些有组织的代码段
代码片相互间有一定的联系,可能是一个包含数据成员和方法的类,
也可能是一组相关但彼此独立的操作函数
·这些代码段是共享的,所以Python允许“调入”一个模块,
允许使用其他模块的属性来利用之前的工作成果,实现代码重用


模块文件
·说模块是按照逻辑来组织Python代码的方法,文件是物理层上组织模块的方法
一个文件被看作是一个独立模块,一个模块也可以被看作是一个文件
模块的文件名就是模块的名字加上扩展名.py


名称空间
·名称空间就是一个从名称到对象的关系映射集合
·给定一个模块名之后,只可能有一个模块被导入到Python解释器中,
所以在不同模块间不会出现名称交叉现象
·每个模块都定义了它自己的唯一的名称空间


1. 模块导入方法

四种方式

  1. 使用import导入模块
  2. 可以在一行导入多个模块,但是可读性会下降
import time,os,sys     #不推荐推荐,每行导入一个模块
  1. 可以只导入模块的某些属性
from random import choice ,randint  #只导入单个模块,常用
  1. 导入模块时,可以为模块取别名
import pickle as p     #取别名  ,不太常用

pycharm 可以点code -> optimize import可以优化导入模块(没有用到的模块将会被
移除,导入的模块按字母顺序排序)

导入模块时,Python会到这些位置搜索:

  1. sys.path 定义的路径
  2. 环境变量PYTHONPATH定义的路径
    #export PYTHONPATH = /var/… (路径)

当导入模块时,模块的顶层代码会被执行
一个模块不管被导入(import) 多少次,只会被加载(load)一次

导入包
包是一个有层次的文件目录结构,为平坦的名称空间加入有层次的组织结构
允许程序员把有联系的模块组合到一起
python2.7 中 包目录下必须有一个_init_.py文件
在Python中,目录可以当成特殊的模块,叫作包,导入mods 目录中的hello.py文件可以为

例如

mkdir mods  
vim  mods/hello.py
hi = "hello world"

import mods.hello
mods.hello.hi
from mods.hello import hi 
from mods import hello 
hello.hi 

2. hashlib 模块

hashlib 用来代替md5和sha模块,并使他们的API一致,专门提供hash算法
包括 md5 、sha1、 sha224、 sha256、 sha384 、sha512,使用非常简单方便

加密
- 对称加密 :加解密使用相同的算法和秘钥 DES/3DES/AES
- 非对称加密: 加解密使用不同的秘钥 RSA/DSA
- 单向加密: 加密只能向一个方向进行,不能通过结果反推回原始数据,MD3/SHA

单向加密用途

  1. 存储加密密码
  2. 校验文件的完整 http://www.cmd5.com/ 可以查询

hashlib:可用于计算MD5值


import hashlib
m = hashlib.md5(b"123456")   #接受二进制形式
print(m.hexdigest())
e10adc3949ba59abbe56e057f20f883e

文件生成MD5

with open("/etc/passwd","rb") as fobj:
    data = fobj.read()

m = hashlib.md5(data)
print(m.hexdigest())  

————————————————————-----
MD5检测

import sys
import hashlib
def check_md5(fname):
    m = hashlib.md5()
    with open(fname,"rb") as fobj:
        while True:
            data = fobj.read(4096)
            if not data:
                break
            m.update(data)
    return m.hexdigest()

if __name__ == '__main__':
    print(check_md5(sys.argv[1])

###############################################################################################

3. tarfile模块

tarfile 模块允许创建、访问tar文件
同时支持 gzip 、bzip2格式

tarfile: 实现压缩、解压缩、可以调用gzip 、bzip2等


import tarfile
import os
tar = tarfile.open("/tmp/security.tar.gz","w:gz")
os.chdir("/etc")
tar.add("security")
tar.close()

os.mkdir("/tmp/demo")
tar = tarfile.open("/tmp/security.tar.gz","r:gz")
tar.extractall(path="/tmp/demo")
tar.close()

练习:备份程序

  1. 需要支持完全和增量备份
  2. 周一执行完全备份
  3. 其他时间执行增量备份
  4. 备份文件需要打包为tar文件并使用gzip格式压缩

构思——备份:

  1. 完全备份
    1)压缩整个目录
    2)计算每个文件的MD5值
  2. 增量备份
    1)取出前一天文件的md5值
    2)计算当前每个文件的md5值
    3) 新增文件和有变化文件需要备份
    4)更新MD5值

参考代码

from time import strftime
import os
import tarfile
import pickle
import hashlib

def check_md5(fname):
    m = hashlib.md5()
    with open(fname,"rb") as fobj:
        while True:
            data = fobj.read(4096)
            if not data:
                break
            m.update(data)
    return m.hexdigest()

#full_backup 完整备份
def full_backup(folder,dest,md5file):
    md5_dict = {}      #用于保存每个文件的MD5值{“文件绝对路径” :md5值}
    fname = os.path.basename(folder.rstrip("/"))
    fname = "%s_full_%s.tar.gz" % (fname,strftime("%Y%m%d"))
    fname = os.path.join(dest,fname)  #目标文件的绝对路径

    tar = tarfile.open(fname,"w:gz")   #压缩
    tar.add(folder)
    tar.close()

    for path,folders,files in os.walk(folder):
        for file in files:
            key = os.path.join(path,file)      #拼出绝对路径
            md5_dict[file] = check_md5(file)    #写入MD5字典

    with open(md5file,"wb") as fobj:          #字典写入文件
        pickle.dump(md5_dict,fobj)

#增量备份
def incr_backup(folder,dest,md5file):
    md5_dict={}  # 用于保存每个文件的MD5值{“文件绝对路径” :md5值}
    fname=os.path.basename(folder.rstrip("/"))
    fname="%s_full_%s.tar.gz"%(fname,strftime("%Y%m%d"))
    fname=os.path.join(dest,fname)  # 目标文件的绝对路径

    for path,folders,files in os.walk(folder):
        for file in files:
            key = os.path.join(path,file)      #拼出绝对路径
            md5_dict[key] = check_md5(key)    #计算当前文件的md5值

    with open(md5file,"rb") as fobj:
        oldmd5 = pickle.load(fobj)      #取出前一天文件MD5值

    with  open(md5file,"wb") as fobj:
        pickle.dump(md5_dict,fobj)       #更新文件md5值

    tar = tarfile.open(fname,"w:gz")
    for key in  md5_dict:
        if oldmd5.get(key) != md5_dict[key]:
            tar.add(key)              #新文件,有变化文件进行备份
    tar.close()

if __name__ == '__main__':
    folder = "/tmp/demo/security"
    dest = "/tmp/demo"
    md5file = "/tmp/demo/md5file"
    if strftime("%a") == "Mon":
        full_backup(folder,dest,md5file)
    else:
        incr_backup(folder,dest,md5file)




十、OOP(面向对象编程)

1. 基本概念

类(Class):
用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法。对象是类的实例

实例化
创建一个类的实例,类的具体对象 。

方法
类中定义的函数

对象
通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。


2. 创建类

使用class 语句来创建一个新类,class之后为类的名称并以冒名结尾
类名建议使用驼峰形式

class BearToy:
    pass

游戏人物:
名字、职业、性别、装备、武器 、位置
跳、走、飞、攻击

OOP:面向对象的编程,实现属性和行为的融合统一
calss Hero:
name =
gender =
def run():
move


2. 子类

OOP的更强大方面之一是能够使用一个已经定义好的类,扩展它或者对其进行修改,而不会影响系统中
使用现存的其它代码片段
OOD(面向对象设计)允许类特征在子孙类或子类中进行继承

创建子类
创建子类只需要在圆括号中写明从哪个父类继承即可

class Vendor:
    def __init__(self,phone):
        self.phone = phone

    def dial(self):
        print("calling %s" % self.phone)

class BearToy:
    def __init__(self,size,color):
        """实例化一个对象时,自动调用"""
        self.size = size                     #bear_big.size = "Large"
        self.color = color                 #bear_big.color = "Brown"
        self.vendor = Vendor("400-800-1234")      #一个类是另一个类的组件   

    def sing(self):
        print("my color is %s,lalala..." % self.color)

class NewBearToy(BearToy):      #子类 括号中填入的是父类、基类
    def __init__(self,name,size,color):
    # BearToy.__init__(self,size,color): 和下面super功能一样其中一条都可以
        super(NewBearToy,self).__init__(size,color)
        self.name = name 
    

if __name__ == '__main__':
    # bear_big = BearToy("Large","Brown")    #实例化,bear_big自动作为第一个参数传递
    # vendor=Vendor("400-800-1234")
    # print(bear_big.vendor.phone)
    # bear_big.vendor.dial()
    # print(bear_big.size)
    # print(bear_big.color)
    # bear_big.sing()
    bear2 =NewBearToy("Middle","Brown")
    bear2.sing()

3. 多重继承

Python允许多重继承,即一个类可以是对个父类的子类,子类可以拥有所有的父类的属性

class Foo:
    def hello(self):
        print("hello world")

class Bar:
    def welcome(self):
        print("how are you?")
        
class FooBar(Foo,Bar):
    '子类有多个父类,它将继承所有父类的方法'
    pass    

3. 静态方法

基本上就是一个函数
在语法上就像一个方法
没有访问对象和它的字段或方法
语法
使用staticmethod装饰器定义
@staticmethod

静态实例

class Book:
    def __init__(self,title,author):
        self.title = title
        self.author = author

    def __str__(self):
        return "<<%s>>" % self.title

    def __call__(self):
        print("<<%s>>is written by %s. " % (self.title,self.author))

if __name__ == '__main__':
    core_py = Book("Core Python","Wesley")
    print(core_py)        #调用 __str__方法
    print(core_py())     #调用__call__方法


4. 类方法

使用classmethod 装饰器定义
第一个参数cls 表示类本身

class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def create(cls,str_date):
        "类中的方法,没有实例不能直接调用,需要将其定义为类方法"
        year,month,day = map(int,str_date.split("-"))
        instance = cls(year,month,day)
        return instance

    @staticmethod    #静态方法
    def check_date(cls,str_date):
        "相当于和类没有关系,只是把一个函数放到类中"
        year,month,day=map(int,str_date.split("-"))
        return year<4000 and 1<=month<=12 and 1<=day
if __name__ == '__main__':
    d1 = Date(2019,12,15)
    print(d1.year)
    d2 = Date.create("2020-8-1")
    print(d2)

###############################################################################################


十一、 search 函数

import re
m = re.search("f..","seafood")
m.group()                                     #得到 foo

1. findall

re.findall("f..","seafood is food")    # 匹配所有 ,返回列表 
["foo","foo"]

2. finditer

re.finditer("f..","seafood is food")        #不是直接返回列表,返回的是所有匹配对象的生成器   

3. split

re.split("\.|-","hello-world.tar.gz")    # 以.和- 区分 字符串
["hello","world","tar","gz"]  

4. sub

re.sub("n[a-z]me,"Niu","Hi name,Nice to meet you nbme!")
"Hi Niu, Nice to meet you Niu!"

"Hi name,Nice to meet you nbme!" .replace("name","Niu")   #用replace也可以替换

5. compile

在进行大量匹配的时候,先把模式pattern 编译一下,可以提升效率

patt = re.compile("f..")
m = patt.search("seafood")
m.group()

练习:分析Apache访问日志

编写一个Apache日志分析脚本

  1. 统计每个客户端访问Apache服务器的次数
  2. 将统计信息通过字典的方式显示出来
  3. 分别统计客户端是Firefox 和MSIE的访问次数
  4. 分别使用函数式编程和面向对象编程的方式实现
import re
def count_patt(fname,patt):
    cpatt = re.compile(patt)
    patt_dict = {}
    with open(fname) as fobj:
        for line in fobj:
            m = cpatt.search(line)
            if m:
                key = m.group()
                patt_dict[key] = patt_dict.get(key,0) +1
    return patt_dict

if __name__ == '__main__':
    fname = r"D:\a\access_log"
    ip = "^(\d+\.){3}\d+"
    br = "Chrome|Firefox|MSIE"
    print(count_patt(fname,ip))
    print(count_patt(fname,br))

————————————————————————————————

import re
from collections import Counter

class CountPatt:
    def __init__(self,patt):
        self.cpatt = re.compile(patt)

    def count_patt(self,fname):
       # cpatt=re.compile(patt)
       # patt_dict={}
        result = Counter()
        with open(fname) as fobj:
            for line in fobj:
                m=self.cpatt.search(line)
                if m:
                    key=m.group()
                    result.update([key])
                   # patt_dict[key]=patt_dict.get(key,0) + 1
        # return patt_dict
        return result
if __name__ == '__main__':
    fname=r"D:\a\access_log"
    ip="^(\d+\.){3}\d+"
    cp = CountPatt(ip)
    print(cp.count_patt(fname))

###############################################################################################

十二、 re模块(正则)

使用正则需要导入re模块

import re

1. 匹配单个字符

记号 说明
. 匹配任意字符(换行符除外)单单一个字符
[…x-y…] 匹配字符组里的任意字符
[^…x-y…] 匹配不在字符组里的任意字符
\d 匹配任意数字,与[0-9]同义
\D 匹配非数字
\w 匹配任意数字字母字符,与[0-9a-zA-Z]同义
\W 匹配非任意数字字母字符 --空格和符号
\s 匹配空白字符,与[\r\v\f\t\n] 同义
\S 匹配非空白字符

测试
在vim里面 输入 / 加内容 例如 /\D 匹配非数字
搜索tm字符内容

/t.m
/t[0-9a-z]m
/\W 
/t[-a0]m
/t[0-9^]m   #和/t[^0-9]m   意义一样,取反

2. 匹配一组字符

记号 说明
literal 匹配字符串的值
re1 re2
* 匹配前面出现的正则表达式零次或多次
+ 匹配前面出现的正则表达式一次或多次
匹配前面出现的正则表达式零次或一次
{M,N} 匹配前面出现的正则表达式至少M次最多N次

例如:

/tam\|t8m 
/t\{3,5\}m   
/t\{3,\}
/t\?m 
/t\+m   

3. 其他元字符

记号 说明
^ 匹配字符串的开始
$ 匹配字符串的结尾
\b 匹配单词的边界
() 对正则表达式分组
\nn 匹配已保存的子组

4. 贪婪匹配

    • 和? 都是贪婪匹配操作符,在其后加上? 可以 取消其贪婪匹配行为
      正则表达式匹配对象通过groups函数 获取子组
data = "His phone number is : 150889912"
m = re.search(".+|(\d+\)",data)  #默认+ 或者 * 都是贪婪匹配
m.group()                         #总是返回整个模式匹配到的内容
"His phone number is : 150889912"   
m.group(1)
"2"
m = re.search(".+?|(\d+\)",data)              #  ?  可以取消贪婪匹配
m.group()
"His phone number is : 150889912"   
m.group(1)
"150889912"

————————————————————————————————————————

import re
re.match("f..","food")                             #如果匹配到,返回一个匹配对象
print(re.match("f","seafood"))             #没有匹配到,返回None
m = re.match("f..","food')
m.group()

###############################################################################################

十三、socket模块

1. 套接字

套接字是一种具有“通讯端点” 概念的计算机网络数据结构
家族名为 AF_UNIX
基于网络的 ,家族名 为 AF_INET

2. 面向连接与无连接

无论你使用哪一种地址家族,套接字的类型只有两种。

  1. 一种是面向连接的套接字
  2. 另一种是无连接的套接字

TCP
面向连接的主要协议就是传输控制协议TCP ,套接字类型为 SOCK_STREAM

UDP
无连接的主要协议是用户数据报协议UDP ,套接字类型为 SOCK_DGRAM

Python中使用socket模块中的socket函数实现套接字的创建

3. Python字符串str和bytes类型转换

Python中所有的字符有:str类型和bytes类型
str类型转换为bytes类型 ( encode 和 decode )

a = "你好"
type(a)
<class "str">  
a.encode()                   #将str 转换为bytes 
b'xe4\xbd\xa0\xe5\xa5\xbd'


b = b"Hello"
tyep(b)
<class "bytes">
b.decode()                    #将bytes转换为str  

3. TCP

面向连接的主要协议就是 传输控制协议 TCP ,
套接字类型: SOCK_STREAM

创建TCP服务器

创建TCP服务器的主要步骤如下:

  1. 创建服务器套接字:s = socket.socket()
  2. 绑定地址到套接字:s.bind()
  3. 启动监听:s.listen()
  4. 接受客户端连接:s.accept()
  5. 与客户端通信: recv()/send()
  6. 关闭套接字: s.close()

参考代码

import socket
host = ""                                                         #代表0.0.0.0  
port = 12345                                                            #应该大于1024  
addr = (host,port)        
s = socket.socket()                                                            #默认使用TCP协议
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)  #设置套接字选项,使得服务程序结束后立即再启动
s.bind(addr)
s.listen(1)                                                                       #一般只能写到5以内,表示允许多少客户端排队访问
cli_sock,cli_addr = s.accept()  
print("客户端:",cli_addr)
data = cli_sock.recv(1024)                                          #相当于fobj.read(1024)
print(data)
print(data.decode())
sdata = "欢迎!\r\n"
cli_sock.send(sdata.encode())                          #发送的数据必需是bytes类型,二进制
cli_sock.close()
s.close()

创建TCP客户端

创建TCP 客户端的步骤主要如下 :

  1. 创建客户端套接字:cs = socket.socket()
  2. 尝试连接服务器: cs=connet()
  3. 与服务器通信:cs.send()/cs.recv()
  4. 关闭客户端套接字:cs.close()

参考代码

import socket

host = "127.0.0.1"
port = "12345"
addr = (host,port)
c = socket.socket()
c.connect(addr)
c.send(b"Hello World!\r\n")
data = c.recv(1024)
print(data.decode(),end="")
c.close()

4. UDP

无连接的主要协议是用户 数据报协议 UDP ,
套接字类型: SOCK_DGRAM

创建UDP服务器

创建UDP服务器的主要步骤如下:

  1. 创建服务器套接字:s =socket.socket()
  2. 绑定服务器套接字:s.bind()
  3. 接收、发送数据: s.recvfrom()/ss.sendto()
  4. 关闭套接字: s.close()

参考代码

import socket

host = ""
port = 12345
addr = (host,port)
s = socket.socket(type=socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(addr)

data,cli_addr = s.recvfrom(1024)
print(data.decode(),end="")
s.sendto(b"How are you?\r\n",cli_addr)
s.close()
                   

创建UDP客户端

创建UDP客户端的步骤主要如下:

  1. 创建客户端套接字:cs = socket.socket()
  2. 与服务器通信: cs.sendto()/cs.recvfrom()
  3. 关闭客户端套接字:cs.close()

参考代码

import socket
host = ""
port = 12345
addr = (host,port)
c = socket.socket(type=socket.SOCK_DGRAM)

c.sendto(b"Nice to meet you!\r\n",addr)
data,ser_addr = c.recvfrom(1024)
print(data.decode())
c.close()

UPD服务器循环

为了实现不间断接收信息

import socket

host = ""
port = 12345
addr = (host,port)
s = socket.socket(type=socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(addr)

while True:
    data,cli_addr = s.recvfrom(1024)
    print(data.decode(),end="")
    s.sendto(b"How are you?\r\n",cli_addr)
s.close()

UDP客户端循环

import socket

host = ""
port = 12345
addr = (host,port)
c = socket.socket(type=socket.SOCK_DGRAM)

while True:
    sdata = input(">")+"\r\n"
    if sdata.strip() == "quit":
        break
    c.sendto(b"Nice to meet you!\r\n",addr)
    data,ser_addr = c.recvfrom(1024)
    print(data.decode())
c.close()


你可能感兴趣的:(笔记,IT,运维认知,python,运维,linux)