Python 编程语言

霍格沃兹测试开发 ceshiren.com

目录

  • python 内置装饰器
  • python 类型注解
  • python 模块与名
  • 错误与异常

内置类装饰器

  • 不用实例化、直接调用
  • 提升代码的可读性
内置装饰器 含义
classmethod 类方法
staticmethod 静态方法

普通方法

  • 定义:

    • 第一个参数为 self,代表 实例本身
  • 调用:

    • 要有实例化的过程,通过 实例对象.方法名 调用
# 1. 定义
class MethodsDemo:
    param_a = 0 #类变量
    def normal_demo(self): # 定义一个类方法,第一个参数必须为self
        """
        普通方法
        :return:
        """
        print("这是一个普通方法", self.param_a)
# 2. 调用
md = MethodsDemo()
md.normal_demo()

类方法

  • 定义:
    • 使用 @classmethod 装饰器,第一个参数为类本身,所以通常使用 cls 命名做区分(非强制)
    • 在类内可以直接使用类方法或类变量,无法直接使用实例变量或方法
  • 调用:
    • 无需实例化,直接通过 类.方法名 调用,也可以通过 实例.方法名 调用
# 1. 类的定义
class MethodsDemo:
    param_a = 0
    # 定义类方法必须加 classmethod装饰器
    @classmethod
    def classmethod_demo(cls):
        """
        类方法,第一个参数需要改为cls
        :return:
        """
        print("类方法", cls.param_a)
# 2. 类的调用
MethodsDemo.classmethod_demo() # 无需实例化,直接调用

练习

  • 定义三个类方法,分别 返回你的姓名,和昵称,以及个人介绍
  • 调用这三个方法,打印内容

实际案例

  • 右边的代码实现的需求是格式化输出时间
  • 如果现在需求变更,输入 年、月、日 没法保证格式统一,可能是 json,可能是其他格式的字符串,在不修改构造函数的前提下,如何更改代码
class DateFormat:
    def __init__(self, year=0, month=0, day=0):
        self.year = year
        self.month = month
        self.day = day
    def out_date(self):
        return f"输入的时间为{self.year}年,{self.month}月,{self.day}日"
   
year, month, day = 2017, 7, 1
demo = DateFormat(year, month, day)
print(demo.out_date())  

练习

  • 传递一个字符串格式的时间,输出 输入的时间为2021年,12月,21日 这种格式

静态方法

  • 定义:
    • 使用 @staticmethod 装饰器,没有和类本身有关的参数
    • 无法直接使用任何类变量、类方法或者实例方法、实例变量
  • 调用:
    • 无需实例化,直接通过 类.方法名 调用,也可以通过 实例.方法名 调用
# 1. 定义
class MethodsDemo:
    param_a = 0
    @staticmethod
    def static_demo():
        """
        静态方法
        :return:
        """
        print("静态方法") # 无法直接调用类变量
# 2. 调用
MethodsDemo.static_demo()

静态方法实际案例

  • 此方法没有任何和实例、类相关的部分,可以作为一个独立函数使用
  • 某些场景下,从业务逻辑来说又属于类的一部分
  • 例子:简单工厂方法
# static 使用场景
class HeroFactory:
    # staticmethod 使用场景,
    # 方法所有涉及到的逻辑都没有使用实例方法或者实例变量的时候
    # 伪代码
    @staticmethod
    def create_hero(hero):
        if hero == "ez":
            return EZ()
        elif hero == "jinx":
            return Jinx()
        elif hero == "timo":
            return Timo()
        else:
            raise Exception("此英雄不在英雄工厂当中")

练习

  • 对打游戏,每次有两个英雄对打
  • 游戏开始,提示“游戏开始”
  • 两个英雄开始对打,提示“本轮比赛开始,first hero VS second hero ”
  • 游戏结束 ,提示“游戏结束”

普通方法、类方法、静态方法

名称 定义 调用 关键字 使用场景
普通方法 至少需要一个参数 self 实例名.方法名() 方法内部涉及到实例对象属性的操作
类方法 至少需要一个 cls 参数 类名.方法名() 或者实例名.方法名() @classmethod 如果需要对类属性,即静态变量进行限制性操作
静态方法 无默认参数 类名.方法名() 或者实例名.方法名() @staticmethod 无需类或实例参与

@property 创建只读属性

  • @property 装饰器会将方法转换为相同名称的只读属性
    • 加了 @property 之后方法就变成了属性
    • 使用属性一样调用(调用的时候不需要加(), 加了() 会报错)
  • 可以与所定义的属性配合使用,这样可以防止属性被修改。

实例一

  • 加了 @property 之后方法就变成了属性
  • 使用属性一样调用(调用的时候不需要加(), 加了() 会报错)
class DecoratorProperty:
    # 加了 `@property` 之后方法就变成了属性,
    @property
    def method_with_property(self):
        return 15

    def method_without_property(self):
        return 15

#使用属性一样调用(调用的时候不需要加(), 加了() 会报错)
print(DecoratorProperty().method_with_property)
print(DecoratorProperty().method_without_property())

实例二

  • 可以与定义的属性配合使用,防止属性被修改
class DecoratorProperty:
    def __init__(self):
        self._image = 1
        self._label = 2
    @property
    def image(self):
        # 方法加入@property后,这个方法相当于一个属性,这个属性可以让用户进行使用,而且用户有没办法随意修改。
        return self._image

    @property
    def label(self):
        return self._label

dec = DecoratorProperty()
print(dec.image)
print(dec.label)

练习

  • 定义两个属性方法,分别用来提供姓名和个人介绍
  • 通过实例,调用这些属性方法来获取到这些信息

练习

  • 定义三个类
      1. Person 类
      • 属性:姓名(不能改变),性别 (不能改变)
      • 方法:吃饭,睡觉,跑步
      1. 学生类(继承 Person)
      • 属性:学号(不能改变)
      • 方法:跑步(类方法:早晚跑步),打游戏(静态方法) ,学习
      1. 家长类(继承 Person)
      • 属性:职业,工资(隐藏起来), 孩子(学生)(不能改变)
      • 方法:工作
  • 调用
      1. 创建一个家长对象
      1. 创建一个学生对象
      1. 一个家长对应一个学生
      1. 打印家长的职业和工作,以及它的孩子信息(学号,姓名,性别,以及 运动,游戏,学习情况)

python 类型注解

类型提示

方法参数类型注解

#  无类型注解
def greeting(name) :
    return 'Hello ' + name
#  有类型注解
def greeting(name: str) -> str:
    return 'Hello ' + name

类型注解好处

  • 明确参数类型,提示相应的属性方法
  • 明确返回数据的类型, 可以提示相应的方法
  • 提高可读性
  • 增加代码提示(返回的数据)

复杂的类型


Vector = list[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])

为什么要用类型注解

python 模块与包

python 模块与包

  • 项目目录结构
  • 模块定义,
  • 文件引用,import ,相对路径与绝对路径

python 的程序结构

  • 组成
    • package 包
    • module 模块
    • function 方法

模块

  • 包含 python 定义和语句的文件
  • .py 文件 就是一个模块
  • 可以作为脚本运行
  • 能够完成一定的功能,同时为其它的模块提供一些服务
  • 定义变量,方法,类

  • 存放多个模块/包
  • 必须存在 init.py 文件

模块导入

  • 格式:

    • import 模块名
    • from <模块名> import <方法| 变量| 类>
    • from <模块名> import *
  • 注意:

    • 同一个模块写多次,只被导入一次
    • import 应该放在代码的顶端

模块分类

  • 系统内置模块(系统模块 sys, 时间 time ,操作系统相关的模块 os, 正则相关的模块 re )
  • 第三方的模块(通过 pip 能够安装的模块)
  • 自定义模块( 自定义模块,特定项目上的需要的功能点)

系统内置模块

  • 系统模块不需要额外的安装
  • 导入之后
    • 未使用 在 IDE 中是灰色的
    • 使用了在 IDE 中就是正常颜色
  • 不建议一行导入多个模块

第三方开源模块

  • 通过 pip 直接安装到 python 系统环境/虚拟环境中 pip install pyyaml
  • pycharm 界面安装
    • settings 里安装
    • 界面上提示安装

自定义模块

  • 开发人员自己编写的模块,对某段逻辑或某些函数进行封装后供其他模块/函数调用。
  • 优势
    • 实现开源模块不具备的功能
    • 模块复用

练习

  • 自己写个模块 student_info.py,编写两个方法, 一个是提供姓名,一个是提供学校和专业,
  • 再写个模块 run.py, 调用模块 1 中的方法,显示当前学员的姓名为XXX, 当前学员的学校为XXX, 专业为xxx

自定义模块与系统模块重名

  • 不要与系统自带模块/ 安装的第三方开源模块重名

搜索路径

python 解释器对模块位置的搜索顺序是:

  • 包含输入脚本的目录(如果未指定,则为当前目录 )
  • PYTHONPATH (目录名称列表,语法与 shell 变量相同 PATH)

练习

  • 创建一个模块 utils.py,连接数据库功能(功能留空)
  • 在另一个模块中调用这个功能

总结

  • 代码的可维护性
  • 提升编码效率
  • 函数名可重复(起名避免与系统重复)

错误与异常

目录

  • 错误与异常
  • 异常类型
  • 异常捕获,异常处理
  • try-catch finally 使用
  • raise 使用

错误

  • 语法错误
  • 逻辑错误
  • 系统错误

异常

常见的异常类型

  • 除数为 0 异常
  • 名称异常(名字写错了)
  • 索引无效异常 (列表的索引 )
  • 键值无效异常(字典键值)
  • 值异常 (例如: 类型转换 a=int(input(“输入一个值:”)))
  • 属性异常(python 里会定义一些常量的属性值 ,在更改这些常量的时候会发生异常)
  • 迭代器异常,在迭代的时候出现的异常

捕获异常 - 格式一

try:
    可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
    处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
    处理异常的代码块2
except  [Exception]:
    处理其它异常

捕获异常 - 格式二

try:
    result = 20 / int(input('请输入除数:'))
    print(result)
except ValueError:
    print('必须输入整数')
except ArithmeticError:
    print('算术错误,除数不能为 0')
else:
    print('没有出现异常')
print("继续执行")

捕获异常 - 格式三

try:
    a = int(input("请输入 a 的值:"))
    print(20/a)
except:
    print("发生异常!")
else:
    print("未发生异常")
finally :
    print("执行 finally 块中的代码")

抛出异常

  • 格式:raise 异常名(提示信息)
def set_age(num):

    if num<=0 or num >120:
        raise ValueError(f"值错误:  {num}")
    else:
        print(f"设置的年龄为:{num}")

set_age(-1)

自定义异常

  • 继承 Exception 类
  • 结合 raise 主动抛出异常

class MyError(Exception):
    def __init__(self, value ):
        self.value = value

def set_age(num):

    if num<=0 or num >120:
        raise MyError(f"值错误:  {num}")
    else:
        print(f"设置的年龄为:{num}")

set_age(-1)

练习异常

  • 判断学员信息是否合理(比如为 Null)
  • 不合理的学员,提示信息“参数 name = {name} 不是合理数据。”

实战练习猜大小

  • 玩法:
    • 系统或人工随机生成一个数字(范围 1~10)
    • 猜的不对,系统会提示大了或者小了
    • 猜对则提示【成功】游戏结束
    • 猜错则继续猜