Python基础

Python基础知识

一、变量的概念

1、变量和常量
  • 常量:固定 的值,不能发生改变
  • 变量:里面盛放的值,随时可以发生改变
  • 声明一个变量,相当于在内存上开了一块空间
2、定义变量
# 变量的赋值
# 定义一个变量的名称为 num
num = 100

二、变量的类型

image-20220411191535236

image-20220411165057702

# 在Python中,不需要单独去声明变量的类型

price = 68.00  # 价格
count = 2  # 数量
money = 136.00  # 总价
name = "alex"  # 客户名称
tel = "18222837227"  # 电话
sale = True  # 是否有货
hdie = False  # 是否允许匿名评价

print(type(price))  # 查看 price 的类型
print(type(sale))   # 查看 sale 的类型


money  = money - 5 #并没有创建新的变量,而是使用原来的变量
----------------------------------------------
<class 'float'>
<class 'bool'>

三、变量的命名规则

  • 标识符由字母、下划线和数字组成,且数字不能开头

    • 中文也可用作变量名,在Python 3.x版本中,语言的编码格式是 UTF - 8 ,支持中文
  • python中的标识符是区分大小写的

  • 驼峰命名法

    • 小驼峰式命名法(lower camel case): 第一个单词以小写字母开始;第二个单词的首字母大写,例如:myName、aDog
    • 大驼峰式命名法(upper camel case): 每一个单字的首字母都采用大写字母,例如:FirstName、LastName
    • 还有一种命名法是用下划线“_”来连接所有的单词,比如send_buf,
    student_name = 'James'      #下划线命名法
    studentName = 'Curry'       #小驼峰命名法
    UserLoginFlag = 'xxxxxx'  #大驼峰命名法
    
  • 关键字

    • python一些具有特殊功能的标识符,这就是所谓的关键字
    • 关键字,是python已经使用的了,所以不允许开发者自己定义和关键字相同的名字的标识符
    Anna = 18
    anna = 16  # 这是两个变量
    print(id(Anna),id(anna))        #查看变量的ID
    
    # 关键字就是系统已经定义好的变量名,开发者不能再使用了
    import keyword
    print(keyword.kwlist)  # 打印当前系统的关键字
    -----------------------------------------------------------
    ['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']
    

四、变量的输入

1. input()
password = input("请输入密码:")
print('您刚刚输入的密码是:%d' % password)
img
  • input()的小括号中放入的是,提示信息,用来在获取数据之前给用户的一个简单提示
  • input()在从键盘获取了数据以后,会存放到等号右边的变量中
  • input()会把用户输入的任何值都作为字符串来对待
2、常用的数据类型转换
函数说明
int(x)将x转换为一个整数
float(x )将x转换为一个浮点数
complex(real [,imag ])创建一个复数,real为实部,imag为虚部
str(x )将对象 x 转换为字符串
repr(x )将对象 x 转换为表达式字符串
eval(str )用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s )将序列 s 转换为一个元组
list(s )将序列 s 转换为一个列表
chr(x )将一个整数转换为一个Unicode字符
ord(x )将一个字符转换为它的ASCII整数值
hex(x )将一个整数转换为一个十六进制字符串
oct(x )将一个整数转换为一个八进制字符串
bin(x )将一个整数转换为一个二进制字符串
"""
数据类型转换
字符串类型想要转换数字类型,需要输入阿拉伯数字
int不能转换带.的字符串,float可以
float可以被int转换
"""

passwd = input("请输入您的银行卡密码:")

#passwd 是一个字符串类型的变量,如果他的值,看起来像数字,就可以转换成数字类型(整数,浮点型)

#将passwd转换成int
passwd_int  = int(passwd)       #不能接受带.的数据
print(passwd_int,type(passwd_int))

#将passwd转换成float
passwd_float = float(passwd)
print(passwd_float,type(passwd_float))

3、变量输入演练—超市买苹果
  • 需求

    收银员输入 苹果的价格,单位:元/斤

    收银员输入 用户购买苹果的重量,单位:斤

    计算并且 输出 付款金额

  • 实验代码

    #收银员输入 苹果的价格,单位:元/斤
    price = input("请输入苹果的价格:")
    #收银员输入 用户购买苹果的重量,单位:斤
    weight = input("请输入苹果的重量:")
    #计算并且 输出 付款金额
    #在计算之前,需要进行数据类型转换
    money = float(price) * float(weight)
    print("苹果的总价格是",money,"元")
    

五、变量的输出

1、print的使用
name = "James"
age = "37"
gender = "boy"
"""
print(value,...,sep=' ',end='\n')     #print函数的完整形式
    在值之间插入字符串,默认是一个 space
    sep:   string inserted between values, default a space.
    在值的最后追加一个字符串,默认是一个\n
    end:   string appended after the last value, default a newline.
"""
print(name,age,gender,sep='-',end='\n')
2、常见的转义符
转义字符说明
\n换行符,将光标位置移到下一行开头。
\r回车符,将光标位置移到本行开头。
\t水平制表符,也即 Tab 键,一般相当于四个空格。
\a蜂鸣器响铃。注意不是喇叭发声,现在的计算机很多都不带蜂鸣器了,所以响铃不一定有效。
\b退格(Backspace),将光标位置移到前一列。
\\反斜线
\’单引号
\"双引号
\在字符串行尾的续行符,即一行未完,转到下一行继续写。
3、格式化输出
person = "杨宇波"
address = " 天津市西青区天津市大学软件学院"
phone = "2150511032"

# 可以使用 “+” 来进行字符串的拼接
print("收件人是:" + person + ",地址为:" + address + "手机号:" + phone)
print("收件人是 %s,地址是 %s,电话号为: %s" % (person, address, phone))

# 使用占位符
price = 2.00
weight = 15

# %d代表整型变量,%.02f表示浮点型变量(保留两位小鼠),%s代表字符串
print("西瓜的价格是 %.02f 元/斤,重量是 %d 斤" % (price, weight))
print("西瓜的价格是 {} 元/斤,重量是 {} 斤".format(price, weight))
print("西瓜的价格是 {0} 元/斤,重量是 {1} 斤".format(price, weight))
print(f"西瓜的价格是 {price} 元/斤,重量是 {weight} 斤") #Python3.7以后支持
4、拳皇实验
  • 实验代码
"""
游戏:拳皇97
输入游戏玩家姓名
输入密码
输入充值信息

"""

#游戏头
print("*" * 50)
print(" " * 22,"拳皇97","" * 22)
print("*" * 50)
#输入用户名
username = input("请输入用户名:")
#输入密码
password = input("请输入密码:")
#提示充值
balance = 10
print("恭喜登录成功!当前余额为{},请出入充值金额".format(balance))
#接受充值
coin = input("请输入您要充值的金额")
balance = balance + int(coin)
#输出 x 充值成功!当前余额位x,请开始游戏
print("{}充值成功! 当前余额为{},请开始游戏!".format(username,balance))
  • 输出结果
**************************************************
                       拳皇97 
**************************************************
请输入用户名:123
请输入密码:123
恭喜登录成功!当前余额为10,请出入充值金额
请输入您要充值的金额10
123充值成功! 当前余额为20,请开始游戏
5、LOL实验
  • 实验代码
"""
游戏:英雄联盟
输入角色
输入拥有的装备
输入想购买的装备
输入付款金额
输出:xxxx 拥有xxxx,花了xxxx元钱
"""

banner = "    / /        //   ) ) / /\n    / /        //   / / / /\n   / /        //   / / / / \n  / /        //   / / / /\n / /____/ / ((___/ / / /____/ /"
print(f"欢迎来到:\n {banner}")
print("-" * 50)

# 输入角色
role = input("请输入英雄名称:")
# 输入拥有的装备
equipment = input("请输入拥有的装备:")
print(f"{role}带着{equipment}出门了!")
# 输入想购买的装备
wanna_equ = input("请输入想要购买的装备名:")
# 输入付款金额
pay = input("请输入付款金额:")
# 输出:xxxx 拥有xxxx,花了xxxx元钱
print("{}购买了{},花费了{}金币!".format(role, wanna_equ,pay))

  • 输出结果
欢迎来到:
     / /        //   ) ) / /
    / /        //   / / / /
   / /        //   / / / / 
  / /        //   / / / /
 / /____/ / ((___/ / / /____/ /
--------------------------------------------------
请输入英雄名称:疾风剑豪
请输入拥有的装备:无尽之刃
疾风剑豪带着无尽之刃出门了!
请输入想要购买的装备名:鬼索的狂暴之刃
请输入付款金额:1000
疾风剑豪购买了鬼索的狂暴之刃,花费了1000金币!

六、扩展赋值运算符

赋值运算符说 明举 例展开形式
=最基本的赋值运算x = yx = y
+=加赋值x += yx = x + y
-=减赋值x -= yx = x - y
*=乘赋值x *= yx = x * y
/=除赋值x /= yx = x / y
%=取余数赋值x %= yx = x % y
**=幂赋值x **= yx = x ** y
//=取整数赋值x //= yx = x // y

七、算数运算符

运算符描述实例
+加 - 两个对象相加a + b 输出结果 30
-减 - 得到负数或是一个数减去另一个数a - b 输出结果 -10
*乘 - 两个数相乘或是返回一个被重复若干次的字符串a * b 输出结果 200
/除 - x除以yb / a 输出结果 2
%取模 - 返回除法的余数b % a 输出结果 0
**幂 - 返回x的y次幂a**b 为10的20次方, 输出结果 100000000000000000000
//取整除 - 返回商的整数部分(向下取整>>> 9//2 4 >>> -9//2 -5

八、关系运算符

运算符描述实例
==等于 - 比较对象是否相等(a == b) 返回 False。
!=不等于 - 比较两个对象是否不相等(a != b) 返回 true.
<>不等于 - 比较两个对象是否不相等。python3 已废弃。(a <> b) 返回 true。这个运算符类似 != 。
>大于 - 返回x是否大于y(a > b) 返回 False。
<小于 - 返回x是否小于y。(a < b) 返回 true。
>=大于等于 - 返回x是否大于等于y。(a >= b) 返回 False。
<=小于等于 - 返回x是否小于等于y。(a <= b) 返回 true。

九、逻辑运算符

运算符逻辑表达式描述实例
andx and y布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。(a and b) 返回 20。
orx or y布尔"或" - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。(a or b) 返回 10。
notnot x布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。not(a and b) 返回 False
1、and
  • / 并且
  • 两个条件同时满足,返回 True
  • 只要有一个条件不满足,就返回 False
条件1条件2结果
成立成立成立
成立不成立不成立
不成立成立不成立
不成立不成立不成立
2、or
  • / 或者
  • 两个条件只要有一个满足,返回 True
  • 两个条件都不满足,返回 False
条件1条件2结果
成立成立成立
成立不成立成立
不成立成立成立
不成立不成立不成立
3、not
  • 非 / 不是
条件结果
成立不成立
不成立成立
4、三目运算符

结果 if 表达式 else 结果

如果是真,返回前面的结果,如果是假,则返回后面的结果

判断语句与循环语句

一、 if判断语句基本格式介绍

 if 要判断的条件:
        条件成立时,要做的事情

二、 if-else的使用格式

   if 条件:
        满足条件时要做的事情1
        满足条件时要做的事情2
        满足条件时要做的事情3
        ...(省略)...
    else:
        不满足条件时要做的事情1
        不满足条件时要做的事情2
        不满足条件时要做的事情3
        ...(省略)...

三、if…elif…else…语句格式

1、elif的功能
    if xxx1:
        事情1
    elif xxx2:
        事情2
    elif xxx3:
        事情3

说明:

  • 当xxx1满足时,执行事情1,然后整个if结束
  • 当xxx1不满足时,那么判断xxx2,如果xxx2满足,则执行事情2,然后整个if结束
  • 当xxx1不满足时,xxx2也不满足,如果xxx3满足,则执行事情3,然后整个if结束
    score = 77

    if score>=90 and score<=100:
        print('本次考试,等级为A')
    elif score>=80 and score<90:
        print('本次考试,等级为B')
    elif score>=70 and score<80:
        print('本次考试,等级为C')
    elif score>=60 and score<70:
        print('本次考试,等级为D')
    elif score>=0 and score<60:
        print('本次考试,等级为E')
2、注意点
  • 可以和else一起使用
   if 性别为男性:
       输出男性的体重
       ...
   elif 性别为女性:
       输出女性的体重
       ...
   else:
       第三种性别的体重
       ...
  • 当 “性别为男性” 满足时,执行 “输出男性的体重”的相关代码
  • 当 “性别为男性” 不满足时,如果 “性别为女性”满足,则执行 “输出女性的体重”的相关代码
  • 当 “性别为男性” 不满足,“性别为女性”也不满足,那么久默认执行else后面的代码,即 “第三种性别的体重”相关代码

四、for循环

1、for循环的格式
for 临时变量 in 列表或者字符串等可迭代对象:
    循环满足条件时执行的代码
2、for循环练习
for i in  range(1,6):
    if i == 3 :
        print("这个馒头有毒!!!")
        print("没有吃饱/(ㄒoㄒ)/~~")
        break
    else:
        print(f"正在吃第{i}个馒头")

else:       #当for循环结束后,会执行 else 语句,如果被break打断,就不会再执行!
    print("吃饱了~~~~")

五、while循环

1、while循环
    while 条件:
        条件满足时,做的事情1
        条件满足时,做的事情2
        条件满足时,做的事情3
        ...(省略)...
2、while练习
i = 1
while i <= 5:
    print(f"这是第{i}遍Hello World!")
    i += 1
3、while嵌套的格式
  while 条件1:

        条件1满足时,做的事情1
        条件1满足时,做的事情2
        条件1满足时,做的事情3
        ...(省略)...

        while 条件2:
            条件2满足时,做的事情1
            条件2满足时,做的事情2
            条件2满足时,做的事情3
            ...(省略)...
4、while练习
i = 1
while i <= 9:
    j = 1
    while j <= i:
        print(f"{j}*{i}={i*j}",end='\t')
        j  += 1
    print()
    i+=1

字符串、列表、元组、字典、集合

一、列表

1、列表的格式
  • 列表中的元素可以是不同类型的
name_list = ["James", "Curry", "Young", "Kuzma"]
2、打印列表
name_list = ["James", "Curry", "Young", "Kuzma"]

print(name_list[0])
print(name_list[1])
print(name_list[2])
James
Curry
Young
3、列表的循环遍历
#列表的遍历,就是将这个列表中的元素,按照顺序进行某些操作
name_list_1 = [1, 4, 5, 6, 87, 9, 2, 3, 4, 6, 7, 8]
name_list_1.sort(reverse=True)
for item in  name_list_1 :
    print(item)
87
9
8
7
6
6
5
4
4
3
2
1
4、列表的相关操作
①、添加元素
  • append

    • 通过append可以向列表添加元素

    • name_list = ["张三", "李四", "王五"]
      # 增加元素
      # 1、.append(),会在列表的最后增加一个元素
      name_list.append("Curry")
      print(name_list)
      
  • extend
    • 通过extend可以将另一个集合中的元素逐一添加到列表中

    • # extend 将两个列表拼接到一起
      name_list = ["张三", "李四", "王五"]
      name_list1 = ["Thompson", "Poole", "Monk", "Reaves"]
      
      name_list.extend(name_list1)
      print(name_list)
      
  • insert
    • insert(index, object) 在指定位置index前插入元素object

    • # .insert()     ,在列表范围内,根据索引值 ,插入一个值,后续的元素,往后排列
      name_list = ["张三", "李四", "王五"]
      name_list.insert(3, "Young")
      print(name_list)
      # 超出范围会拍到最后
      name_list.insert(66, "Kuzma")
      print(name_list)
      
②、查找元素
  • in, not in
    • in(存在),如果存在那么结果为true,否则为false

    • not in(不存在),如果不存在那么结果为true,否则false

    • # in成员运算符
      name = "James"
      result = 'J' in name
      print(result)  # True
      
      result = 'Jm' in name
      print(result)  # False
      
③、删除元素
  • del

    • 根据下标进行删除

    • name_list = ["James", "Curry", "Young", "Kuzma"]
      # del 关键字  会将列表或者元素从内存中直接删除
      del name_list[0]
      print(name_list)
      
      # 直接删除列表
      del name_list
      print(name_list)
      
  • pop

    • 删除最后一个元素

    • name_list = ["James", "Curry", "Young", "Kuzma"]
      # pop删除列表的最后一个元素
      name_list.pop()
      print(name_list)
      
      # pop()可以指定索引删除对应值
      name_list.pop(0)
      print(name_list)
      
  • remove

    • 根据元素的值进行删除

    • name_list = ["James", "Curry", "Young", "Kuzma"]
      
      # remove 删除指定元素
      print(name_list)
      name_list.remove("Young")
      print(name_list)
      
④、排序
  • sort

    • 升序排列

    • # .sort() 升序排列
      num_list = [1, 4, 5, 6, 87, 9, 2, 3, 4, 6, 7, 8]
      
      # 将整个列表中的元素进行升序排列
      num_list.sort()
      print(num_list)
      
      # 将整个列表中的元素进行降序排列
      num_list.sort(reverse=True)
      print(num_list)
      
  • reverse

    • 将列表的元素倒着输出,不会排序

    • # .reverse()方法,将列表的元素倒着输出,不会排序
      name_list_1 = [1, 4, 5, 6, 87, 9, 2, 3, 4, 6, 7, 8]
      name_list_1.reverse()
      print(name_list_1)
      
⑤、统计
  • count

    • 统计某个元素出现的次数

    • # .count()函数
      name_list = ["James", "Curry", "James", "Young", "Kuzma", "James"]
      print(name_list.count("James"))
      # 这时候remove删除,只会删除第一个元素
      name_list.remove("James")
      print(name_list)
      

二、字符串

1、字符串的操作
# 字符串可以看作是一列字符的有序的集合,但是在 Python ,没有字符(char)的概念,只有string的概念

name = "abcdefg"

"""

"""

# 下列三个变量的ID相同
letter = 'a'
letter_01 = "a"
letter_02 = '''a'''
print(id(letter), id(letter_01), id(letter_02))
print(letter is letter_01 is letter_02)

s1 = input("请输入:")
s2 = input("请出入:")
print(s1 == s2)
print(s1 is s2)     # 如果输入的字符串长度是0或者1,结果为True,否则为False

2、切片

切片是指对操作的对象截取其中一部分的操作。字符串、列表、元组都支持切片操作。

  • 切片的语法

    • [起始:结束:步长]
    • """
      索引分为正索引和负索引
      正索引:从0开始的第几个
      负索引:倒数第几个
      
      语法:
          str[start:end:方向(±)/步长]
          方向:切片的时候,字符串的输出方向
              + :正着输出
              - :反着输出
              默认情况下是正向输出
          步长:出去切片值的时候,取值的间隔
      """
      # 切片1:根据索引取值
      
      filename = "picture.png"
      print(filename[5])  # 输出:r
      
      # 切片2:截取部分字符串
      print(filename[0:7])  # 取从0到7之前的元素,包前不包后
      print("索引5对应的元素为:{}".format(filename[7]))
      
      # 省略开头
      print(filename[7:])  # 从7开始一直取到最后
      # 省略结尾
      print(filename[:7])  # 从开头一直取值到6
      
      # 取负数值
      print(filename[8:-1])  # 从第8个元素开始,取值到倒数第1个之前(不包含倒数第1个)
      print(filename[:-2])  # 从开头取值,一直取值到倒数第2个之前
      print(filename[-2:])  # 从倒数第2个值取值,取到结尾
      
      # [::] 将这个字符串取值,从前取到最后
      print(filename[::])
      
      #方向/步长,步长默认为1
      print(filename[::-1])  #反着输出
      print(filename[::-2])
      
      #带有步长的切片
      print(filename[-1:-5:-1])       #切片默认从左到右,-1代表从右向左取值
      
      
3、字符串的常见操作
3.1、与大小写相关操作
"""
1、和大小写相关的

"""

message = "Who do not do the next, first I do !"

# .capitalize()
print(message.capitalize())

# .title()       #将每个单词的首字母大写
print(message.title())

# .upper()      #将单词全部转换为大写
str_upper = message.upper()
print(str_upper)

# .lower()        #将单词全部转换为小写
print(message.lower())

# .istitle()     返回的结果是bool类型的 Ture False 判断字符串是否符合 title的格式(每个单词开头都大写)
# 是 返回 True ,否 返回 False
str2 = "Who Do Not Do The Next, First I Do !"
print(str2.istitle())
print(message.istitle())
3.2、find

检测 str 是否包含在 mystr中,如果是返回开始的索引值,否则返回-1

mystr = 'hello world itcast and itcastcpp
mystr.find(str, start=0, end=len(mystr))
3.3、index

跟find()方法一样,只不过如果str不在 mystr中会报一个异常.

mystr = 'hello world itcast and itcastcpp
mystr.index(str, start=0, end=len(mystr))
3.4、count

返回 str在start和end之间 在 mystr里面出现的次数

mystr = 'hello world itcast and itcastcpp
mystr.count(str, start=0, end=len(mystr))
3.5、replace

把 mystr 中的 str1 替换成 str2,如果 count 指定,则替换不超过 count 次.

mystr = 'hello world itcast and itcastcpp
mystr.replace(str1, str2,  count=mystr.count(str1))
3.6、split

以 str 为分隔符切片 mystr,如果 maxsplit有指定值,则仅分隔 maxsplit+1 个子字符串

mystr = 'hello world itcast and itcastcpp
mystr.split(str=" ", 2)
3.7、strip

能去除字符串前后的空格

"""

strip lstrip rstrip

strip 能去除字符串前后的空格
"""
str1= "   Lebron James  "
str2 = str1.strip()
print(str1)
print(str2)

#去除左边的空格
str3 = str1.lstrip()
print(str3)

#去除右边的空格
str4=str1.rstrip()
print(str4)

三、元组

1、元组的介绍

Python的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。

# 定义一个元组
tuple_1 = ()  # 没有元素的元组, 是一个空元组
print(type(tuple_1))

tuple_1_1 = tuple()  # 定义空元组的方法
print(type(tuple_1_1))

tuple_2 = ("a", 1)  # 假如只有一个元素需要加,才能构成元组
print(type(tuple_2))

print(tuple_2.index("a"))  # 元组可以通过值取索引
print(tuple_2[0])  # 可以通过索引取值       元组是一个有序的数据的集合

a = 1
b = 2
a, b = b, a
print(a, b)

2、拆包与装包
t1 = (2, 3, 6, 8, 0, 5)
# 可以看到表达式的左边没用括号,表达式的右边,是带括号的,t1不可以直接对左边的表达式赋值
# 需要先将t1的括号去掉(拆包),然后在给左边的变量进行赋值
a, *b, c = t1  # *b代表可以接受非固定的数的元素

print(b)  # [3, 6, 8, 0]
print(*b)  # 3 6 8 0
# *b不属于任何类型,如果要使用*b,则对*b进行装包  b= [3 6 8 0](装包)

t1 = (9,)
a, *b = t1
print(a, b)  # 9 []

x, y, *z = "hello"
print(x, y, z)  # h e ['l', 'l', 'o'],z并不等于"llo",而是一个列表
print(*z)  # l l o

# 列表的拆包和装包
x, y, *z = ['aa', 6, 'hello', 'good', 'happy', 'Lucky']
print(x,y,z)
print(*z)

四、字典

1、字典的格式
tom = {"name":"tom",        #"name":"tom"叫做一个键值对
       "age":18,
       "height":1.75,
       "weight":75}
  • 字典和列表一样,也能够存储多个数据
  • 列表中找某个元素时,是根据下标进行的
  • 字典中找某个元素时,是根据’名字’(就是冒号:前面的那个值,例如上面代码中的’name’、age’、‘height’)
  • 字典的每个元素由2部分组成,键:值。
2、根据键访问值
info = {'name':'杨宇波', 'id':100, 'sex':'f', 'address':'天津市大学软件学院'}

print(info['name'])
print(info['address'])
杨宇波
天津市大学软件学院
3、字典的常见操作
3.1、添加元素
info = {'name': '杨宇波', 'id': 100, 'sex': 'f', 'address': '天津市大学软件学院'}
info['phone'] = "123123123"
print(info)
{'name': '杨宇波', 'id': 100, 'sex': 'f', 'address': '天津市大学软件学院', 'phone': '123123123'}
3.2、删除元素
"""
删除 del pop()
pop(pop(key[,defalut]) )  
"""
dict_2 = {"张三": 100, "李四": 40, "王五": 100, "小赵": 110}

# del dict_2["王五"]
# print(dict_2)

print(dict_2.pop("王五", "没有这个键值对"))  # pop("要删除的键","如果字典中没有王五这个键,则提示的信息")
print(dict_2)

print(dict_2.popitem())  # 随机删除,一般删除最后一一个
3.3、items
  • 字典的解封装,将字典拆包,生成 一个dict_items 的一个集合,dict_items的每个元素都是一个元组,元组包含了键值对

  • """
    items()     #字典的解封装,将字典拆包,生成 一个dict_items 的一个集合,
                dict_items的每个元素都是一个元组,元组包含了键值对
    """
    
    result = dict_1.items()  # 数据类型是dict_items
    print(result, type(result))
    
    for key, value in dict_1.items():
        if value > 90:
            print(key)
    
    # values()和key()是字典的属性,而不是字典解封装的属性
    print(dict_1.keys())
    print(dict_1.values())
    
3.4、update
  • 将两个字典合并成1个

  • """
    update() 将两个字典合并成1个
    """
    
    dict1 = {0: "tom", 1: "jack", 2: "lucy"}  # 字典中不能出现相同的键,如果在合并字典的时候。有相同的键,则保留后面字典键对应的值
    dict2 = {0: "lily", "4": "ruby"}
    dict1.update(dict2)  # 保留dict2 的键
    print(dict1)
    
3.5、fromkeys(seq,[])
"""
fromkeys(seq,[])        #[]里可以设定每个键的默认值
#seq是一个序列,dict.fromkeys() 这个函数 会根据这个序列,来形成一个新字典,
会以序列中的元素作为字典的键,可以不赋值,如果没用赋值,则每个键对应的值为None
"""

list = ["alex", "box", "alice", "tom"]

# 创建一个新字典,使用list1的元素作为字典的键
new_dict = dict.fromkeys(list)  # 以列表的每个元素作为字典的键,没用给字典的键赋值,为None(空)
print(new_dict)
{'alex': None, 'box': None, 'alice': None, 'tom': None}

五、集合

  • 集合(set)是一个无序的不重复元素序列。
1、创建
  • 可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

    创建格式:

    parame = {value01,value02,...}
    或者
    set(value)
    
2、定义空数据类型
定义空集合
my_set = set()

#定义空字典
my_dict = dict()
my_dict1 = {}

#定义空元组
my_tuple = tuple ()
my_tuple1 = ()

#定义空列表
my_list = list()
my_list1 = []
3、集合的基本操作
  • 添加元素.add()

    s1.add("James")
    s1.add("Curry")
    s1.add("Young")
    print(s1)  # 集合的元素是无序的,所以每次输出的结果不同
    
  • .update()追加

    tuple = ("Howard", "Westbrook")			#追加元组
    s1.update(tuple)
    print(s1)
    
    tuple2 = {"Anthony", "George"}			#追加集合
    s1.update(tuple2)
    print(s1)
    
    tuple3 = ["Durant", "Paul"]			#追加列表
    s1.update(tuple3)
    print(s1)
    
    tuple4 = {"key": "value", }  		# 如果添加的是字典,则添加的元素是字典的键
    s1.update(tuple4)
    print(s1)
    
    str1 = "Yang"
    s1.update(str1)  # 会将字符串拆分成单个字符,分别添加到集合中
    print(s1)
    
  • .remove()删除

    s1.remove("Y")
    # s1.remove("bo")     #删除不存在的元素会报错
    print(s1)
    
  • .pop()随机删除

    s1.pop()		
    print(s1)
    
  • discard()删除元素

    s1.discard("bo")  # 删除不存在的元素也不会报错
    s1.discard("key")
    print(s1)
    
  • clear()清空集合

    s1.clear()
    print(s1)  # 输出:set()
    
  • 其他操作

    set1 = set()
    set2 = {2, 3, 4, 5, 6}
    set3 = {2, 3, 4, 5, 6}
    print(6 in set1)
    print(6 in set2)
    print(set2 == set3)  # 值相同
    print(set2 is set3)  # 但是内存不相同
    print(id(set2))
    print(id(set3))
    
    False
    True
    True
    False
    2199033381832
    2199033383400
    
4、集合的运算
  • 差集

    """
    #差集,在前一个在前一个集合存在,在后一个集合不存在.difference()
    """
    
    print(set1 - set2)  # 输出set1比set2多那些元素
    # 等价于.difference()
    print(set1.difference(set2))
    
    print(set2 - set1)  # 输出set2比set1多那些元素
    
    print(set2.difference(set1))
    
  • 交集

    """
    #交集 :取两个集合中相同的元素,组成一个新的集合intersection()
    """
    
    set3 = set2 & set1
    print("set2和set1的交集为:{}".format(set3))
    print(set1.intersection(set2))
    
  • 并集

    """
    并集 | .union()
    """
    
    set4 = set1 | set2
    print("set1和set2的并集为:{}".format(set4))
    print(set1.union(set2))
    
  • 对称差集

    """
    对称差集  用两个集合的并集减去他们的交集
    ^
    """
    
    set5 = set1 ^ set2
    print(set5)
    
5、集合内置方法汇总
方法功能
add()为集合添加元素
clear()移除集合中的所有元素
copy()拷贝一个集合
difference()返回多个集合的差集
difference_update()移除集合中的元素,该元素在指定的集合也存在。
discard()删除集合中指定的元素
intersection()返回集合的交集
intersection_update()返回集合的交集。
isdisjoint()判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。
issubset()判断指定集合是否为该方法参数集合的子集。
issuperset()判断该方法的参数集合是否为指定集合的子集
pop()随机移除元素
remove()移除指定元素
symmetric_difference()返回两个集合中不重复的元素集合。
symmetric_difference_update()移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。
union()返回两个集合的并集
update()给集合添加元素
6、可变、不可变及类型转换
  • 不可变类型
  • 可变类型
"""
可变和不可变类型
字典的键 必须是数字、字符串、元组

数字、字符串、元组是不可变类型,当变量的ID不发生改变的时候,他的值是不能变的
列表,字典都是可变的, 当id不发生改变的时候,他的值是可以改变的

字典的键 必须使用不同类型的变量
集合(set)的元素:必须使用不同类型的变量
"""
# 数字类型
x = 1
y = x
print(y)
y = 2
print(x)

print("--------------------")

#列表类型
a = [1, 2, 3, 4, 5, 6]
b = a
print(b)
b.append(777)
print(b)
print(a)

六、常用方法

1、join()用法
  • Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串
#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
str = "-";
seq = ("a", "b", "c"); # 字符串序列
print str.join( seq );

函数

一、函数的定义

所谓函数,就是把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用

函数的调用包括两个步骤:

​ 1.定义函数一一封装 独立的功能

​ 2.调用函数一一享受 封装 的成果

函数的作用,在开发程序时,使用函数可以提高编写的效率以及代码的 重用

二、函数的调用

  • 本地调用

    def multiple_table():  # 使用def(define的缩写)关键字来定义一个函数
        """
        定义一个乘法表函数
        :return:
        """
        for i in range(1, 10):
            for j in range(1, i + 1):
                print(f"{j}*{i}={i * j}", end="\t")
            print(" ")
    
    
    # 在本地调用
    multiple_table()
    
  • 外部调用

    # 导入yang_01_函数这个文件,使用这个文件中的功能
    
    import Day05.yang_01_函数
    Day05.yang_01_函数.multiple_table() # 在yang_01_文件中,调用他的函数
    
    import Day05.yang_04_函数的参数
    
    Day05.yang_04_函数的参数.sum_2_num(1,50)
    

三、函数的参数

1、定义带有参数的函数
def add2num(a, b):
    c = a+b
    print c
2、调用带有参数的函数

以调用上面的add2num(a, b)函数为例:

def add2num(a, b):	# a,b 形参 ,形式上的参数,没有固定的值,用来接受实参的值
    c = a+b
    print c

add2num(11, 22) # 调用带有参数的函数时,需要在小括号中,传递数据

四、函数的嵌套使用

def test1():
    print("*" * 50)
    print("我是test1")
    print("*" * 50)


def test2():
    print("-" * 50)
    print("我是test2")
    test1()  # 调用 test1函数
    print("-" * 50)


test1()
test2()

五、局部变量与全局变量

1、介绍
num = 100  # 全局变量  顶格写 定义的变量就是全局变量


def func():
    num1 = 1000  # 定义在函数内部的变量就是局部变量
    print("使用局部变量 num1--->{}".format(num1))
    print("使用全局变量 num--->{}".format(num))


# 暂时无法在全局去调用函数内部的变量

func()


def func1():
    print("使用全局变量 num--->{}".format(num))

func1()
2、global关键字
num = 100
print("定义完num变量ID为:", id(num))


def func():  # 在func中,修改全局变量的应用,可以使用global关键字进行声明

    global num  # 使用global关键字,之后,在函数内部,就可以修改全局变量的引用
    num = 888  # num被重新赋值只在函数内部生效

    print("局部变量内:", num)
    print("在函数运行过程中num的ID:", id(num))


func()

print("程序执行结束后:", num)
print("程序执行结束后 num 的ID:", id(num))

六、缺省参数

  • 调用函数时,缺省参数的值如果没有传入,则取默认值。
# 如果一个函数,存在多个缺省参数的写法:

def print_info(name, genfer=True, title="班长"):  # 在函数中,定义缺省参数,一定要放到所以参数的最后
    """
    :param name:     姓名
    :param title:    职务
    :param genfer:   性别 True 默认为男,False 为女
    """
    gender_text = "男生"  # 定义新的变量
    gender_1 = "他"
    if not genfer:
        gender_text = "女生"
        gender_1 = "她"

    print(f"{name}的性别是{gender_text},{gender_1}的职务是{title}")


print_info("小明")
print_info("小美", False, "副班长")

七、多值参数

  • 有时可能需要一个函数能处理比当初声明时更多的参数, 这些参数叫做不定长参数,声明时不会命名。
"""
函数参数的数量不固定
参数名前增加 一个 * 可以接收 元组
参数名前增加 两个 * 可以接收 字典
"""


# 定义一个函数,这个函数处理接受的第一个数字,后面的内容存储为元组,字典
def func(num, num1, *args, **kwargs):
    print(f"我接受到的第一个值为:{num}")
    print(f"我接受到的第二个值为:{num1}")
    print(f"后续接收的是:{args}")  # 装包
    print(f"后续接受的内容是:{kwargs}")  # 拆包


func(1, 2, 3, 4, 5, 6, 7, 8, name="杨宇波", age=22, gender=True)

八、递归函数

  • 函数调用自身编程技巧 称为 递归
  • 特点:l一个函数 内部 调用自己
"""
1.定义一个函数 sum_numbers
2.能够接收一个 num 的整形参数
3.计算 1+2+…+n的结果

分析:我们传入的 num 是 n 实际计算的是 n!
"""


def sum_numbers(num):
    # 出口是1
    if num == 1:
        return 1

    result = sum_numbers(num - 1)
    return  num + result

sum1 = sum_numbers(10)
print(sum1)

九、内部函数

1、函数的嵌套
  • 在一个函数当中,调用其他函数
  • 在一个函数当中,调用自身
  • 在一个函数当中,定义一个函数(内部函数)
2、内部函数的特点
  • 可以访问外部函数的变量
  • 内部函数可以修改外部函数的可变类型的变量 比如:list1
  • 函数内部修改全局变量,要加global 变量名,内部函数要修改外部函数的不可变类型的变量的时候要加nonlocal在函数内部,要想修改全局变量的值,使用 global
  • locals() 查看本地变量有哪些,以字典的形式输出
  • globals() 查看全局变量有哪些,以字典的形式输出()

十、闭包

# 闭包基于函数内部的形式
# 要想单纯的在 全局 调用内部函数:
def outside():
    num_1 = 100

    def inside():
        print("我是内部函数,调用了外部函数的变量", num_1)

    return inside  # 不带括号

    # 我想把 print(num_1) 表现出来,怎么办?  也就是在全局下调用inside()


# print(outside())
var = outside()  # var = inside  var()=inside()
# inside函数的地址是<function outside.<locals>.inside at 0x00000274B3931948>
var()

十一、装饰器

  • 也叫 语法糖@ (糖衣语法)

  • 在闭包的基础上做的升级,遵循如下规则:

    • 函数A作为参数出现,函数B接收函数A作为参数
    • 要有闭包的特点
    • 不影响原有函数的功能,还能添加新的功能
"""
# 装饰器  也叫  语法糖@ (糖衣语法)
在闭包的基础上做的升级,遵循如下规则:

1.函数A作为参数出现,函数B接收函数A作为参数
2.要有闭包的特点
3.不影响原有函数的功能,还能添加新的功能

"""


# 符合闭包的特点
def func_b(arg_1):
    print("我是函数B!,是一个外部函数!")

    def inner_func():
        print("我是函数B的内部函数!")
        return arg_1()

    return inner_func


@func_b  # 用func_b装饰func_a,其实是将未装饰的函数作为参数传递给闭包的外部,现在再执行 func_b
def func_a():
    print("我是函数A!~~")


func_a()

"""
等价于
def func_a():
    print("我是函数A!~~")
var = func_b(func_a)
var()    

"""

十二 、匿名参数

Python 使用 lambda 来创建匿名函数。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
"""
不再使用def来定义函数,而是使用lambda
格式 : lambda 参数1,参数2,……;  运算

"""

# 正常定义函数
def func_name():
    pass

# 匿名函数--->不需要考虑函数的命名

def add(a, b):
    result = a + b
    return result

var1 = add(1, 2)
print(var1)

# 相当于定义了add()函数
var2 = lambda a, b: a + b
# print(var2)  # 返回的是var2的地址

var3 = lambda a, b: print(a + b)  # a和b是参数。print(a+b)是返回值  var3 来接受返回值
var3(1, 5)  # 通过var3来传递参数

十三、推导式

Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。

Python 支持各种数据结构的推导式:

  • 列表(list)推导式
  • 字典(dict)推导式
  • 集合(set)推导式
  • 元组(tuple)推导式
1、列表推导式
  • 格式

    • """
      通过旧的列表利用推导式生成新的列表
      格式:
       [ 表达式 for 变量 in 旧列表]
       或者  [ 表达式 for 变量 in 旧列表 if 条件]
      """
      
      names = ["James", "Curry", "Young", "Kuzma", "y", "b"]
      
      # 用name来生成一个新列表,它的条件是 先遍历naems列表,拿取字符串长度大于3的元素
      new_names = [name for name in names if len(name) > 3]
      print(new_names)
      
      # name for name in names  for循环遍历names列表
      new_names = []
      
      """
      for name in names:
          if len(name) > 3:
              new_names.append(name)
      """
      
2、集合推导式
  • 格式

    • """
      类似于列表推导式,在列表推导式的基础上增加了一个去重复的功能
      
      """
      lis1 = [1, 2, 3, 4, 62, 2, 1, 3]
      
      new_lis1 = {x for x in lis1}
      print(new_lis1)
      
      # 添加条件,最小于5的元素进行+1操作
      new_lis2 = {i + 1 for i in new_lis1 if i < 5}
      print(new_lis2)
      
3、字典推导式
  • 格式

    • """
      # 案例:
      需求:对字典的key 和 value 进行交换
      """
      # 定义的一个字典
      dict1 = {'a': 'A', 'b': 'B', 'c': 'C'}
      
      dict2 = {value: key for key, value in dict1.items()}
      print(dict2)
      
      # dict1.items() 字典解封装
      
      print(dict1.items())  # 数据类型是: dict_items
      # dict_items([('a', 'A'), ('b', 'B'), ('c', 'C')])
      
      for i in dict1:
          print(i)
      

十四、生成式

# 将 1-20的数字 进行 *3的操作

new_list = [i * 3 for i in range(5)]
print(new_list)  # [0, 3, 6, 9, 12]

"""
当我们再 调用 new_list的时候,实际上 ,再内存中,会先创建该列表,
如果打印或者遍历列表, 再从这个内存中取 取值,进行相对于的操作

如果一个列表 有 100万个元素,只需要 对前10个元素进行操作, 是否也需要给 100万个元素的列表 开空间?
"""

# 需求 只取 new_list 的前 3 个值

var = new_list.__iter__()  # 迭代器
print(var)  # <list_iterator object at 0x000001265CED96F0>
print(var.__next__())  # 0
print(var.__next__())  # 3
print(var.__next__())  # 6
print(next(var))  # var.__next__() 等价于 next(var)
print(next(var))

"""
如果 使用 迭代器的次数 ,大于了 集合元素的个数, 系统报错: StopIteration
"""

面向对象

一、面和对象简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
  • **方法:**类中定义的函数。

二、类和对象的关系

  • 类是模板对象 是根据 这个模板创建出来的,应该 先有类,再有对象

  • 只有一个,而 对象 可以有很多个

  • 不同的对象 之间 属性 可能会各不相同

  • 中定义了什么 属性和方法,对象 中就有什么属性和方法,不可能多,也不可能少

三、语法

class Leiming:  # 类名  大驼峰
    # 创建对象的时候,程序会自动调用 new 和 init
    # def __init__(self):  # 程序自动执行,暂时先不要修改
    #     pass             # 给对象开辟空间
    
    
    def __init__(self,shuxing):  # 给对象 定义属性
        self.shuxing = shuxing
    
    
    def method(self):  # 方法 和 函数很像,多了一个 self 参数
        pass


# 根据类创建对象
obj1 = Leiming("属性1")  
obj1.method()  # 对象可以调用方法
print(obj1.shuxing)  # 对象可以访问属性
class MyClass:
    """一个简单的类实例"""
    i = 12345
    def f(self):
        return 'hello world'
 
# 实例化类
x = MyClass()
 
# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f())

四、构造方法

1、概念

Python 中的 init()方法,是一个特殊的类实例方法,称为构造方法、构造函数或构造器,英文为 Constructor。

仅包含 self 参数的 init(self) 构造方法,又称为类的默认构造方法。

构造方法最大的用处就是在创建对象时执行初始化,当创建一个对象时,系统会为这个对象的实例进行默认的初始化。

在 Python 类中,如果不手动为类添加任何构造方法,Python 会自动为类添加一个仅包含 self 参数的构造方法。

2、实例
class Complex:
    def __init__(self, realpart, imagpart):
        self.r = realpart
        self.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i)   # 输出结果:3.0 -4.5

五、继承

  • 在程序中,继承描述的是多个类之间的所属关系。
  • 如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。
  • 那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。
# 父类
class A(object):
    def __init__(self):
        self.num = 10

    def print_num(self):
        print(self.num + 10)
# 子类
class B(A):
    pass


b = B()
print(b.num) 
b.print_num()
1、单继承
  • 子类在继承的时候,在定义类时,小括号()中为父类的名字
  • 父类的属性、方法,会被继承给子类
# 定义一个Master类
class Master(object):
    def __init__(self):
        # 属性
        self.kongfu = "古法煎饼果子配方" 

    # 实例方法
    def make_cake(self):
        print("按照 <%s> 制作了一份煎饼果子..." % self.kongfu)


# 定义Prentice类,继承了 Master,则Prentice是子类,Master是父类。
class Prentice(Master): 
    # 子类可以继承父类所有的属性和方法,哪怕子类没有自己的属性和方法,也可以使用父类的属性和方法。
    pass                

# laoli = Master()
# print(laoli.kongfu)
# laoli.make_cake()

damao = Prentice()  # 创建子类实例对象
print(damao.kongfu) # 子类对象可以直接使用父类的属性
damao.make_cake()   # 子类对象可以直接使用父类的方法
  • 虽然子类没有定义__init__方法初始化属性,也没有定义实例方法,但是父类有。所以只要创建子类的对象,就默认执行了那个继承过来的__init__方法
2、多继承
  • 多继承可以继承多个父类,也继承了所有父类的属性和方法
  • 注意:如果多个父类中有同名的 属性和方法,则默认使用第一个父类的属性和方法(根据类的魔法属性mro的顺序来查找)
  • 多个父类中,不重名的属性和方法,不会有任何影响。
# 父类1
class Base1:
    def demo1(self):
        print("我是Base1的demo1方法")


# 父类2
class Base2:
    def demo2(self):
        print("我是Base2的demo2方法")


# 子类继承父类
class Derived(Base1, Base2):  # 重名的话,谁写在()前,先调用谁
    def test(self):
        self.demo1()
        self.demo2()


obj = Derived()
obj.demo1()
obj.demo2()

print(Derived.__mro__)  #查看Derived类的调用方法或者访问属性的顺序

"""
(<class '__main__.Derived'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>)
object  如果按照查找顺序路都找不到,最后回在object类中进行查找,如果最后object也没有该方法或者属性,就会报错

object是所以类的父类
"""
3、方法的重写
class Animal:
    def __init__(self):
        self.color = "grey"

    def eat(self):
        print("站起来吃")

    def drink(self):
        print("drink")

    def run(self):
        print("run")

    def sleep(self):
        print("sleep")


class Dog(Animal):

    def eat(self):  # 虽然父类有eat方法,但是有所不同,所以需要重写

        """
        重写父类方法:
            1、完全覆盖父类方法,只保留父类方法的名字
            2、在父类方法的基础上,对该方法进行拓展,会保留父类方法的功能
        """


        super().eat()  # super().的方式,保留父类方法的功能,对父类方法进行拓展

        print("狗狗用盆吃")
    def bark(self):
        print("汪汪汪~")


wangcai = Dog()
wangcai.eat()
wangcai.bark()

六、私有属性和私有方法

私有权限:在属性名和方法名 前面 加上两个下划线 __
  1. 类的私有属性 和 私有方法,都不能通过对象直接访问,但是可以在本类内部访问;
  2. 类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问;
  3. 私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。

七、类的属性

  • 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性
"""
定义一个 工具类
每件工具都有自己的 name 实例属性
需求 -- 知道使用这个类,创建了多少个工具对象 类属性

"""


class Tools(object):
    count = 0  # 类属性,用来描述 这个类 创建了多少个 实例

    def __init__(self, name):  # 初始化方法,是用来给对象(实例赋予属性值的)
        self.name = name  # 实例属性

        # 通过这个类创建了 多少个 对象 ,做一个计数  count
        # 思路: 每创建一个对象,就会调用一次 __init__(self) 方法 ,每调用一次 __init__ ,就对 count做一个 +1 的操作
        Tools.count += 1


tool1 = Tools("手电筒")  # 创建实例
tool2 = Tools("扳手")
tool3 = Tools("菜刀")

print(Tools.count)  # 输出  通过类创建的对象数
print(tool1.count)  # 注意: count属性,是 Tools 这个类的,但是 可以被实例访问
print(id(tool1.count), id(Tools.count))  # 1759695208752 1759695208752

tool1.count = 100  # 该定义方式,只是给 tool1 增加了一个属性 count,增加了一个 tool1.count的内存空间
# 而不会改变 类属性的值

print(id(tool1.count), id(Tools.count))  # 1759695211856 1759695208752

print(Tools.count)  # --->3

八、类的方法

  • 是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以’cls’作为第一个参数的名字,就最好用’cls’了),能够通过实例对象和类对象去访问。
# 类属性 是用来描述 类对象  的属性
# 类方法  描述 类的 方法
"""
在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法
"""
"""
需求:
定义一个 工具类
每件工具都有自己的 name
需求 – 在 类 封装一个 show_tool_count 的类方法,输出使用当前这个类,创建的对象个数
"""


class Tools(object):
    count = 0

    def __init__(self, name):
        self.name = name
        Tools.count += 1

    # 创建类方法
    @classmethod
    def show_tool_count(cls):
        print(f"目前创建了 {cls.count}个 工具实例了!")  # 类方法内部,访问了类属性,也可以调用其他类方法
        # print(self.name)  # 类方法内部,不能访问 实例属性,也不能调用实例方法


tool1 = Tools("James")
tool2 = Tools("Curry")

Tools.show_tool_count()

九、静态方法

  • 需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数,可以通过对象和类来访问。
class Dog:
    def __init__(self):
        self.name = "旺财"

    @staticmethod
    def run():
        """
        定义了一个 静态方法  静态方法不需要访问实例属性 也不需要 调用实例方法
                            静态方法不需要访问类属性 也不需要 调用类方法
        """
        print(f"James")


James = Dog()  # 根据类创建实例
James.run()

十、单例设计模式

1、设计模式
  • 设计模式前人工作的总结和提炼,通常,被人们广泛流传的设计都是针对 某一特定问题 的成熟的方案
  • 使用 设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
2、单例 设计模式
  • 目的 — 让 创建的对象,在系统中 只有 唯一的一个实例
  • 每一次执行 类名( ) 返回的对象,内存地址是相同的
class MusicPlayer(object):
    instance = None  # instance设置为初始值 None,如果 创建过对象,
    # 也就是 调用过 new方法了, instance 的值就不是 None了

    init_flag = False  # 定义一个初始值,用于标记 __init__方法,没有被再次执行

    def __new__(cls, *args, **kwargs):  # 重写__new__方法
        if cls.instance is None:  # 如果 之前没有执行过 new方法,则 cls.instance is None
            cls.instance = super().__new__(cls)  # 将 内存id 赋值给 cls.instance
        return cls.instance  # 重写 new方法后,将 内存 id 返回

    def __init__(self):
        if MusicPlayer.init_flag == True:
            return
        print("播放器初始化")
        MusicPlayer.init_flag = True


player1 = MusicPlayer()
player2 = MusicPlayer()
print(id(player1))  # 多个实例  2918561262816引用 是通过 __new__返回的
print(id(player2))

模块和包

  • 模块就好比是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块

一、import

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

    import module1,mudule2...
  • 如果想一次性引入math中所有的东西,还可以通过from math import *来实现

as

import Day09.yang_测试模块_01 as Dog_module  # 用于当前文件中,简写
import Day09.yang_测试模块_02 as Cat_module

# 调用模块1的工具
print(Dog_module)
Dog_module.say_hello()
dog = Dog_module.Dog()
dog.james()

cat = Cat_module.Cat()
print(cat)

二、from…import

Python的from语句让你从模块中导入一个指定的部分到当前命名空间中

语法如下:

    from modname import name1[, name2[, ... nameN]]
# import Day09.yang_测试模块_01 as Dog_module  # 用于当前文件中,简写
# import Day09.yang_测试模块_02 as Cat_module

from Day09.yang_测试模块_01 import Dog  # 仅导入yang_测试模块_01中的Dog类

# 如果多个模块之间,存在同名的工具,后导入的,会覆盖掉先导入的。为了防止这种现象,可以使用as方法
from Day09.yang_测试模块_01 import say_hello as Dog_say_hello
from Day09.yang_测试模块_02 import say_hello


# 调用模块1的工具
dog = Dog()  # 此时,不需要带模块名
print(dog)

Dog_say_hello()
say_hello()

三、from … import *

把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

    from modname import *
注意
  • 这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

四、包

1、概念
  • 包 是一个 包含多个模块 的 特殊目录

  • 目录下有一个 特殊的文件 init . py

  • 包名的 命名方式 和变量名一致,小写字母 + _

2、优点

使用import包名,可以一次性的导入包中的所有模块

3、总结
  • 包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为
  • 有效避免模块名称冲突问题,让应用组织结构更加清晰

异常

1、捕获异常 try…except…

try:
    num = int(input("请输入一个数字:"))
    result = 8 / num
    print(f"您输入的数字为{result}")

except ValueError:  # 开发者预测到的错误类型1
    print("您输入的不是数字!")

except ZeroDivisionError:
    print("被除数不能为0")

except Exception as e:  # Exception类,包含着系统中定义的各种错误
    # e 可以认为是Exception类的一个实例(可以自己定义)
    # python 2.x except Exception , e
    print(f"发生了以下错误:{e}")
2、else、finall

咱们应该对else并不陌生,在if中,它的作用是当条件不满足时执行的实行;同样在try…except…中也是如此,即如果没有捕获到异常,那么就执行else中的事情

try…finally…语句用来表达这样的情况:

在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。 比如文件关闭,释放锁,把数据库连接返还给连接池等

try:
    num = int(input("请输入一个数字:"))
    result = 8 / num
    print(f"结果为:{result}")

except ValueError:  # 开发者预测到的错误类型1
    print("您输入的不是数字!")

except ZeroDivisionError:
    print("被除数不能为0")

except Exception as e:  # Exception类,包含着系统中定义的各种错误
    # e 可以认为是Exception类的一个实例(可以自己定义)
    # python 2.x except Exception , e
    print(f"发生了以下错误:{e}")

else:
    print("不抛出异常会执行的代码!")

finally:
    print("无论是否抛异常,都会执行的代码!")

文件操作

一、open()方法

1、基础介绍

Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。

**注意:**使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。

open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。

open(file, mode='r')

完整的语法格式为:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
2、参数说明
  • file: 必需,文件路径(相对或者绝对路径)。
  • mode: 可选,文件打开模式
  • buffering: 设置缓冲
  • encoding: 一般使用utf8
  • errors: 报错级别
  • newline: 区分换行符
  • closefd: 传入的file参数类型
  • opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
3、mode模式
模式描述
t文本模式 (默认)。
x写模式,新建一个文件,如果该文件已存在则会报错。
b二进制模式。
+打开一个文件进行更新(可读可写)。
U通用换行模式(Python 3 不支持)。
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+打开一个文件用于读写。文件指针将会放在文件的开头。
rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
  • 默认为文本模式,如果要以二进制模式打开,加上 b
4、实例
"""
r  只读
w  只写  不能读
a  追加  不能读
# r+  读写,写操作,不覆盖源文本
# w+  读写,最开始操作的时候会将文件覆盖,然后才能进行读和写的操作
      如果在 w+ 的模式下,进行read()操作,则返回字符串的长度

# a+  读写,指针会放到文件末尾,执行write()操作,会在文本末尾继续写,读取不到内容,
"""

recv = open("readme", "r", encoding='utf-8')  # 返回一个对象,也叫一个句柄
'''
已只读的形式打开readme文件,文本编码格式是UTF-8
'''

# 对句柄进行操作
print(recv.read())

text = recv.read()
print(text)

# 完成操作之后,要关闭文件句柄,从内存中将句柄删除
recv.close()  # 容易忘记执行关闭的操作
5、复制文件
with open("readme", encoding='utf-8') as  recv:
    text=recv.read()
    with open('readme_副本',"w",encoding='utf-8') as recv_01:
        recv_01.write(text)
6、.readlines()方法
with open("readme", encoding='utf-8') as recv:
    # .readlines()方法,读取全部内容,在读取的过程中,将每一个行作为一个元素,存储到列表中
    content = recv.readlines()

    with open("readme_副本02", "w", encoding='utf-8') as recv2:
        for item in content:
            recv2.write(item)

正则表达式

在这里插入图片描述

一、正则匹配的方法

  • match 匹配 : 要从字符串开头去匹配,如果不匹配,返回None(只返回一个)
  • search匹配 : 查找字符串,如果有符合条件的字符串,返回结果(只返回一个)
  • findall匹配 : 匹配整个字符串,一直找到字符串结尾,返回结果,不返回字符串的位置(可以返回多个)

二、正则匹配的规则

[] 表示一个字符位
    \w : 数字和字母
    \s : 空格 space
    \b : 表示边界 boundary
    \d : 数字 digital
+ 表示匹配一次或者多次,如果是多次的话,则全部匹配出来
? 匹配0次或1次
* 匹配0次或多次
{x}   用于验证将前面的模式匹配m次
{x,}  用于匹配x次或者多次,如果是多次的话全部匹配出来
{x,y} 匹配从x次到y次  >=m,<=n 
$  用于结尾
^  用于匹配字符串的开头,match自动使用这种方法

三、正则的分组

import re

# 匹配数字 0 到 100
# 5 50 100
# 第一位不能是0  第二位0-9 只有100才会有第三位,如果取值为0也符合

num = "100"
result = re.match("[1-9]?[0-9]?$ |100$", num)  # 只能匹配0-99
print(result)

# 验证邮箱
# @前面字符 5-20位
email = "1532889973@qq.com"
result1 = re.match("\w{5,20}@(qq|163|126)\.(com|net|cn)$", email)
print(result1)

# 电话号码 带区号,分别提取区号和电话号码----> 分组
# 021-20703917
phone = '021-20703917'
result2 = re.match("(\d{3,4})-(\d{7,8}$)", phone)
print(result2)
print(result2.group(1))
print(result2.group(2))
print(result2.groups())  # 每个组都提取出来,生成一个元组

# 提取标签里面的内容
html = '<html>ab@c</html>'

# \1 表示group1
result3 = re.match(r'<([\w]+)>(.+)<(/\1)>', html)
print(result3)
print(result3.group(1))

# 多个标签
html1 = "<html><h1>hello</h1></html>"
result4 = re.match(r'<(\w+)><(\w+)>(.+)</\2></\1>', html1)
print(result4.groups())

四、sub和split

# sub  替换, 将符合规则的字符串 替换成 指定字符串
import re

msg = "java:99,python:0,C:59"
result = re.sub(r"\d+", "90", msg)
print(result)

# split 切割  如果遇到符合规则的字符串,进行切割,将结果保存到列表
msg1 = "java:99,python:0,C:59"
result = re.split(r"[:,]", msg1)
print(result)

五、贪婪和非贪婪

# 贪婪和非贪婪
import re

msg = 'abc123124312abc'
result = re.match(r'abc\d??',msg)  # "+" 用于将前面的模式匹配1次或多次(贪婪模式)
result1 = re.match(r'abc\d{4,8}',msg)
result2 = re.match(r'abc\d{4,8}?',msg)
#+个? 代表非贪婪模式
print(result)
print(result1)
print(result2)

Socket 模块

一、简介

  • Socket模块的主要目的是帮助在网络上的两个程序之间建立信息通道。

  • 在Python中提供了两个基本的Socket模块:

    • 服务端Socket
    • 客户端Socket
  • 当创建了一个 服务端Socket 之后,这个Socket就会在本机的一个端口上 等待连接

  • 客户端Socket访问 这个端口,当两者完成连接之后,就可以进行交互了。

二、实例化Socket类

  • 在使用Socket进行编程的时候,需要:首先 实例化一个Socket类 ,

  • 这个实例化需要三个参数:

    • 第一个参数是地址族
    • 第二个参数是(TCP/UDP)
    • 第三个参数是使用的协议
socket(family,type[,protocal])

三、family

  • 要使用的地址族

    • 常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX、UNIX域Socket)、AF_ROUTE等。

      默认值为socket.AF_INET,通常使用这个默认值即可。

四、type

  • 用来指明Socket类型
    • SOCK_STREAM,这是TCP类型,保证数据顺序及可靠性;(默认
      • TCP流控机制:平滑增长
    • SOCK_DGRAM,用于UDP类型
    • SOCK_RAW,这是原始类型,允许对底层协议如IP或ICMP进行直接访问,基本不会用到

五、默认参数

s = socket.socket()

# 等价于

socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 初始化UDP类型的Socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

六、服务端函数

1、bind()
  • 这个函数由服务端Socket调用,会将之前创建Socket与指定的IP地址和端口进行绑定。如果之前使用了AF_INET初始化Socket,那么这里可以使用元组(host,port)的形式表示地址。

  • s.bind(('127.0.0.1',2345))
    
2、listen()
  • 这个函数用于在使用TCP的服务端 开启 监听模式

  • 可以使用一个参数来指定可以挂起的最大连接数量。

    这个参数的值最小为1,一般设置为5。例如,要在服务端开启一个监听,可以使用如下语句。
    
    s.listen(5)
    
3、accept()
  • 这个函数用于在使用TCP的 服务端 接收连接,一般是阻塞态。
  • 接受TCP连接并返回(conn,address)
  • 其中,conn是新的套接字对象,可以用来接收和发送数据;address是连接客户端的地址。
4、实验
# s = socket.socket()
import socket  # 导入模块

s1 = socket.socket()  # 实例化
s1.bind(("127.0.0.1", 2345))  # 绑定开启的服务器的IP地址和端口号。注意: bind()方法的参数是元组的形式
s1.listen(5)  # 开启侦听可以连接端口号的最大数

"""
开启侦听之后,不断地等待用户连接,并向客户端发送数据
"""
while 1:
    conn, address = s1.accept()  # 等待客户端的连接
    print("a new connect from", address)  # 检测到有人连接打印"a new connect from"
    """
    方法一:
        conn.sendall(b"Hello Yang")
        b 是将"Hello Yang"转换为字节
        
    data = conn.recv(65535)  #表示服务器能接受的最大数据是65535个字符
    """
    conn.sendall(b"Hello Yang")  # 给客户端发送"Hello Yang"
    conn.close()  # 数据发送完毕,关闭socket

七、客户端函数

1、connect()
  • 这个函数用于在使用TCP的 客户端去连接服务端 时使用,使用的参数是一个元组,形式为(hostname,port)。

  • 例如,在客户端程序初始化了一个Socket之后,就可以使用这个函数去连接到服务端。要连接本机的2345端口,可以使用如下语句。
    s.connect(("127.0.0.1",2345))
    

八、服务端和客户端都可以使用的函数

1、send()

用于在使用 TCP 时发送数据,完整的形式为 send(string[,flag]),

利用这个函数可以将string代表的数据发送到已经连接的Socket,返回值是发送字节的数量

但是可能未将指定的内容全部发送。

2、sendall()

与send()相类似,也是用于在使用TCP时发送数据,完整的形式为 sendall(string[,flag])

与send()的区别是完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

例如,使用这个函数发送一段字符到Socket,可以使用如下语句。

 s.sendall(bytes("Hello,My Friend!",encoding="utf-8"))
3、recv()

这个函数用于在使用TCP时接收数据,完整的形式为 recv(bufsize[,flag])

接收Socket的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量,flag这个参数一般不会使用。

例如,通过这个函数接收一段长度为1024的字符Socket,可以使用如下语句。    
   obj.recv(1024)
4、sendto()

这个函数用于在使用UDP时发送数据,完整的形式为

 sendto(string[,flag],address),

返回值是发送的字节数。address是形式为(ipaddr,port)的元组,指定远程地址。

5、recvfrom()

UDP专用,接收数据,返回数据远端的IP地址和端口,但返回值是(data,address)。其中,data是包含接收数据的字符串,address是发送数据的套接字地址。

6、close()

关闭socket。

7、实验
import socket

s2 = socket.socket()
s2.connect(("127.0.0.1", 2345))
data = s2.recv(1024)
s2.close()
"""
方法二:
    data.decode('utf-8') ----> 解码
    
"""

"""
Return the canonical string representation of the object.
返回对象的规范字符串表示形式
"""

print("Received", repr(data.decode('utf-8')))

Nmap模块

一、功能

  • 主机发现功能。向目标计算机发送信息,然后根据目标的反应来确定它是否处于开机并联网的状态。

    • 如果开启防火墙可能导致ping失败,此时可借助端口扫描
  • 端口扫描。向目标计算机的指定端口发送信息,然后根据目标端口的反应来判断它是否开放。

  • 服务及版本检测。向目标计算机的目标端口发送特制的信息,然后根据目标的反应来检测它运行服务的服务类型和版本。

  • 操作系统检测。

二、Python-nmap

1、简介
  • python-nmap是一个可以帮助使用 Nmap功能的 Python 模块文件

  • 在python-nmap模块的帮助下,可以轻松地在自己的程序中使用Nmap扫描的结果,也可以编写程序自动化地完成扫描任务。

  • 模块的作者的个人网站为http://xael.org/。

2、安装
sudo apt-get install nmap
sudo pip install python-nmap
3、基本用法

python-nmap模块的核心就是

  • PortScanner(同步):发送一次请求,收到回复后才会发送下一次请求
  • PortScannerAsync(异步):一次性发出请求,等待回复
  • PortScannerError
  • PortScannerHostDict
  • PortScannerYield等
4、PortScanner

实例化

nmap.PortScanner()
5、PortScannerAsync

实例化

nmap.PortScannerAsync()

三、Python-nmap中的函数

1、Scan()

这个函数的完整形式为

scan(self, hosts='127.0.0.1', ports=None, arguments='-sV',sudo=False)
	用来对指定目标进行扫描,其中需要设置的三个参数包括hosts、ports和arguments。

	参数hosts的值为字符串类型,表示要扫描的主机,形式可以是IP地址,例如“192.168.1.1”,也可以是一个域名,例如“www.nmap.org”。

	参数ports的值也是字符串类型,表示要扫描的端口。如果要扫描的是单一端口,形式可以为“80”。如果要扫描的是多个端口,可以用逗号分隔开,形式	为“80,443,8080”。如果要扫描的是连续的端口范围,可以用横线,形式为“1-1000”。

参数arguments的值也是字符串类型,这个参数实际上就是Nmap扫描时所使用的参数,
	如“-sP”“-PR”“-sS”“-sT”“-O”“-sV”等。
        “-sP”表示对目标进行Ping主机在线扫描,
        “-PR”表示对目标进行一个ARP的主机在线扫描,
        “-sS”表示对目标进行一个TCP半开(SYN)类型的端口扫描,
        “-sT”表示对目标进行一个TCP全开类型的端口扫描,
        “-O”表示扫描目标的操作系统类型,
        “-sV”表示扫描目标上所安装网络服务软件的版本。
  • 半开连接:只发送两次握手

  • 全开链接:发送三次握手

  • 实例

    # 如果要对192.168.1.101的1~500端口进行一次TCP半开扫描,可以使用如图所示的命令
    	nm.scan("127.0.0.1","1-10000","-sS")
    
    import nmap
    
    nm = nmap.PortScanner()
    nm.scan("127.0.0.1","1-10000","-sS")
    result = nm.all_hosts()
    print(result)
    
    
    #扫描一个网段的主机(同步,时间较久)
    nm.scan("192.168.43.0/24")
    >>> import nmap
    >>> nm = nmap.PortScanner()
    >>> nm.scan("192.168.1.0/24")
    
    
    # all_hosts()函数:返回一个被扫描的所有主机列表
    
4、command_line()函数
  • 返回在当前扫描中使用的命令行
>>> import nmap
>>> nm  = nmap.PortScanner()
>>> nm.scan("192.168.1.4","1-500","-sS")
{'nmap': {'command_line': 'nmap -oX - -p 1-500 -sS 192.168.1.4', 'scaninfo': {'tcp': {'method': 'syn', 'services': '1-500'}}, 'scanstats': {'timestr': 'Sun Apr 24 20:33:34 2022', 'elapsed': '0.14', 'uphosts': '1', 'downhosts': '0', 'totalhosts': '1'}}, 'scan': {'192.168.1.4': {'hostnames': [{'name': '', 'type': ''}], 'addresses': {'ipv4': '192.168.1.4'}, 'vendor': {}, 'status': {'state': 'up', 'reason': 'localhost-response'}}}}

>>> nm.all_hosts()		# 返回一个被扫描的所有主机列表
['192.168.1.4']

>>> nm.command_line()
'nmap -oX - -p 1-500 -sS 192.168.1.4'		#返回在当前扫描中使用的命令行
5、csv()函数
  • 返回值是一个CSV(逗号分隔值文件格式)的输出,如图所示。显示一个比较工整的扫描结果
>>> nm.csv()
'host;hostname;hostname_type;protocol;port;name;state;product;extrainfo;reason;version;conf;cpe\r\n'

>>> print(nm.csv())
host;hostname;hostname_type;protocol;port;name;state;product;extrainfo;reason;version;conf;cpe
6、has_host(self, host)函数
  • 检查是否有host的扫描结果,如果有则返回True,否则返回False
7、scaninfo()函数
  • 列出一个扫描信息的结构
>>> nm.scaninfo()
{'tcp': {'method': 'syn', 'services': '1-500'}}

image-20220424205001763

nm["192.168.1.4"]["tcp"][67]		#查看67端口是否开启

四、异步类的函数

PortScannerAsync类中最为重要的函数也是scan(),

用法与PortScanner类中的scan()基本一样,但是多了一个回调函数

完整的scan()函数格式为:

 scan(self, hosts='127.0.0.1',ports=None, arguments='-sV', callback=None, sudo=False)

这里面的callback是以(host, scan_data)为参数的函数
1、scan()
>>> import nmap
>>> nma = nmap.PortScannerAsync()
>>> nma.scan(hosts="192.168.1.0/24",arguments="-sP")
2、still_scanning()
  • 如果扫描正在进行,则返回True,否则返回False
>>> nma.still_scanning()
True
3、stop()
  • 停止当前扫描
>>> nma.stop()
>>> nma.still_scanning()
False
4、wait(self, timeout=None)
  • 函数表示等待时间
#不管有没有扫到,2s扫描一个地址
>>> nma.wait(2)

五、nmap来编写扫描器

1、实验需求
  • 编写一个简单的端口扫描器。扫描192.168.1.121 开放从1~1000的哪些端口,这里先使用命令行来完成这个程序。
2、代码
import nmap

nm = nmap.PortScanner()
nm.scan('192.168.184.0/24', '1-1000')

# 获取该网段的主机IP地址   IP地址的列表
ip_list = nm.all_hosts()  # 返回一个被扫描的所有主机列表
print(nm)
for host in ip_list:
    print('-' * 88)
    print(f"Host:{host}({nm[host].hostname()})")  # 打印IP地址和host-name
    print(f"Start:{nm[host].state()}")		# 获取主机的状态A

    #  从获取到的一台主机当中,获取主机的端口号
    print('-' * 88)
    for protocol in nm[host].all_protocols():
        print(f'Protocol:{protocol}')
        l_port = nm[host][protocol].keys()


        for port  in l_port:        #遍历主机的端口列表
            print(f"port:{port}\t"
                  f"start:{nm[host][protocol][port]['starte']}")

Scapy模块文件

一、简介

  • Scapy是一个由Python语言编写的强大工具
  • 也可以在自己的程序中使用这个模块来实现对网络数据包的发送、监听和解析
  • 这个模块相比起Nmap来说,更为底层。可以更为直观地了解到网络中的各种扫描和攻击行为
  • l如果想对网络中的各种问题进行深入研究,Scapy无疑是一个更好的选择,可以利用它来产生各种类型的数据包并发送出去,Scapy也只会把收到的数据包展示给你,而并不会告诉你这意味着什么,一切都将由你来判断。

二、Scanpy的基本操作

  • 首先使用几个实例来演示一下Scapy的用法,在Scapy中每一个协议就是一个类只需要实例化一个协议类,就可以创建一个该协议的数据包
#如果要创建一个IP类型的数据包,就可以使用如下命令。
  ip = IP() 
  • IP数据包最重要的属性就是源地址目的地址这两个属性可以使用src和dst来设置
#例如,要构造一个发往“192.168.1.107”的数据包,可以这么写。
  ip = IP(dst="192.168.1.107")
    
>>> ip = IP(dst='192.168.1.100')
>>> ip
<IP  dst=192.168.1.100 |>
  • 这个目标dst值可以是一个IP地址,也可以是一个网段,例如192.168.1.0/24,这时产生的就不是一个数据包,而是256个数据包
>>> ip = IP(dst='192.168.1.0/24')
>>> ip
<IP  dst=Net('192.168.1.0/24') |>
  • 查看其中的每个数据包
[p for p in ip]		# 列表推导式
>>> [p for p in ip]
[<IP  dst=192.168.1.0 |>,
 <IP  dst=192.168.1.1 |>,
 <IP  dst=192.168.1.2 |>,
 <IP  dst=192.168.1.3 |>,
 <IP  dst=192.168.1.4 |>,
 <IP  dst=192.168.1.5 |>,
 <IP  dst=192.168.1.6 |>,
 <IP  dst=192.168.1.7 |>,
 <IP  dst=192.168.1.8 |>,
 <IP  dst=192.168.1.9 |>,
……………………………………………………………………
 <IP  dst=192.168.1.253 |>,
 <IP  dst=192.168.1.254 |>,
 <IP  dst=192.168.1.255 |>]

三、构造数据包

1、Scapy采用分层的形式来构造数据包
  • 通常最下面的一个协议为Ether,然后是IP,再之后是TCP或者是UDP。

  • IP()函数无法用来构造ARP请求和应答数据包,可以使用Ether(),

  • 这个函数可以设置发送方和接收方的MAC地址。

2、命令
  • 产生一个广播数据包

    >>>Ether(dst="ff:ff:ff:ff:ff:ff")
    
3、分层
  • Scapy中的分层通过符号“/”实现,一个数据包是由多层协议组合而成,这些协议之间就可以使用“/”分开,按照协议由底而上的顺序从左向右排列

  • TCP数据包

    >>>Ether()/IP()/TCP()
    
  • HTTP数据包

    >>>IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"		#没有表明二层的时候计算机会自动识别
    
  • 将ttl的值设置为32

    >>>IP(src="192.168.1.1",dst="192.168.1.101",ttl=32)
    
4、ls()
  • ls()****函数来查看一个类所拥有的属性
  • 使用**ls(Ether())**来查看Ether类的属性
  • 使用**ls(IP())**来查看IP类的属性
>>> tcp_packet = IP(dst='192.168.184.10')/fuzz(TCP())
>>> tcp_packet
<IP  frag=0 proto=tcp dst=192.168.184.10 |<TCP  |>>

>>> ls(tcp_packet)
version    : BitField  (4 bits)                  = 4               (4)				#IP部分
ihl        : BitField  (4 bits)                  = None            (None)	
tos        : XByteField                          = 0               (0)
len        : ShortField                          = None            (None)
id         : ShortField                          = 1               (1)
flags      : FlagsField  (3 bits)                = <Flag 0 ()>     (<Flag 0 ()>)
frag       : BitField  (13 bits)                 = 0               (0)
ttl        : ByteField                           = 64              (64)
proto      : ByteEnumField                       = 6               (0)
chksum     : XShortField                         = None            (None)
src        : SourceIPField                       = '192.168.184.128' (None)
dst        : DestIPField                         = '192.168.184.10' (None)
options    : PacketListField                     = []              ([])
--
sport      : ShortEnumField                      = <RandShort>     (20)					#TCP部分
dport      : ShortEnumField                      = <RandShort>     (80)
seq        : IntField                            = <RandInt>       (0)
ack        : IntField                            = <RandInt>       (0)
dataofs    : BitField  (4 bits)                  = None            (None)
reserved   : BitField  (3 bits)                  = <RandNum>       (0)
flags      : FlagsField  (9 bits)                = <RandNum>       (<Flag 2 (S)>)
window     : ShortField                          = <RandShort>     (8192)
chksum     : XShortField                         = None            (None)
urgptr     : ShortField                          = <RandShort>     (0)
options    : TCPOptionsField                     = <RandTCPOptions> (b'')

四、Scapy中的函数

1、send()和sendp()
  • 这两个函数的区别在于send()工作在第三层,而sendp()工作在第二层
  • **send()是用来发送IP数据包的,而sendp()**是用来发送Ether数据包的。
  • 只发不收,只会将数据包发送出去,但是没有能力处理该数据包的回应包!!
# 例如,构造一个目的地址为“192.168.1.101”的ICMP数据包,并将其发送出去,可以使用如下语句。


 send(IP(dst="192.168.184.10")/ICMP())
.
Sent 1 packets.				#不会有数据的回显

#发送广播报文
>>>sendp(Ether(dst="ff:ff:ff:ff:ff:ff"))

image-20220429114146352

2、fuzz()
  • 如果希望发送一个内容是随机填充的数据包,而且又要保证这个数据包的正确性,那么可以是fuzz()函数。
# 可以使用如下命令来创建一个发往192.168.1.101的TCP数据包。

>>> IP(dst="192.168.1.101")/fuzz(TCP())
<IP  frag=0 proto=tcp dst=192.168.1.101 |<TCP  |>>
3、sr()、sr1()、srp()
  • 在网络的各种应用中,需要做的不仅是将创建好的数据包发送出去,也需要接收这些数据包的应答数据包,这一点在网络扫描中尤为重要。

  • 在Scapy中提供了三个用来 发送和接收数据包的函数,分别是sr()、sr1()和srp(),其中,sr()和sr1()主要用于第三层,例如IP和ARP等。而srp()用于第二层。

# 仍然向192.168.1.101发送一个ICMP数据包来比较一下sr()和send()的区别。

>>>sr(IP(dst="192.168.1.101")/ICMP())			# 会有数据回显
  • sr()

    • sr()函数是Scapy的核心,他的返回值是两个列表
      • 第一个列表是收到了应答的包和对应的应答
      • 第二个列表是未收到应答的包
    • 所以可以使用连个列表来保存sr()的返回值
    • .summary()查看包中的具体内容
    >>> icmp_packet = IP(dst='192.168.184.10')/ICMP()
    >>> icmp_packet
    <IP  frag=0 proto=icmp dst=192.168.184.10 |<ICMP  |>>
    >>> sr(icmp_packet)
    Begin emission:
    Finished sending 1 packets.
    .*
    Received 2 packets, got 1 answers, remaining 0 packets
    (<Results: TCP:0 UDP:0 ICMP:1 Other:0>,
     <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
     
     """
     当产生的数据包发送出去后,Scapy就会监听收到的数据包,并将其中对应的应答数据包筛选出来,显示在下面
     
     Reveived 表示收到的数据包的个数
     answers  表示对应的应答数据包
     
     """
    
    >>> ans,unans = sr(icmp_packet)
    Begin emission:
    Finished sending 1 packets.
    ..*
    Received 3 packets, got 1 answers, remaining 0 packets
    >>> ans.summary()			#查看包中的具体内容
    IP / ICMP 192.168.184.128 > 192.168.184.10 echo-request 0 ==> IP / ICMP 192.168.184.1 > 192.168.184.128 redirect network-redirect / IPerror / ICMPerror
    >>> 
    
  • sr1()

    • 和sr()的作用基本一样,但是只返回一个应答包
    • 只需要一个列表就可以保存这个函数的返回值
    >>> p = sr1(IP(dst = "192.168.184.10")/ICMP())
    Begin emission:
    Finished sending 1 packets.
    .*
    Received 2 packets, got 1 answers, remaining 0 packets
    >>> p.summary()
    'IP / ICMP 192.168.184.1 > 192.168.184.128 redirect network-redirect / IPerror / ICMPerror'
    
    • 利用sr1()函数来测试目标的某个端口是否开放,采用半开扫描(SYN)的方法
    >>> sr1(IP(dst="192.168.184.10")/TCP(dport=80,flags="S"))
    

image-20220429114120821

4、sniff()
  • 这个函数可以在自己的程序中捕获经过本机网卡的数据包

    >>> sniff()
    ^C<Sniffed: TCP:0 UDP:88 ICMP:25 Other:9>
    
  • filter参数

    • 只捕获与192.168.1.102有关的数据包

      >>> sniff(filter="host 192.168.1.102")
      
    • 指定过滤ICMP类型的数据包

      >>> sniff(filter="icmp")
      
    • 同时满足多个条件可以使用andor等关系运算符

      >>> sniff(filter="host 192.168.1.102 and icmp")
      
  • iface参数

    • 指定eth1作为监听网卡

      >>> sniff(iface="eth1")
      
  • count参数

    • 用来指定监听到的数据包的数量,达到指定的数量就会停止监听

    • 只希望监听到三个数据包

      >>> sniff(count=3)
      
  • 综合案例

  • 设计一个综合性的监听器,它会在网卡eth0上监听源地址或者目的地址为192.168.1.102icmp数据包,当收到了三个这样的数据包之后,就会停止监听。

    >>> sniff(filter="icmp and host 192.168.1.102",count=3,iface="eth0")
    
    """
    如果需要查看这三个数据包内容,可以使用“_”,在Scapy中这个符号表示是上一条语句执行的结果,
    
    例如刚刚使用sniff捕获到的数据包,就可以用“_”表示。     
    
    >>> a =_
    >>> a.nsummary()
    
    """
    

五、Scapy模块的常用简单实例

  • 使用Scapy来实现一次ACK类型的端口扫描

  • **ACK****扫描:**扫描主机向目标主机发送ACK数据包。根据返回的RST数据包有两种方法可以得到端口的信息。

  • 正常的时候,如果一个开放的端口会回应ACK数据包,而关闭的端口会回应RST数据包。

  • 在网络中,一些网络安全设备会过滤掉一部分端口,这些端口不会响应来自外界的数据包,一切发往这些端口的数据包都如同石沉大海。注意这些端口的状态并非是开放或者关闭,而是被屏蔽。

#例如,对192.168.1.102 的 21、23、135、443、445 这5个端口是否被屏蔽进行扫描,注意是屏蔽不是关闭,采用ACK扫描模式,可以构造如下的命令方式。
 
>>> ans,unans = sr(IP(dst="192.168.1.102")/TCP(dport=[21,80,135,443,445],flags="A"))

"""
向目标发送了5个标志位置为“A”的TCP数据包。按照TCP三次握手的规则,如果目标端口没有被过滤,发出的数据包就会得到回应,否则没有回应。另外,根据Scapy的设计,ans列表中的数据包就是得到了回应的数据包,而unans中的则是没有得到回应的数据包,只需要分两次来读取这两个列表就可以得到端口的过滤结果
"""

>>>for s,r in ans:
	... if s[TCP].dport == r[TCP].sport:			# 如果发出去的报文和收到的报文端口号相同,则打印出来
		... print (str(s[TCP].dport) + " is unfiltered“)	
                   
# 利用类似的方法来查看被过滤的端口
>>>for s in unans:
	... print str(s[TCP].dport) + " is filtered"
"""

能够实现查看端口是否被屏蔽

"""
from scapy.all import IP,TCP,sr

ans,unans = sr(IP(dst="192.168.184.10")/TCP(dport=[21,23,80,135,443,445],flags="A"))

for s,r in ans:         # s:send    r:receive
    if s[TCP].dport == r[TCP].sport:
        print(f"{s[TCP].dport} 没有被过滤")
└─# python3 yang_02_端口扫描.py                                                                                  
Begin emission:
Finished sending 6 packets.
.******
Received 7 packets,got 6 answers,remaining 0 packets
21没有被过滤
23没有被过滤
80没有被过滤
135没有被过滤
443没有被过滤
445没有被过滤

情报收集

一、简介

这里的**“情报”**指的是目标网络、服务器、应用程序的所有信息。

渗透测试人员需要使用资源尽可能地获取要测试目标的相关信息。

二、分类

  • 信息收集获得信息的方法可以分成两种:被动扫描主动扫描
    • 被动扫描主要指的是在目标 无法察觉的情况下 进行的信息收集,例如,如果想了解一个远在天边的人,你会怎么做呢?显然可以选择在搜索引擎中去搜索这个名字。其实这就是一次对目标的被动扫描

    • 主动扫描一般都是针对目标发送特制的数据包,然后根据目标的反应来获得一些信息。

      扫描之后将会获得的信息包括:目标网络的结构,目标网络所使用设备的类型,目标主机上运行的操作系统,目标主机上所开放的端口,目标主机上所提供的服务,目标主机上所运行的应用程序

三、nmap工具

1、语法
nmap + 参数
选择扫描目标的nmap语法如下所示。
(1)扫描指定IP主机:nmap 192.168.169.1332)扫描指定域名主机:nmap www.nmap.com。
(3)扫描指定范围主机:nmap 192.168.169.1-20。
(4)扫描一个子网主机:nmap 192.168.169.0/24
2、对目标的端口进行扫描
扫描一个主机的特定端口:nmap -p 22 192.168. 169.1
扫描指定范围端口:nmap -p 1-80 192.168. 169.1
扫描100个最为常用的端口:nmap -F 192.168. 169.1
3、对目标端口状态进行扫描
使用TCP全开扫描:nmap -sT 192.168. 169.1		#正常三次握手
使用TCP半开扫描:nmap -sS 192.168. 169.1	# 只发送SYN,收到SA的时候回复RST
使用UDP扫描:nmap -sU -p 123,161,162 192.168. 169.1
4、对目标的操作系统和允许服务进行扫描
扫描目标主机上运行的操作系统:nmap -O 192.168.169.1
扫描目标主机上运行的服务类型:nmap -sV 192.168.169.1

身份认证

一、使用Python编写一个生成字典的程序

  • 在这个程序中需要使用到一个新的模块:itertools,这是一个强大的内置模块。
1、基础函数介绍
①、**count()**函数:这个函数的作用是产生递增的序列,例如count(1,5),生成从1开始的循环器,每次增加5,即1,6,11,16,21,26,…
②、**cycle()**函数:这个函数的作用是重复序列中的元素,例如cycle(‘hello’),将序列中的元素重复,即h,e,l,l,o,h,e,l,l,o,h,…
③、**repeat()**函数:这个函数的作用是重复元素,构成无穷循环器,例如Repeat(100),即100,100,100,100,…
④、**product()**函数:它可以用来获得多个循环器的笛卡儿积,例如product(‘xyz’, [0, 1]),得到的结果就是x0,y0,z0,x1,y1,z1
⑤、permutations(‘abcd’, 2)#从’abcd’中挑选两个元素,例如ab,bc,…,并将所有结果排序,返回为新的循环器。这些元素中的组合是有顺序的,同时生成cd和dc**(最为常用的)**
⑥、combinations(‘abc’, 2) #:从’abcd’中挑选两个元素,例如ab,bc,…,将所有结果排序,返回为新的循环器,这些元素中的组合是没有顺序的,例如c和d只能生成cd
2、过程
第一步:导入itertools库。
>>>import itertools

第二步:指定生成字典的字符,这里使用所有的英文字符和数字(但是没有考虑大小写和特殊字符)

>>>words = "1234568790abcdefghijklmnopqrstuvwxyz"

**第三步:**使用itertools中提供的循环器来生成字典文件

>>>temp = itertools.permutations(words,2)

**第四步:**打开一个用于保存结果的记事本文件

>>>passwords = open("dic.txt","a")

**第五步:**使用一个循环将生成的密码写入到一个记事本文件中。

>>>for i in temp:         
	passwords.write("".join(i))         	
	passwords.write("".join("\n"))
3、实例
  • 普通情况
"""
创建一个字典文件
"""
# 导入itertools库
import itertools
# 根据字母池创建密码
words = "qwertyuiopasdfghjklzxcvbnm1234567890"
temp = itertools.permutations(words,4)
# 创建一个密码本字典
with open("dist.txt", 'a') as password_dict:
    for i in temp:
        password_dict.write("".join(i))
        password_dict.write("".join('\n'))
  • 熟知特定字符
import itertools
import sys

if len(sys.argv) != 3:
    print("请按照如下格式输入:\n Python xxx.py 参数1 参数2")
    sys.exit()

words = sys.argv[1]
lens = int(sys.argv[2])

temp = itertools.permutations(words, lens)

with open("Dist.txt", 'a',encoding='utf-8') as passwd_Dict:
    for i in temp:
        passwd_Dict.write("".join(i))
        passwd_Dict.write("".join('\n'))

网络嗅探与欺骗

一、网络数据嗅探

1、sniff()函数
①、重要参数
  • **count:**表示要捕获数据包的数量。默认值为0,表示不限制数量
  • store:表示是否要保存捕获到的数据包,默认值为1
  • prn:这个参数是一个函数,这个函数将会应用在每一个捕获到的数据包上,如果这个函数有返回值,将会显示出来。默认是空; 返回一个数据包信息
  • iface:表示要使用的网卡或者网卡列表
②、BPF表达式
  • Type用来规定使用名字或数字代表的类型,例如host、net和port等
  • Dir用来规定流量的方向,例如src、dst和src and dst等
  • Proto用来规定匹配的协议,例如ip、tcp和arp等
⑤、常见的过滤器

(1)只捕获与网络中某一个IP的主机进行交互的流量:“host 192.168.1.1”。

(2)只捕获与网络中某一个MAC地址的主机交互的流量:“ether host 00-1a-a0-52-e2-a0”。

(3)只捕获来自网络中某一个IP的主机的流量:“src host 192.168.1.1”。

(4)只捕获去往网络中某一个IP的主机的流量:“dst host 192.168.1.1”,host也可以省略。

(5)只捕获23端口的流量:“port 23”。

(6)捕获除了23端口以外的流量:“!23” 。

(7)只捕获目的端口为80的流量:“dst port 80”。

(8)只捕获ICMP流量:“icmp”。

(9)只捕获type为3,code为0的ICMP流量:“icmp[0] = 3 &&icmp[1] = 0”。 ([type,code])

⑥、实例
>>> sniff(filter="dst 39.156.66.14 and tcp port 80",prn=lambda x:x[IP].src,
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
192.168.184.128
<Sniffed: TCP:10 UDP:0 ICMP:0 Other:0>
2、wrpcap()函数
  • 通过sinff函数收集到的数据包,可以使用wrpcap()函数保存起来,通常使用的格式为pcap。

  • 举例

    >>> packet = sniff(count=5)
    >>>wrpcap("demo.pcap", packet)  # 此时将会生成一个demo.pcap的文件
    
3、编写网络嗅探工具
# 导入包
from scapy.all import *
import sys

# if 判断
if len(sys.argv) != 2:
    print("Usage: catchPackets<IP>:\n eg: catchPackets 192.168.0.1 ")
    sys.exit()
# 定义ip地址
ip = sys.argv[1]

# 定义callback 回调函数
def callback(packet):
    print(packet.show())

packets = sniff(filter="host " + ip, prn=callback, count=5)
wrpcap("yang.pcap", packets)
image-20220430222937685

此时开启一个终端ping www.baidu.com,另一个终端执行脚本,就会抓取到相应的流量,在桌面生成对应的数据包

二、ARP的原理与缺陷

1、概念

​ ARP协议是“Address Resolution Protocol”(地址解析协议)的缩写。其作用是在以太网环境中,数据的传输所依懒的是MAC地址而非IP地址,而将已知IP地址转换为MAC地址的工作是由ARP协议来完成的。

2、缺陷
  • 过程中并没有任何的 认证机制
3、arpspoof

arpspoof [-i指定使用的网卡] [-t 要欺骗的目标主机] [-r] 要伪装成的主机

4、开启流量转发

root@kali:~# echo 1 >> /proc/sys/net/ipv4/ip_forward

三、代理ARP

1、概念
  • 路由器收到ARP Request时,若发现查询的目的IP地址在不同子网,路由器会扮演代理的ARP的角色,代为回答,告诉查询者它所要做的MAC地址
  • 代理ARP可以解决配置静态路由没有网关和不配置下一跳的问题
  • 点到点模式不需要配置下一跳,自动发送广播报文
2、配置
arp-proxy enable

四、无故/免费ARP

  • 当一个VRRP 备份组完成选举之后, MASTER 接口会发出一个 无故ARP,用于通告 MASTER设备的MAC地址,用于流量的引导。
  • 对于交换机来讲,交换机会将 虚拟mac地址对应的接口写入MAC地址表,用于流量的引导
  • 对于普通用户来讲,成为Master的设备,通过发送无故ARP,告知用户,网关的MAC地址是多少。

五、DHCP

1、概念

目的:使客户机可以通过路由器所提供的DHCP服务获取到IP地址

DHCP:动态主机配置协议

主要为客户机提供TCP/IP参数:IP地址、子网掩码、网关、DNS服务器地址

image-20220501103313030
2、配置
image-20220501105731504
[AR1]ip pool pool1		# 创建一个地址池
[AR1-ip-pool-pool1]network 192.168.1.0 mask 255.255.255.0		#设置范围
[AR1-ip-pool-pool1]gateway-list 192.168.1.254		# 配置网关
# 配置DNS服务器
[AR1-ip-pool-pool1]dns-list 8.8.8.8					
[AR1-ip-pool-pool1]dns-list 114.114.114.114		
[AR1]dhcp enable			# 开启DHCP服务
[AR1-GigabitEthernet0/0/0]dhcp select  global		#调用一个全局模式下建立的地址池 (ip pool) 网关
[AR1-GigabitEthernet0/0/0]ip addr 192.168.1.254 24		# 配置IP地址

[AR1-ip-pool-pool1]excluded-ip-address 192.168.1.251		# 配置IP地址的时候自动排除192.168.1.251
[AR1]dis ip pool name pool1 all 		# 查看pool1地址池的详细信息

配置完成后,PC端即可自动获取IP地址

因为有些服务器需要固定的IP地址,所以每台设备获取DHCP的时候,会发送免费ARP,确定有没有人使用此IP,避免冲突情况

SSH服务

一、基础SSH配置

交换机、防火墙设备SSH服务的开启与测试

1、拓扑图

image-20220503164153640

2、基础配置
①、SW1
# 配置管理Vlan并允许通过
[SW1]vlan batch 100
[SW1-GigabitEthernet0/0/1]port link-type trunk 
[SW1-GigabitEthernet0/0/1]port trunk allow-pass vlan 100

[SW1-GigabitEthernet0/0/2]port link-type trunk 
[SW1-GigabitEthernet0/0/2]port trunk allow-pass vlan 100

[SW1-GigabitEthernet0/0/24]port link-type trunk 
[SW1-GigabitEthernet0/0/24]port trunk allow-pass vlan 100

[SW1-GigabitEthernet0/0/3]port link-type access
[SW1-GigabitEthernet0/0/3]port default vlan 100

[SW1]stp enable		# 开启STP
[SW1]stp root primary		# 设置SW1为根桥

# 配置IP地址
[SW1]int Vlanif 100
[SW1-Vlanif100]ip add 192.168.100.1 24
②、SW2
[SW2]vlan batch 100
[SW2-GigabitEthernet0/0/1]port link-type trunk 
[SW2-GigabitEthernet0/0/1]port trunk allow-pass vlan 100

[SW2-GigabitEthernet0/0/2]port link-type trunk 
[SW2-GigabitEthernet0/0/2]port trunk allow-pass vlan 100

[SW2-GigabitEthernet0/0/24]port link-type trunk 
[SW2-GigabitEthernet0/0/24]port trunk allow-pass vlan 100

# 配置IP地址
[SW2-GigabitEthernet0/0/2]int vlan 100
[SW2-Vlanif100]ip addr 192.168.100.2 24
③、SW3
[SW3]vlan batch 100
[SW3-GigabitEthernet0/0/1]port link-type trunk 
[SW3-GigabitEthernet0/0/1]port trunk allow-pass vlan 100

[SW3-GigabitEthernet0/0/2]port link-type trunk 
[SW3-GigabitEthernet0/0/2]port trunk allow-pass vlan 100

# 配置IP地址
[SW3]int vlan 100
[SW3-Vlanif100]ip addr 192.168.100.3 24
4、SW4
[SW4]vlan batch 100
[SW4-GigabitEthernet0/0/1]port link-type trunk 
[SW4-GigabitEthernet0/0/1]port trunk allow-pass vlan 100

[SW4-GigabitEthernet0/0/2]port link-type trunk 
[SW4-GigabitEthernet0/0/2]port trunk allow-pass vlan 100

# 配置IP地址
[SW4]int vlan 100
[SW4-Vlanif100]ip addr 192.168.100.4 24
5、配置SSH
[SW1]dsa local-key-pair create		# 创建本地密钥对
	Please input the modulus [default=512]:2048
	
# 配置用户名和密码
[SW1]stelnet server enable 		# 开启SSH登录
[SW1]ssh user yang authentication-type password		# 用户名为 yang,认证方式为密码认证
[SW1]ssh user yang service-type stelnet			# 设置登录类型为ssh

#开放 Vty端口,能被远程登录
[SW1]user-interface vty 0 4	  	# 开启0-4的vty端口,允许5台设备登录
# 认证模式为aaa认证

"""
authentication 认证:谁能登录进来
authorizathon  授权:谁进来能干什么
according      审计:谁进来干了什么
"""
[SW1-ui-vty0-4]authentication-mode aaa		
[SW1-ui-vty0-4]protocol inbound ssh		#登录进来的协议是ssh 

#配置aaa
[SW1-aaa]local-user yang password cipher 123123		# 设置密码
[SW1-aaa]local-user yang privilege level 15			# 设置权限等级
[SW1-aaa]local-user yang service-type ssh
6、测试连通性
C:\Users\Yang>ping 192.168.100.1

正在 Ping 192.168.100.1 具有 32 字节的数据:
来自 192.168.100.1 的回复: 字节=32 时间=35ms TTL=255
来自 192.168.100.1 的回复: 字节=32 时间=14ms TTL=255
来自 192.168.100.1 的回复: 字节=32 时间=11ms TTL=255

192.168.100.1 的 Ping 统计信息:
    数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 11ms,最长 = 35ms,平均 = 20ms
image-20220503103944404
7、在SW2做相同配置
[SW2]dsa local-key-pair create		# 创建本地密钥对
	Please input the modulus [default=512]:2048
	
# 配置用户名和密码
[SW2]stelnet server enable 		# 开启SSH登录
[SW2]ssh user yang authentication-type password		# 用户名为 yang,认证方式为密码认证
[SW2]ssh user yang service-type stelnet			# 设置登录类型为ssh

#开放 Vty端口,能被远程登录
[SW2]user-interface vty 0 4	  	# 开启0-4的vty端口,允许5台设备登录
# 认证模式为aaa认证

"""
authentication 认证:谁能登录进来
authorizathon  授权:谁进来能干什么
according      审计:谁进来干了什么
"""
[SW2-ui-vty0-4]authentication-mode aaa		
[SW2-ui-vty0-4]protocol inbound ssh		#登录进来的协议是ssh 

#配置aaa
[SW2-aaa]local-user yang password cipher 123123		# 设置密码
[SW2-aaa]local-user yang privilege level 15			# 设置权限等级
[SW2-aaa]local-user yang service-type ssh
8、防火墙
防火墙
# 对G0/0/0管理接口 预配置
 先修改 管理IP地址
 开启 G0/0/0 的SSH 服务 (同SW1) 
	注意:配置密码的时候password cipher 123123
 interface G0/0/0 
 ip addr 192.168.100.102
  service-manage ssh permit		#开启SSH 服务
  service-manage ping permit		# 开启此命令,其他设备才能ping通
  service-manage https permit  (在浏览器输入 https://IP 地址:8443# 冒号是英文的
# SSH登录配置
ssh user yang
ssh user yang authentication-type password
ssh user yang service-type stelnet
stelnet server enable

# vty 端口的配置
user-interface vty 0 4
 authentication-mode aaa
 protocol inbound ssh
 
# 用户信息配置
aaa
 manager-user yang
  password cipher 123123
  service-type ssh
  level 15

二、Python通过SSH链接

import paramiko
import time

# 创建客户端对象
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 使用客户端导入参数 hostname="192.168.100.1", username="yang", password="123123"
ssh.connect(hostname="192.168.100.1", username="yang", password="123123")

# 发送命令,创建命令对象,调用shell
command = ssh.invoke_shell()
# 给设备发送配置命令,编码格式为UTF-8(将发送的命令,字符串形式转换为UTF-8格式的二进制,传递给网络设备)
command.send("sys \n".encode())
command.send("sys Hello \n".encode())

time.sleep(1)  # 1s之后回显数据,发送完命令需要一个延时回显

output = command.recv(65535)  # 接受服务器返回的数据
print(output.decode())  # 将收到的数据解码
ssh.close()  # 程序结束关闭文件

三、Python读取设备配置文件

1、读取配置文件,将读取到的每一行发送给设备
import paramiko
import time

# 创建客户端对象
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 使用客户端导入参数 hostname="192.168.100.1", username="yang", password="123123"
ssh.connect(hostname="192.168.100.1", username="yang", password="123123")

# 发送命令,创建命令对象,调用shell
command = ssh.invoke_shell()

# 读取配置文件,将读取到的每一行发送给设备
with open("SW1.cfg", "r", encoding="utf-8") as f:
    while True:
        content = f.readline()  # 讲读取到的文件,按行储存为一个列表
        if not content:
            break
        # print(i)
        command.send(content.encode())
        # command.send("sys Hello \n".encode())

# print("please wait a monment ...")
time.sleep(5)  # 1s之后回显数据,发送完命令需要一个延时回显

output = command.recv(65535)  # 接受服务器返回的数据
print(output.decode())  # 将收到的数据解码

ssh.close()  # 程序结束关闭文件

2、测试结果
image-20220503160442196

四、配置多个文件

1、设备
dict_sw1 = {"ip_add": "192.168.100.9", "username": "yang", "password": "123123", "path": "D:\桌面\Dream\Day16\SW1.cfg"}
dict_sw2 = {"ip_add": "192.168.100.20", "username": "yang", "password": "123123", "path": "D:\桌面\Dream\Day16\SW2.cfg"}

database = [dict_sw1, dict_sw2]


def done():
    print("""
 ,ggg,         gg                                       
dP""Y8a        88                                       
Yb, `88        88                                       
 `"  88        88                                       
     88        88                                       
     88        88    ,gggg,gg   ,ggg,,ggg,     ,gggg,gg 
     88       ,88   dP"  "Y8I  ,8" "8P" "8,   dP"  "Y8I 
     Y8b,___,d888  i8'    ,8I  I8   8I   8I  i8'    ,8I 
      "Y88888P"88,,d8,   ,d8b,,dP   8I   Yb,,d8,   ,d8I 
           ,ad8888P"Y8888P"`Y88P'   8I   `Y8P"Y8888P"888
          d8P" 88                                  ,d8I'
        ,d8'   88                                ,dP'8I 
        d8'    88                               ,8"  8I 
        88     88                               I8   8I 
        Y8,_ _,88                               `8, ,8I 
         "Y888P"                                 `Y8P"  

    """)

done()
2、脚本
import paramiko
import time
from Day16.devoce_info import *

# 多台设备需要配置数据库,里面存储着各个设备的信息
# 用列表创建数据库,信息使用字典

# range(len(database))遍历,使得item等于对应的值  ---> 0-2
for item in range(len(database)):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname=database[item]["ip_add"], username=database[item]["username"],
                password=database[item]["password"])
    command = ssh.invoke_shell()

    with open(database[item]["path"], "r", encoding="utf-8") as f:
        while True:
            content = f.readline()  # 讲读取到的文件,按行储存为一个列表
            if not content:
                break
            # print(i)
            command.send(content.encode())
            # command.send("sys Hello \n".encode())

    print("please wait a monment ...")
    time.sleep(5)  # 1s之后回显数据,发送完命令需要一个延时回显

    output = command.recv(65535)  # 接受服务器返回的数据
    print(output.decode())  # 将收到的数据解码
    done()

    ssh.close()  # 程序结束关闭文件

image-20220503165857566

五、备份设备配置文件

1、基础配置
display current-configuration		# 查看所有配置   
  exclude  #不包括什么配置
  include  #包括什么配置

display saved-configuration		# 查看已保存的配置

[SW1]user-interface console 0		#进入console 0 口	Ensp默认console口登录
[SW1-ui-console0]screen-length 0		# 不分页全部输出

# 由于SSH登录默认 
[SW1-ui-console0]screen-length 0		
2、脚本
  • 基础脚本
"""
display current-configuration 查看当前的配置
  exclude  #不包括什么配置
  include  #包括什么配置

display saved-configuration		# 查看已保存的配置
"""
import paramiko
import time
# from datetime import time as time_01
from datetime import datetime  # 获取当前时间
from Day17.devoce_info import *

# 创造一个SSH客户端
# 多个设备时需要循环
for item in range(len(database)):
    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh_client.connect(hostname=database[item]["ip_addr"],
                       username=database[item]["username"],
                       password=database[item]["password"])
    command = ssh_client.invoke_shell()

    # 给设备发送查看配置的命令
    command.send("system-view\n"
                 "user-interface vty 0 4\n"
                 "screen-length 0\n".encode())

    command.send("dis cu\n".encode())
    time.sleep(3)

    recv = command.recv(65535).decode()
    # print(recv)
    """
    recv 就是设备给我们返回的结果,但是如果直接将这个结果写入文件,文件呈现的效果是,一行结束会多一个回车。
    所以处理方法为recv这个文件通过.splitlines(),将他的每一行进行切割,组成一个列表
    从而遍历列表,即大文件的每一行,再将每一行写入文件
    但是.splitlines()出来的列表没有换行,所以需要写入的时候添加\n
    """
    resut = recv.splitlines()  # 按行生成列表,没有\n

    bk_time = str(datetime.now())
    now_time = bk_time[:-7].replace(':', ":")
    # 将回显的内容保存到本地
    # 需求:文件名为保存文件的时间
    with open(f"{database[item]['device_name']}-{now_time}.txt", "w") as file_backup:
        for i in resut:
            print(i)
            file_backup.write(i + '\n')

    ssh_client.close()

  • datetime模块
from datetime import *

time1 = datetime.now()
# print(time1)
str_time = str(time1)
print(str_time[:-7].replace(":", ":"))

  • 设备列表
SW1_info = {"ip_addr": "192.168.100.9",
            "username": "yang",
            "password": "123123",
            "device_name": "SW1",
            "device_type": "交换机"}
SW2_info = {"ip_addr": "192.168.100.20",
            "username": "yang",
            "password": "123123",
            "device": "SW2",
            "device_type": "交换机"}

database = [SW1_info, SW2_info]
3、测试
image-20220503212159645

Ubuntu安装与配置

1、安装utools
sudo apt upgrade
sudo apt install open-vm-tools-desktop y-
sudo reboot
2、创建root
# 为root创建密码
sudo passwd root

# 切换到root
su - root
3、更换Ubuntu源
  • 备份源

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    
  • 更改源

    #添加阿里源
    deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
    #添加清华源
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse multiverse
    3.更新
    
  • 更新源

    sudo apt-get update
    

Python虚拟环境安装

1、安装Python

sudo apt install python3 python3-pip -y

2、安装虚拟环境

apt install virtualenv virtualenvwrapper -y

3、定制虚拟环境

  • 编辑~/.bashrc文件

    tail -n3 ~/.bashrc
    
    export WORKON_HOME=$HOME/.virtualenvs
    # find / -name virtualenvwrapper.sh 可以查看文件路径
    source /usr/share/virtualenvwrapper/virtualenvwrapper.sh
    
  • 配置生效

    source ~/.bashrc
    

4、创建虚拟环境安装模块

# 创建命令
mkvirtualenv -p /usr/bin/python3 YikJiang

# 退出虚拟环境
deactivate

# 删除虚拟环境
rmvirtualenv YikJiang

# 进入虚拟环境
workon YikJiang

# 查看虚拟环境下的内容
ls .virtualenvs/

yikjiang@yikjiang:~$ ls .virtualenvs/
get_env_details  postdeactivate    postrmvirtualenv  premkproject     YikJiang
initialize       postmkproject     preactivate       premkvirtualenv
postactivate     postmkvirtualenv  predeactivate     prermvirtualenv

5、虚拟环境的模块源设置(PIP源)

# 安装软件
pip install name

# 查看通过pip安装的Python模块
pip list

# 删除模块
pip uninstall name				# 不添加sudo

# 查看以安装的软件和版本号
pip freeze

# 更换pip源
pip install pip -U		
pip config set global.index-ur1 https://pypi.tuna.tsinghua.deu.cn/simple

PyCharm集成

一、与Ubuntu联通

1、目标
  • Window上的PyCharm使用Ubuntu上的虚拟环境里的解释器
2、前提
  • 需要查看Python解释器在哪里

    ls .virtualenvs/YikJiang/bin/
    
  • 完整的路径

    /home/yangyubo/.virtualenvs/YikJiang/bin/
    
3、步骤
  • PyCharm专业版与Ubuntu连通,实现文件传递
  • PyCharm使用Ubuntu虚拟环境里面的python解释器

二、文件传递

1、Windows代码目录
2、开启Ubuntu的SSH服务
# 安装 SSH 软件
sudo apt-get install openssh-server

# 修改SSH配置(修改端口号,是否使用root用户登录等)
sudo vim /etc/ssh/sshd_config
	# 能让root用户登录
	PermitRootLogin yes
	
# 重启服务
sudo systemctl restart ssh

# 查看当前服务的状态
systemctl status ssh

# 关闭防火墙
sudo ufw disable
sudo systemctl stop ufw
# 测试SSH登录
3、配置SFTP
  • 在PyCharm的菜单栏中,找到tools-Deploymen-Configuration,配置SFTP

image-20220504165518518

image-20220504165546308

  • 配置SFTP参数
image-20220504225358562 image-20220504230546237
  • PyCharm远程连接失败、错误,报错:Can‘t connect…【解决方法与错误分析】

    # 原因
     未安装ssh
     
    # 解决方法
    apt-get install openssh-server
    
4、在Ubuntu中创建存放脚本的目录
  • 创建目录

    yikjiang@yikjiang:~$ mkdir yikjiang_py
    
  • 创建关联目录

image-20220504231124634
5、连通性测试
image-20220504231333391
  • 配置解释器位置
    • 其中下面有本地文件和Ubuntu文件
image-20220504231527271
  • PyCharm上载到Ubuntu

    Ctrl+Shift+Alt+x 
    
  • 查看Ubuntu

image-20220504232735446

自动化运维初体验

一、psutil模块

1、作用
  • psutil是一个跨平台库,主要获取两部分的信息

  • 进程信息

  • 系统利用率信息 - CPU、内存、磁盘、网络等

  • 支持版本

    • 2.x
    • 3.x
  • 最新版本:psutil 5.9.0

2、安装
yikjiang@yikjiang:~/yikjiang_py$ workon yikjiang
(yikjiang) yikjiang@yikjiang:~/yikjiang_py$ pip install psutil

二、常用命令

1、进程相关
ps、top、lsof、kill、nice、pidof、taskset
ps   # 显示当前进程的状态,类似于Windows的进程管理器
ps -aux
	a:显示其他用户启动的进程
	u:启动这个进程的用户和他的启动时间
	x:查看系统中属于自己的进程

lsof # lsof(list open files)是一个列出当前系统打开文件的工具

kill # Linux kill 命令用于删除执行中的程序或工作。

nice # nice命令用于改变进程的优先级。niceness值为负时,表示高优先级,能提前执行和获得更多的资源,对应低友善度;反之,则表示低优先级,高友善度。

pidof # pidof是一个命令行实用程序,可让您找到正在运行的程序的进程ID
。
taskset 
# taskset命令用于设置进程(或 线程)的处理器亲和性(Processor Affinity)
#可以将进程(或 线程)绑定到特定的一个 或 多个CPU上去执行,而不允许将进程(或线程)调度到其他的CPU上
2、网络相关
netstat、ifconfig
netstat # Linux netstat 命令用于显示网络状态。
ifconfg # Linux ifconfig命令用于显示或设置网络设备。 ifconfig可设置网络设备的状态,或是显示目前的设置。
3、用户相关
who
who 
# Linux who命令用于显示系统中有哪些使用者正在上面,显示的资料包含了使用者 ID、使用的终端机、从哪边连上来的、上线时间、呆滞时间、CPU 使用量、动作等等。
#使用权限:所有使用者都可使用。
3、磁盘相关
df
df # Linux df(英文全拼:disk free) 命令用于显示目前在 Linux 系统上的文件系统磁盘使用情况统计。
4、内存相关
free
free 
# Linux free命令用于显示内存状态。
# free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共享内存区段,以及系统核心使用的缓冲区等。
5、io相关
  • iostat属于sysstat软件包。可以直接安装:apt install sysstat -y 安装iostat
ionice、iostat、iotop
ionice # ionice 获取或设置程序的IO调度与优先级。

iostat # iostat是I/O statistics(输入/输出统计)的缩写 显示所有设备的负载情况

iotop  # apt install iotop -y 安装iotop

iotop命令是一个用来监视磁盘I/O使用状况的top类工具。iotop具有与top相似的UI,其中包括PID、用户、I/O、进程等相关信息。Linux下的IO统计工具如iostat,nmon等大多数是只能统计到per设备的读写情况,如果你想知道每个进程是如何使用IO的就比较麻烦,使用iotop命令可以很方便的查看。
与iostat工具比较,iostat是系统级别的IO监控,而iotop是进程级别IO监控
6、运行时相关
uptime
uptime # 查看当前的允许状态 当前运行了几个账户
7、终端相关
tty
tty 
# Linux tty命令用于显示终端机连接标准输入设备的文件名称。
# 在Linux操作系统中,所有外围设备都有其名称与代号,这些名称代号以特殊文件的类型存放于/dev目录下。
# 你可以执行tty(teletypewriter)指令查询目前使用的终端机的文件名称
8、将服务器调整为英文格式输出
yikjiang@yikjiang:~/桌面$ LANG=EN
yikjiang@yikjiang:~/桌面$ echo $LANG
EN
9、查看系统所支持的语言
yikjiang@yikjiang:~/桌面$ locale
LANG=zh_CN.UTF-8
LANGUAGE=zh_CN:zh
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

三、命令实践

1、获取网卡的IP地址
  • ifconfig
iang@yikjiang:~/桌面$ ifconfig ens33 | grep netmask | awk '{print $2}'
192.168.184.133
  • ip addr
yikjiang@yikjiang:~/桌面$ ip addr | grep global | awk '{print $2}'
192.168.184.133/24

# cut -d '/' -f1 : 以 / 为分隔符,取第一个区
yikjiang@yikjiang:~/桌面$ ip addr | grep global | awk '{print $2}' | cut -d '/' -f1
192.168.184.133
  • cut
Linux cut命令用于显示每行从开头算起 num1 到 num2 的文字。

-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
-c :以字符为单位进行分割。
-d :自定义分隔符,默认为制表符。
-f :与-d一起使用,指定显示哪个区域。
-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的
范围之内,该字符将被写出;否则,该字符将被排除
2、获取所有网卡的IP地址
  • ifconfig
# 获取网卡名称
yikjiang@yikjiang:~/桌面$ ifconfig | grep flags | cut -d ':' -f1
ens33
lo

#获取所有IP地址
#仅限于 ifconfig命令,ip address 不能用
# cut -d '/' -f1 : 以 / 为分隔符,取第一个区域
yikjiang@yikjiang:~/桌面$ for net_name in $(ifconfig | grep flags | cut -d ':' -f1);do ifconfig $net_name | grep netm | awk '{print $2}';done
192.168.184.133
127.0.0.1
  • ip addr
yikjiang@yikjiang:~/桌面$ ip addr | grep scope | grep -v inet6 | awk '{print $2}' | cut -d '/' -f1
127.0.0.1
192.168.184.133
3、获取所有运行端口的信息
  • netstat
yikjiang@yikjiang:~/桌面$ sudo netstat -nupl		#查看UDP类型的端口
[sudo] yikjiang 的密码: 
激活Internet连接 (仅服务器)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
udp        0      0 127.0.0.53:53           0.0.0.0:*                           764/systemd-resolve 
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           809/avahi-daemon: r 
udp        0      0 0.0.0.0:39229           0.0.0.0:*                           809/avahi-daemon: r 
udp        0      0 0.0.0.0:631             0.0.0.0:*                           880/cups-browsed    
udp6       0      0 :::5353                 :::*                                809/avahi-daemon: r 
udp6       0      0 :::58728                :::*                                809/avahi-daemon: r 
yikjiang@yikjiang:~/桌面$ sudo netstat -ntpl
激活Internet连接 (仅服务器)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      764/systemd-resolve 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      907/sshd: /usr/sbin 
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      812/cupsd           
tcp6       0      0 :::22                   :::*                    LISTEN      907/sshd: /usr/sbin 
tcp6       0      0 ::1:631                 :::*                    LISTEN      812/cupsd   

四、模块安装

1、模块安装
  • 进入普通用户的 虚拟环境 ,并查看已经安装的模块
yikjiang@yikjiang:~/桌面$ workon yikjiang
(yikjiang) yikjiang@yikjiang:~/桌面$ pip list
Package       Version
------------- -------
pip           20.0.2 
pkg-resources 0.0.0  
psutil        5.9.0  
setuptools    44.0.0 
wheel         0.34.2 
(yikjiang) yikjiang@yikjiang:~/桌面$ pip install psutil
2、模块的使用
  • 在Python环境中
# 导入包
import psutil

# 使用包功能
psutil.virtual_memory()
(yikjiang) yikjiang@yikjiang:~/桌面$ python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import psutil
>>> psutil.virtual_memory()
svmem(total=2055090176, available=696741888, percent=66.1, used=1181618176, free=137699328, active=1053388800, inactive=419950592, buffers=69718016, cached=666054656, shared=2637824, slab=200876032)
  • ipython
(yikjiang) yikjiang@yikjiang:~/桌面$ sudo apt install ipython3
(yikjiang) yikjiang@yikjiang:~/桌面$ ipython3 

In [1]: import psutil                                                         

In [2]: psutil.virtual_memory()                                               
Out[2]: svmem(total=2055090176, available=626012160, percent=69.5, used=1251840000, free=134275072, active=1024696320, inactive=449495040, buffers=50929664, cached=618045440, shared=2580480, slab=202473472)

五、PyCharm使用

1、测试
import psutil
info = psutil.virtual_memory()
print(info)
image-20220505113110260
2、获取系统性能信息

CPU 信息

  • Linux操作系统的CPU利用率有以下几个部分:
    • User Time,执行用户进程的时间百分比;
    • System Time,执行内核进程和中断的时间百分比;
    • Wait IO,由于IO等待而使CPU处于idle(空闲)状态的时间百分比;
    • Idle,CPU处于idle状态的时间百分比
#基本信息
.cpu_times() # 我们可以为该方法添加 percpu=True 的属性,获取 逻辑cpu信息

#cpu核信息
.cpu_count() # 我们可以为该方法添加 percpu=True 的属性,获取 逻辑cpu信息
  • 代码
import psutil

# 获取总体基本信息
cpu_info = psutil.cpu_times()
print(f"CPU的基本信息{cpu_info}")

# 获取部分信息
cpu_user = cpu_info.user
print(f'CPU用户进程的时间为:{cpu_user}')

cpu_system = cpu_info.system
print(f"CPU系统进程的时间为:{cpu_system}")

cpu_iowait = cpu_info.iowait
print(f"CPU IO等待时间占比为:{cpu_iowait}")

# 获取逻辑包含的部分信息
# 生成的是列表,并且显示多个逻辑CPU信息
# 在虚拟机设置里可以设置CPU的数量
cpu_info_percpu = psutil.cpu_times(percpu=True)
print(f"CPU基本信息:{cpu_info_percpu}")
  • 输出
CPU的基本信息scputimes(user=35.73, nice=28.13, system=69.67, idle=12166.18, iowait=0.98, irq=0.0, softirq=0.88, steal=0.0, guest=0.0, guest_nice=0.0)
CPU用户进程的时间为:35.73
CPU系统进程的时间为:69.67
CPU IO等待时间占比为:0.98
CPU基本信息:[scputimes(user=16.29, nice=11.39, system=34.8, idle=6086.92, iowait=0.61, irq=0.0, softirq=0.47, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=19.43, nice=16.74, system=34.87, idle=6079.25, iowait=0.36, irq=0.0, softirq=0.4, steal=0.0, guest=0.0, guest_nice=0.0)]

Process finished with exit code 0
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值