- 验证实验
让我用一个简单的例子证明:
python
class BasePage:
def init(self, page):
self.page = page # 在父类初始化中设置
print("父类初始化完成")
class LoginPage1(BasePage):
def init(self, page):
# 不调用父类初始化
print("子类1初始化,但不调用super")
def try_use_page(self):try:print(f"page属性: {self.page}") # 会报错!except AttributeError as e:print(f"错误: {e}")
class LoginPage2(BasePage):
def init(self, page):
super().init(page) # 调用父类初始化
print("子类2初始化,调用了super")
def try_use_page(self):try:print(f"page属性: {self.page}") # 正常工作except AttributeError as e:print(f"错误: {e}")
测试
page_obj = "模拟的page对象"
login1 = LoginPage1(page_obj)
login1.try_use_page()
输出: 错误: 'LoginPage1' object has no attribute 'page'
login2 = LoginPage2(page_obj)
login2.try_use_page()
输出: page属性: 模拟的page对象
- 为什么必须调用 super().init()
Python 的继承机制
python
class Parent:
def init(self, value):
self.value = value # 父类设置属性
print("父类初始化")
class Child(Parent):
def init(self, value):
# 如果没有调用 super().init()
# 父类的 init 永远不会执行!
print("子类初始化")
# 此时 self.value 不存在!
child = Child("test")
print(hasattr(child, 'value')) # 输出: False
正确的做法
python
class Child(Parent):
def init(self, value):
super().init(value) # 必须先调用父类初始化
print("子类初始化")
# 现在 self.value 可用了
child = Child("test")
print(hasattr(child, 'value')) # 输出: True
3. 在 Playwright 页面对象中的具体应用
python
from playwright.sync_api import Page
class BasePage:
def init(self, page: Page):
self.page = page # 关键:在这里设置 self.page
self.base_url = "https://example.com"
def navigate(self, path=""):self.page.goto(f"{self.base_url}{path}")
class LoginPage(BasePage):
def init(self, page: Page):
# 必须调用父类初始化,否则 self.page 不存在!
super().init(page)
# 现在可以安全地使用 self.pageself.username_input = self.page.get_by_placeholder("请输入11位手机号")self.password_input = self.page.get_by_placeholder("请输入密码")def login(self, username, password):# 使用 self.page 是安全的,因为父类初始化已调用self.username_input.fill(username)self.password_input.fill(password)
- 如果不调用 super().init() 会发生什么
python
class BadLoginPage(BasePage):
def init(self, page: Page):
# 忘记调用 super().init(page)
self.username_input = self.page.get_by_placeholder("请输入11位手机号") # 报错!
# AttributeError: 'BadLoginPage' object has no attribute 'page' - 什么时候可以不用调用 super().init()
只有当父类没有 init 方法或者父类的 init 方法不需要参数时,才可以不调用:
python
class SimpleParent:
# 没有 init 方法
pass
class SimpleChild(SimpleParent):
def init(self):
# 可以不调用 super().init()
self.value = "hello"
child = SimpleChild()
print(child.value) # 正常工作
6. 最佳实践
总是调用父类初始化
python
class GoodPage(BasePage):
def init(self, page: Page):
super().init(page) # 总是先调用父类
# 然后进行子类的初始化
self.setup_selectors()
self.setup_events()
def setup_selectors(self):self.username_input = self.page.get_by_placeholder("请输入11位手机号")
使用参数传递
python
class BasePage:
def init(self, page: Page, config=None):
self.page = page
self.config = config or {}
class LoginPage(BasePage):
def init(self, page: Page):
# 传递所有必要参数给父类
super().init(page, config={"timeout": 5000})
总结
您的问题非常关键!是的,子类必须显式调用 super().init(page) 才能使用父类中定义的 self.page,因为:
继承不会自动调用父类构造函数
self.page 是在父类 init 中设置的
如果不调用父类 init,这些属性就不会存在
这是 Python(和大多数 OOP 语言)的基本规则