Python 面向对象详解
从概念到实战,一文明白 OOP
面向对象(OOP)是一种对现实世界理解和抽象的方法。Python 是一门面向对象的语言,掌握 OOP 思维,是从"写脚本"到"写工程"的关键一步。
面向对象编程简单来说就是一种封装代码的方式,一句经典的描述——一切皆对象。对象是指在现实生活中能够看得见摸得着的具体事物。
| |
|---|
| 描述具有相同属性和方法的集合,简单来说就是一个模板,通过它来创建对象 |
| |
| |
| 定义在类中且在函数之外的变量,在所有实例化对象中公用 |
| |
🔒 封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,提高复用性和安全性。
🔗 继承
一个类继承一个基类便可拥有基类的属性和方法,提高代码的复用性。
🔀 多态
父类定义的引用变量可以指向子类的实例对象,提高程序的拓展性。
Python 中使用 class 关键字定义类,语法如下:
class Cat: # 类变量 color = 'black' # 构造方法,实例化时自动调用 def __init__(self, name): self.name = name # 自定义方法 def eat(self, food): self.food = food print(self.name, '正在吃' + food)# 直接通过类名访问类变量print('color-->', Cat.color)
🔑 关键要点
① __init__() 是构造方法,类实例化时自动调用② self 代表类的实例,是方法的第一个参数③ 类变量可通过 类名.属性名 直接访问
在属性名或方法名前加两条下划线__ 即可定义为私有,外部不能直接访问。
class Cat: # 私有类变量 __cid = '1' # 私有方法 def __run(self, speed): print('__cid是' + self.__cid + '的猫', '以' + speed + '的速度奔跑') # 公开方法,内部调用私有成员 def run(self, speed): self.__run(speed)# ❌ 外部直接访问会报错# print(Cat.__cid) # AttributeError# c.__run('50迈') # AttributeError# ✅ 通过公开方法间接访问c = Cat('Tom')c.run('50迈')# 输出:__cid是1的猫 以50迈的速度奔跑
💡 小贴士
私有属性和方法并非"绝对不可访问"。Python 的私有机制只是名称改写(Name Mangling),实际上 __cid 被改写为 _Cat__cid,通过 c._Cat__cid 仍可访问。但这是语言实现细节,日常编码中应遵守封装约定,不要这样用。
创建对象也称类的实例化,创建后可以访问属性和调用方法:
# 创建对象(实例化)c = Cat('Tom')# 访问属性print('name-->', c.name) # name--> Tomprint('color-->', c.color) # color--> black# 调用方法c.eat('鱼') # Tom 正在吃鱼
⚠️ 踩坑经验
忘记传 self 是新手最常犯的错误。调用方法时 Python 会自动将对象作为第一个参数传入,定义方法时必须写 self,但调用时不需要手动传。
Python 支持类的继承,而且支持多继承,子类可以拥有父类的属性和方法,也可以重写父类方法。
# 波斯猫类(继承 Cat)class PersianCat(Cat): def __init__(self, name): self.name = name def eat(self, food): print(self.name, '正在吃' + food)# 加菲猫类(继承 Cat)class GarfieldCat(Cat): def __init__(self, name): self.name = name def run(self, speed): print(self.name, '正在以' + speed + '的速度奔跑')# 单继承class SingleCat(PersianCat): pass# 多继承class MultiCat(PersianCat, GarfieldCat): pass# 调用sc = SingleCat('波斯猫1号')sc.eat('鱼') # 波斯猫1号 正在吃鱼mc = MultiCat('波斯加菲猫1号')mc.eat('鱼') # 波斯加菲猫1号 正在吃鱼mc.run('50迈') # 波斯加菲猫1号 正在以50迈的速度奔跑
如果继承的父类方法不能满足需求,子类可以重写父类方法:
class SingleCat(PersianCat): # 重写父类 eat 方法 def eat(self, food): print(self.name, '正在吃' + food, '十分钟后', self.name + '吃饱了')sc = SingleCat('波斯猫1号')sc.eat('鱼')# 输出:波斯猫1号 正在吃鱼 十分钟后 波斯猫1号吃饱了
💡 小贴士
重写方法后如果仍想调用父类的原始逻辑,可以用 super():super().eat(food),在父类逻辑基础上扩展,而不是完全替换。
⚠️ 踩坑经验
多继承时如果多个父类有同名方法,Python 按 MRO(方法解析顺序) 决定调用哪个,顺序为从左到右。可以用 类名.__mro__ 查看继承链。多继承用不好容易出问题,能用组合解决的尽量用组合。
在自动化测试中,OOP 是页面对象模式(POM)的基础。通过继承和封装,可以大幅减少重复代码:
# 基类:封装通用操作class BasePage: def __init__(self, driver): self.driver = driver def find(self, locator): """查找元素""" return self.driver.find_element(*locator) def click(self, locator): """点击元素""" self.find(locator).click() def input_text(self, locator, text): """输入文本""" element = self.find(locator) element.clear() element.send_keys(text)# 子类:继承基类,实现具体页面class LoginPage(BasePage): # 私有定位器 __username_input = ('id', 'username') __password_input = ('id', 'password') __login_btn = ('id', 'login-btn') def login(self, username, password): """登录操作""" self.input_text(self.__username_input, username) self.input_text(self.__password_input, password) self.click(self.__login_btn)# 使用page = LoginPage(driver)page.login('admin', '123456')
💡 给测试工程师的建议
1. 用继承做 BasePage:封装通用操作(查找、点击、等待),子类只需关注页面特有逻辑2. 用私有属性藏定位器:页面元素定位器用 __ 前缀保护,避免外部随意修改3. 用多态做多端适配:定义 WebPage 和 AppPage 同名方法,一套用例适配多端
面向对象是 Python 工程化的核心思维,也是自动化测试框架设计的基石。掌握类、对象、继承和多态,才能真正写出可维护、可扩展的测试项目!
Python 学习笔记系列 | 第十一篇