错误异常处理与面向对象

文章目录

    • 1. 错误和异常
      • 1.1 基本概念
      • 1.1.1 Python 异常
      • 1.2 检测(捕获)异常
      • 1.2.1 try except 语句
      • 1.2.2 捕获多种异常
      • 1.2.3 捕获所有异常
      • 1.3 处理异常
      • 1.4 特殊场景
      • 1.4.1 with 语句
    • 2. 内网主机存活检测程序
      • 2.1 scapy 模块
      • 2.1.1 主要功能
      • 2.1.2 scapy 安装
      • 2.1.3 进入scapy 模块
      • 2.1.4 简单使用
      • 2.2 主机存活检测程序
    • 3. 面向对象编程
      • 3.1 类
      • 3.1.1 创建类
      • 3.1.2 __init__ 方法
      • 3.2 方法
      • 3.2.1 绑定方法
      • 3.3 继承
      • 3.3.1 子类继承
      • 3.3.2 方法重写
      • 3.3.3 多重继承
      • 3.4 魔法函数
      • 3.4.1 类和实例的内建函数
      • 3.4.2 常用的魔法函数
      • 私有化

1. 错误和异常

如果遇到了错误(异常),如何去处理?

1.1 基本概念

1.1.1 Python 异常

当程序运行时,因为遇到未知的错误而导致中止运行,便会出现Traceback 消息,打印异常。异常即是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行。一般情况下,在Python 无法正常处理程序时就会发生一个异常。异常是Python 对象,表示一个错误。当Python 脚本发生异常时我们需要响应处理它,否则程序会终止执行。

异常 描述
SyntaxError 语法错误
NameError 未声明/初始化对象
IndexError 序列中没有此索引
KeyboardInterrupt 用户中断执行(Ctrl+C)
EOFError 没有内建输入,到达EOF 标记(Ctrl+D) 不适用windows 系统
IOError 输入/输出操作失败
ValueError 当操作或函数接收到具有正确类型但值不适合的参数, 并且情况不能用更精确的异常,例如 IndexError来描述时将被引发。
TypeError 字符串与整数相加时触发。

1.2 检测(捕获)异常

如果一个语句发生了错误或异常,跳过该语句的执行,执行另外的语句。

1.2.1 try except 语句

尝试执行try 语句,如果遇到异常(行不通)则执行except 语句。两个语句执行执行一个。

语法规则

try:
    pass                # 监控这里的异常
except Exception[, reason]:
    pass                # 异常处理代码

示例:

# 01 - 异常初探.py

try:
    username = input("Please input your name: ")
    print(f"Welcome, {username}")

except:
    print("\nSomething Error!")

1.2.2 捕获多种异常

算命脚本:输入年龄,预测明年的年龄。

可以把多个except 语句连接在一起,处理一个try 块中可能发生的多种异常。

# 02 - 捕获多种异常.py

banner = '''
算命脚本
1. 预测年龄
2. 预测财运
3. 预测姻缘
'''

print(banner)

choice = input("Please input the number: ")
choice = int(choice)

if choice != 1:
    print("好好学习...")
    exit()

try:
    age = input("Please input your age: ")
    print(f"The next year your name: {int(age) + 1}")

except ValueError:
    print("Please input a number!")

except KeyboardInterrupt:
    print("\nCtrl + C")

except:
    print("\nSomething Error!")

1.2.3 捕获所有异常

如果出现的异常没有出现在指定要捕获的异常列表中,程序仍然会中断。可以使用在异常继承的树结构中,BaseException 是在最顶层的,所以使用它可以捕获任意类型的异常。

except BaseException:           # 捕获所有异常,相当于except
    print("\nSomething Error!")

Pyhton 异常树

BaseException                                               所有异常的基类
     |
     |
     +-- SystemExit                                         解释器请求退出
     |
     |
     +-- KeyboardInterrupt                                  用户中断执行(通常是输入^C)
     |
     |
     +-- GeneratorExit                                      生成器调用close();方法时触发的
     |
     |
     +-- Exception                          常规错误的基类,异常都是从基类Exception继承的。
          |
          +-- StopIteration                                 迭代器没有更多的值
          |
          +-- StandardError                                 所有的内建标准异常的基类
          |    +-- BufferError                              缓冲区操作不能执行
          |    +-- ArithmeticError                          所有数值计算错误的基类
          |    |    +-- FloatingPointError                  浮点计算错误
          |    |    +-- OverflowError                       数值运算超出最大限制
          |    |    +-- ZeroDivisionError                   除(或取模)零 (所有数据类型)
          |    +-- AssertionError                           断言语句失败
          |    +-- AttributeError                           访问未知对象属性
          |    +-- EnvironmentError                         操作系统错误的基类
          |    |    +-- IOError                             输入输出错误
          |    |    +-- OSError                             操作系统错误
          |    |         +-- WindowsError (Windows)         系统调用失败
          |    |         +-- VMSError (VMS)                 系统调用失败
          |    +-- EOFError                                 没有内建输入,到达EOF 标记
          |    +-- ImportError                              导入模块/对象失败
          |    +-- LookupError              无效数据查询的基类,键、值不存在引发的异常
          |    |    +-- IndexError                          索引超出范围
          |    |    +-- KeyError                            字典关键字不存在
          |    +-- MemoryError              内存溢出错误(对于Python 解释器不是致命的)
          |    +-- NameError                未声明/初始化对象 (没有属性)
          |    |    +-- UnboundLocalError                   访问未初始化的本地变量
          |    +-- ReferenceError           弱引用(Weak reference)试图访问已经垃圾回收了的对象
          |    +-- RuntimeError                             一般的运行时错误
          |    |    +-- NotImplementedError                 尚未实现的方法
          |    +-- SyntaxError                              语法错误
          |    |    +-- IndentationError                    缩进错误
          |    |         +-- TabError                       Tab 和空格混用
          |    +-- SystemError                              一般的解释器系统错误
          |    +-- TypeError                                对类型无效的操作
          |    +-- ValueError                               传入无效的参数
          |         +-- UnicodeError                        Unicode 相关的错误
          |              +-- UnicodeDecodeError             Unicode 解码时的错误
          |              +-- UnicodeEncodeError             Unicode 编码时错误
          |              +-- UnicodeTranslateError          Unicode 转换时错误
          |
          +-- Warning                                       警告的基类
               +-- DeprecationWarning                       关于被弃用的特征的警告
               +-- PendingDeprecationWarning                关于特性将会被废弃的警告
               +-- RuntimeWarning              可疑的运行时行为(runtime behavior)的警告
               +-- SyntaxWarning                            可疑的语法的警告
               +-- UserWarning                              用户代码生成的警告
               +-- FutureWarning                            关于构造将来语义会有改变的警告
               +-- ImportWarning               关于模块进口可能出现错误的警告的基类。
               +-- UnicodeWarning                           有关Unicode警告的基类。
               +-- BytesWarning                             有关字节警告相关的基类。

1.3 处理异常

try:                                                # 尝试执行某个语句
    num = int(input("The number:"))
except BaseException:                               # 如果遇到异常,执行的语句
    print("something error!")
else:                                               # 如果没有遇到异常,执行的语句
    print(num)
finally:                                            # 不管是否遇到异常,都要执行的语句。
    print("This is finally")
  • else 子句:在try 范围中没有异常被检测到时,执行else 子句。在else 范围中的任何代码运行前,try 范围中的所有代码必须完全成功。
  • finally 子句:finally 子句是无论异常是否发生,是否捕捉都会执行的一段代码。比如获取用户的输入,写入文件,但是如果在获取数据过程中,发生了异常,就会导致整个脚本结束执行,文件也无法关闭了。为了解决这个问题,可以采用异常处理中的finally 子句,也就是说,无论语句是否正常执行,都需要关闭。
# 03 - 处理异常.py

banner = '''
------------------------------------------------
5块钱算命脚本:
1. 预测年龄
2. 预测财运
3. 预测姻缘
------------------------------------------------
'''
print(banner)

def guess_age():
    try:
        age = input("Please input your age:")
        age = int(age)
    except KeyboardInterrupt:
        print("\nCtrl + C.END!")

    except ValueError:
        print("\nPlwase input a number!")

    else:   #try中没有异常时,执行else中的语句
        age +=1
        if(age > 130):
            print("Please enter your real age!!!")
        else:
            print(f"Next year,your age is {age}")

    finally:    #不管try中语句是否异常都要finally语句
        print("5块钱算命脚本,执行结束!")
guess_age()

1.4 特殊场景

1.4.1 with 语句

with 语句是用来简化代码的。比如在将打开文件的操作放在with 语句中,代码块结束后,文件将自动关闭。用来简化文件操作的打开和关闭,其中closed 属性是判断文件是否被关闭的

>>> with open('foo.py') as f:

2. 内网主机存活检测程序

2.1 scapy 模块

与scrapy 有非常大的区别。

scapy 是一个Python 的第三方模块,被称为“网络神器”。scapy 模块能够发送、捕获、分析和铸造网络数据包。

2.1.1 主要功能

错误异常处理与面向对象_第1张图片

2.1.2 scapy 安装

Windows 下安装scapy

python -m pip install scapy

Kali 中自带scapy 环境。

2.1.3 进入scapy 模块

┌──(ajest zh-CN)-[~]
└─$ sudo scapy                     

                     aSPY//YASa       
             apyyyyCY//////////YCa       |
            sY//////YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.4.5
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyP////C   | Have fun!
              p///Ac            sC///a   |
              P////YCpc           A//A   | Craft packets before they craft
       scccccp///pSP///p          p//Y   | you.
      sY/////////y  caa           S//P   |                      -- Socrate
       cayCyayP//Ya              pY/Ya   |
        sY/PsY////YCc          aC//Yp 
         sc  sccaCY//PCypaapyCP//YSs  
                  spCPY//////YPSps    
                       ccaacs         
                                       using IPython 7.22.0
>>>

2.1.4 简单使用

构造数据包

>>> pkt = IP()/TCP()
>>> pkt.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \
###[ TCP ]### 
     sport     = ftp_data
     dport     = http
     seq       = 0
     ack       = 0
     dataofs   = None
     reserved  = 0
     flags     = S
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = ''

>>> pkt = IP(src = "192.168.1.11", dst = "192.168.1.1")/TCP()
>>> pkt.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 192.168.1.11
  dst       = 192.168.1.1
  \options   \
###[ TCP ]### 
     sport     = ftp_data
     dport     = http
     seq       = 0
     ack       = 0
     dataofs   = None
     reserved  = 0
     flags     = S
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = ''

>>>

发送数据包

发送数据包的函数 说明
sr(pkt) 发送数据包,接收所有返回包
sr1(pkt) 发送数据包,接收一个返回包
send(pkt) 发送数据包,不等待返回包
srp(pkt) 发送2 层数据包,等待回应
sendp(pkt) 发送2 层数据包,不等待返回包
>>> res = sr1(pkt)
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>>

查看返回包

>>> res.show()
###[ IP ]### 
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 44
  id        = 13990
  flags     = 
  frag      = 0
  ttl       = 255
  proto     = tcp
  chksum    = 0x46a4
  src       = 10.9.21.1
  dst       = 10.9.21.111
  \options   \
###[ TCP ]### 
     sport     = http
     dport     = ftp_data
     seq       = 1510518667
     ack       = 1
     dataofs   = 6
     reserved  = 0
     flags     = SA
     window    = 65535
     chksum    = 0x4f9c
     urgptr    = 0
     options   = [('MSS', 1460)]
###[ Padding ]### 
        load      = '\x00\x00'

>>>

2.2 主机存活检测程序

# 04 - 内网主机存活检测程序.py

from scapy.all import *

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

network = "10.9.75."

for host in range(1, 20):
    ip = f"{network}{host}"
    print(f"[-] Trying: {ip}")

    pkt = IP(src = "10.9.75.214", dst = ip)/ICMP()
    res = sr1(pkt, timeout = 0.2, verbose = False)
    if res :
        print(f"[+] Alive: {ip}")
# 04 - 内网主机存活检查程序进阶.py

from scapy.all import *
from scapy.layers.inet import *

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

from termcolor import colored

netmask = "10.9.75."
src = "10.9.75.214"

for i in range(1,50):
    dst = f"{netmask}{i}"
    
    pkt=IP(src=src,dst=dst)/ICMP()
    res = sr1(pkt,timeout=1,verbose=False)

    if res and res.type==0:
        print(colored(f"\n[+] {dst} is ALIVE!","green"))
    else:
        print(f"\r[-] {dst} is NOT ALIVE!",end="")

说明:

  1. from scapy.all import *from scapy.layers.inet import * 引入了 Scapy 库的相关模块和功能,以便使用其中的网络包构造和发送功能。
  2. import logging 引入了 Python 的 logging 模块,用于设置日志记录的级别。
  3. logging.getLogger("scapy.runtime").setLevel(logging.ERROR) 将 Scapy 的日志级别设置为 ERROR,以避免出现冗余的日志信息。
  4. from termcolor import colored 引入了 termcolor 库的 colored 函数,用于在终端输出时设置文本颜色。
  5. netmask 是一个字符串变量,表示局域网的子网掩码。
  6. 使用循环来迭代目标 IP 地址的最后一位,范围是从 1 到 50,不含50。
  7. 在每次循环中,将目标 IP 地址设置为格式化后的值,例如 "10.9.75.1"、"10.9.75.2"等。
  8. 构造一个 ICMP 请求的数据包,其中源 IP 地址为 src,目标 IP 地址为当前迭代的 dst
  9. 使用 sr1() 函数发送数据包并等待响应,超时时间设置为 1 秒。sr1() 函数用于发送数据包并接收第一个响应。
  10. 如果收到响应并且响应类型为 0(ICMP 回显回答),则输出目标 IP 地址为活动状态,将文本着色为绿色。

3. 面向对象编程

3.1 类

类是一类事物的统称,比如学生。对象就是类的实例化。

类有属性(变量),比如学生的姓名、性别、年龄、成绩等,也就是编程里面的变量。

类有方法(函数),比如学生的上课、下课等,也就是编程里面的函数。

3.1.1 创建类

类是一种数据结构,我们可以用它来定义对象,对象把数据值和行为特性融合在一起。Python 使用class 关键字来创建类:通常类名的第一个字母大写,推荐使用驼峰式命名法,单词首字母均大写。类由属性(变量)和方法(动作,函数)组成。

class ClassName(bases):
    'class documentation string'    #'类文档字符串'
    class_suite                     # 类体

3.1.2 init 方法

__init__() 是类的实例(对象)创建后第一个被调用的方法,通常被用来进行对象中属性(变量)的初始化。设置实例的属性可以在实例创建后任意时间进行,但是通常情况下优先在__init__() 方法中实现。

  • 定义类型
  • 实例化对象(创建一个对象)
  • 初始化对象(第一次给对象属性赋值)
# 04 - __init__.py

class Stu():
    def __init__(self,name,sex,age,score):
        self.name=name
        self.sex=sex
        self.age=age
        self.score=score

stu1=Stu(name="ghui",sex=True,age=18,score=59.9)

print(f"{stu1.name}的成绩为:{stu1.score}")

3.2 方法

3.2.1 绑定方法

方法仅仅是类内部定义的函数,方法只有在其所属的类拥有实例时,才能被调用;任何一个方法定义中的第一个参数都是变量self,它表示调用此方法的实例对象就是自己。

类中的方法,也就是类中定义的函数,这个函数第一个参数永远是self,表示自己。

# 05 - 绑定方法.py

import time

class Stu():
    def __init__(self,name,sex,age,score):
        self.name=name
        self.sex=sex
        self.age=age
        self.score=score

    def getScore(self):
        print(f"{self.name}的成绩为: {self.score}")

    def goodGoodStudy(self):
        print("好好学习中...")
        time.sleep(10)
        self.score +=0.1

stu1=Stu(name="ghui",sex=True,age=18,score=59.9)

stu1.getScore()  # ghui的成绩为: 59.9
stu1.goodGoodStudy()   #  好好学习中...
stu1.getScore()    # ghui的成绩为: 60.0

输出结果:

image-20230919145914653

3.3 继承

3.3.1 子类继承

继承描述了基类(祖先)的属性如何遗传给派生类(子孙),子类可以继承它的基类的任何属性,不管是数据属性还是方法。

# 06 - 子类继承.py

import time

class Kid():
    def __init__(self, name = "", sex = "", age = ""):
        self.name = name
        self.age = age
        self.sex = sex

    def play(self):
        print("玩游戏中...")

class Stu(Kid):	 #继承 Kid 类
    def __init__(self,name = "", sex = "", age = "", score = ""):
        Kid.__init__(self, name, sex, age)
        self.score = score

    def get_score(self):
        print(f"{self.name} 的成绩是{self.score}")

    def good_good_study(self):
        print("好好学习中...")
        time.sleep(10)
        self.score += 0.1

stu1 = Stu(name = "张三", sex = True, age = 24, score = 59.9)

stu1.play()  #能够调用父类中的方法

3.3.2 方法重写

如果子类中有和父类同名的方法,父类方法将被覆盖;如果需要访问父类的方法,则要调用一个未绑定的父类方法,明确给出子类的实例。

# 07 - 方法重写.py
 
import time

class Kid():
    def __init__(self, name = "", sex = "", age = ""):
        self.name = name
        self.age = age
        self.sex = sex

    def play(self):
        print("玩游戏中...")

class Stu(Kid):
    def __init__(self,name = "", sex = "", age = "", score = ""):
        Kid.__init__(self, name, sex, age)
        self.score = score

    def get_score(self):
        print(f"{self.name} 的成绩是{self.score}")

    def play(self):   # 父类方法重写
        print("玩QQ飞车中...")
        time.sleep(2)	# 添加 2 秒延迟
        self.score -=10

    def good_good_study(self):
        print("好好学习中...")
        time.sleep(10)
        self.score += 0.1

stu1=Stu(name="张三",sex=True,age=22,score=59.9)

stu1.get_score()    # 张三的成绩是59.9

stu1.good_good_study()  # 好好学习中...
stu1.get_score()    # 张三的成绩是60.0

stu1.play()   # 玩QQ飞车中...
stu1.get_score()   # 张三的成绩是50.0

说明:

import time 引入了 time 模块,用于添加延时。

__init__() 方法是一个构造函数,用于初始化对象的属性。

​ Kid.init(self, name, sex, age) 是在 Stu 类的构造函数中调用了 Kid 类的构造函数来初始化从 Kid 类继承的属性。在 Stu 类中新增了一个 score 属性,并在 __init__() 方法中进行初始化。

错误异常处理与面向对象_第2张图片

3.3.3 多重继承

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

多继承的格式:
class 子类名(父类1, 父类2, …):
子类中的代码

如果继承了多个父类,且父类都有同名方法,则默认只执行第一个父类的

# 08 - 多重继承.py

class A:
    def get(self):
        print("get A")


class B:
    def get(self):
        print("get B")


class C(A, B):
    def __init__(self):
        print("class C")

c = C()
c.get()

输出结果:

image-20230919145001601

另一种情况:

class A:
    def __init__(self):
        print("class A")

class B:
    def __init__(self):
        print("class B")

class C(A, B):
    def get(self):
        print("get C")

c = C()
c.get()

输入结果:

image-20230919145208542

继承顺序交换

class A:
    def get(self):
        print("get A")


class B:
    def get(self):
        print("get B")


class C(B, A):
    def __init__(self):
        print("class C")

c = C()
c.get()

输出结果:

image-20230919145422078

不重复的函数

class A:
    def get(self):
        print("get A")

    def func1(self):
        print("func1")

class B:
    def get(self):
        print("get B")

    def func2(self):
        print("func2")


class C(B, A):
    def __init__(self):
        print("class C")

    def func3(self):
        print("func3")

c = C()
c.func1()
c.func2()
c.func3()

输出结果:

image-20230919145552494

3.4 魔法函数

3.4.1 类和实例的内建函数

函数 作用
issubclass() 判断一个类是另一个类的子类或子孙类
isinstance() 判定一个对象是否是另一个给定类的实例
hasattr() 判断一个对象是否有一个特定的属性
getattr() 获得一个对象的属性值
setattr() 设置一个对象的属性
delattr() 删除一个对象的属性

3.4.2 常用的魔法函数

魔法函数是系统自带的,会在“恰当”的时候自动调用。

基本的魔术方法:

方法 说明
__init__(self) 初始化方法,当实例被创建的时候调用的初始化方法
__call__(self) 允许一个类的实例像函数一样被调用
__str__(self) 定义当被 str() 调用时的行为
__hash__(self) 定义当被 hash() 调用时的行为
__bool__(self) 定义当被 bool() 调用时的行为,应该返回 True 或 False
# 09 - 魔术方法.py

class Test():
    def __init__(self):	#初始化时调用
        print("Function __init__ is called!")

    def __str__(self):  # 对象打印时调用
        return "Why print(self)?"

    def __call__(self):	# 把对象当作函数调用时触发
        print("Why call me like Function?")

t = Test()
print("------------------------")
print(t)
print("------------------------")
t()

执行结果:

错误异常处理与面向对象_第3张图片

私有化

Python 为类元素(属性和方法)的私有性提供初步的形式,由双下划线开始的属性在运行时被“混淆”,所以直接访问是不允许的。

# 10 - 私有化.py


import time

class Stu():
    def __init__(self, name, sex, age, score):
        self.name = name
        self.sex = sex
        self.age = age
        self.__score = score # 设置 score 为私有的,只有在类的内部访问到 score

    def getSocre(self): #我们可以在外部调用内部的getScore方法来访问 Score属性
        print(f"{self.name} 的成绩是{self.__score}")

    def goodGoodStudy(self):
        print("好好学习中...")
        time.sleep(10)
        self.__score += 0.1

stu2 = Stu(name = "GHUI", sex = True, age = 24, score = 89.9)


# print(stu2.score) #外部不能直接访问类的私有属性
stu2.getSocre() #调用类的内部方法来访问类的私有属性

执行结果:

image-20230919175717642

你可能感兴趣的:(Python,灰帽编程,python)