当前位置:首页>python>Python(二十八) 类的封装详解

Python(二十八) 类的封装详解

  • 2026-08-18 23:11:10
Python(二十八) 类的封装详解
Python(二十八) 类的封装详解
1. 什么是封装

封装是面向对象编程中的一个重要思想。

通俗地说:

封装就是把数据和操作数据的方法放在一个类里面,
并且控制外部代码如何访问和修改这些数据。

举一个生活中的例子:

手机把很多复杂零件封装在内部。
用户不用关心芯片、电池、电路板怎么工作。
用户只需要通过按钮、屏幕、充电口来使用手机。

在程序中也是一样。

一个对象内部可能有很多数据,但外部代码不应该随便乱改。

我们希望:

重要数据由类自己管理。
外部只能通过类提供的方法来访问和修改。

这就是封装。

2. 为什么需要封装

先看一个没有封装的例子。

classStudent:
def__init__(self, name, score):
self.name = name
self.score = score
stu = Student("张三"90)
stu.score = -100
print(stu.name)
print(stu.score)

输出:

张三
-100

问题出现了:

学生成绩被改成了 -100。
这明显不合理。

因为成绩通常应该在 0 到 100 之间。

如果外部代码可以随便修改对象属性,就容易产生不合法的数据。

封装可以解决这个问题。

我们可以让外部不要直接修改成绩,而是通过方法修改。

classStudent:
def__init__(self, name, score):
self.name = name
self.score = score
defupdate_score(self, new_score):
if0 <= new_score <= 100:
self.score = new_score
else:
print("成绩必须在 0 到 100 之间")
stu = Student("张三"90)
stu.update_score(95)
stu.update_score(-100)
print(stu.score)

输出:

成绩必须在 0 到 100 之间
95

这样就避免了不合理的数据进入对象。

3. 封装解决什么问题

封装主要解决三个问题。

3.1 让数据更安全

不让外部随便修改重要数据。

例如:

银行账户余额不能被随便改成负数。
学生成绩不能超过 100。
商品库存不能小于 0。
3.2 让代码更清晰

把数据和操作数据的方法放在一个类中。

例如:

BankAccount 类中放余额数据,也放存款和取款方法。
Student 类中放成绩数据,也放修改成绩和判断是否及格的方法。
3.3 让外部使用更简单

使用者不需要知道对象内部怎么实现,只需要知道可以调用哪些方法。

例如:

account.deposit(100)
account.withdraw(50)

外部只需要知道:

deposit() 可以存钱。
withdraw() 可以取钱。

不用关心余额在内部怎么保存。

4. 封装的核心思想

封装可以用一句话总结:

内部数据自己管,外部访问走方法。

也可以这样理解:

不该让外部直接碰的数据,就藏起来。
外部需要使用时,提供合适的方法。

封装不是为了把所有东西都藏起来。

封装是为了让数据访问更合理、更安全、更清晰。

5. Python 中的访问控制

在一些编程语言中,属性和方法有严格的访问权限,例如:

public
private
protected

Python 的访问控制没有那么严格。

Python 更强调约定。

常见命名方式:

写法
名称
含义
name
公开属性
外部可以直接访问
_name
受保护属性
约定内部使用,外部不建议直接访问
__name
私有属性
名称会被改写,外部不容易直接访问

示例:

classStudent:
def__init__(self):
self.name = "张三"
self._age = 18
self.__score = 90

这里:

name 是公开属性。
_age 是受保护属性。
__score 是私有属性。
6. 公开属性

公开属性就是普通属性。

外部可以直接访问和修改。

classStudent:
def__init__(self, name):
self.name = name
stu = Student("张三")
print(stu.name)
stu.name = "李四"
print(stu.name)

输出:

张三
李四

公开属性适合保存那些允许外部直接访问和修改的数据。

例如:

姓名
标题
颜色
普通状态

但是如果一个属性需要限制修改规则,就不适合完全公开。

7. 受保护属性

受保护属性通常以一个下划线 _ 开头。

例如:

classStudent:
def__init__(self, name, score):
self.name = name
self._score = score

这里的 _score 表示:

这个属性主要给类内部使用。
外部不建议直接访问。

注意:

一个下划线开头只是约定,不是强制限制。

也就是说,外部仍然可以访问。

classStudent:
def__init__(self, name, score):
self.name = name
self._score = score
stu = Student("张三"90)
print(stu._score)

输出:

90

虽然可以访问,但不推荐。

看到 _score,意思是作者提醒你:
这个属性是内部使用的,外部最好不要直接动。
8. 私有属性

私有属性以两个下划线 __ 开头。

示例:

classStudent:
def__init__(self, name, score):
self.name = name
self.__score = score
stu = Student("张三"90)
print(stu.name)
print(stu.__score)

运行后:

print(stu.name) 可以正常输出。
print(stu.__score) 会报错。

因为 __score 是私有属性,外部不能直接用 对象.__score 访问。

私有属性适合保存不希望外部直接修改的数据。

例如:

账户余额
密码
内部状态
需要校验的数据
9. 私有属性的作用

私有属性的作用不是为了绝对安全,而是为了限制外部随意访问。

例如:

classBankAccount:
def__init__(self, owner, balance):
self.owner = owner
self.__balance = balance
account = BankAccount("张三"1000)
print(account.owner)
print(account.__balance)

owner 可以访问。

__balance 不能直接访问。

这样做的目的是:

账户所有人可以公开。
账户余额不应该让外部随便改。

如果余额可以被随便改:

account.balance = -999999

就会产生严重问题。

10. 私有属性并不是绝对安全

Python 中的私有属性不是真正意义上的绝对隐藏。

Python 会把私有属性名做名称改写。

例如:

classStudent:
def__init__(self):
self.__score = 90
stu = Student()

__score 在内部大致会被改写成:

_Student__score

所以 technically 可以这样访问:

print(stu._Student__score)

但是非常不推荐这样写。

双下划线不是保险箱。
它是一种名称保护机制。
正常代码不要绕过它。
11. 私有属性的正确访问方式

如果外部需要读取私有属性,应该提供公开方法。

例如:

classStudent:
def__init__(self, name, score):
self.name = name
self.__score = score
defget_score(self):
returnself.__score
stu = Student("张三"90)
print(stu.get_score())

输出:

90

这里:

__score 是私有属性。
get_score() 是公开方法。
外部通过 get_score() 读取成绩。
12. 私有属性的正确修改方式

如果外部需要修改私有属性,也应该提供方法。

示例:

classStudent:
def__init__(self, name, score):
self.name = name
self.__score = score
defget_score(self):
returnself.__score
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩必须在 0 到 100 之间")
stu = Student("张三"90)
stu.set_score(95)
print(stu.get_score())
stu.set_score(-10)
print(stu.get_score())

输出:

95
成绩必须在 0 到 100 之间
95

这样做的好处是:

外部不能随便乱改成绩。
必须通过 set_score() 方法。
set_score() 可以检查数据是否合法。
13. getter 和 setter

在面向对象中,读取属性的方法通常叫 getter。

修改属性的方法通常叫 setter。

例如:

defget_score(self):
returnself.__score

这是 getter。

defset_score(self, score):
self.__score = score

这是 setter。

完整示例:

classStudent:
def__init__(self, score):
self.__score = score
defget_score(self):
returnself.__score
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩不合法")
stu = Student(80)
print(stu.get_score())
stu.set_score(90)
print(stu.get_score())

输出:

80
90
getter 用来读。
setter 用来改。
改的时候可以顺便做检查。
14. 使用 property

getter 和 setter 很清楚,但调用起来稍微有点麻烦。

stu.get_score()
stu.set_score(90)

Python 提供了 property,可以让方法像属性一样使用。

示例:

classStudent:
def__init__(self, score):
self.__score = score
    @property
defscore(self):
returnself.__score
    @score.setter
defscore(self, value):
if0 <= value <= 100:
self.__score = value
else:
print("成绩必须在 0 到 100 之间")
stu = Student(80)
print(stu.score)
stu.score = 95
print(stu.score)
stu.score = 150
print(stu.score)

输出:

80
95
成绩必须在 0 到 100 之间
95

这里看起来像直接访问属性:

stu.score

其实背后调用的是方法。

15. property 的好处

property 的好处是:

外部使用起来像普通属性。
内部仍然可以做数据校验和控制。

例如:

stu.score = 95

看起来像直接赋值。

但实际上会调用:

@score.setter
defscore(self, value):
    ...

这就实现了:

外部用法简单。
内部控制严格。
16. 只读属性

如果只写 @property,不写 setter,那么这个属性就是只读的。

示例:

classCircle:
def__init__(self, radius):
self.radius = radius
    @property
defarea(self):
return3.14 * self.radius * self.radius
circle = Circle(5)
print(circle.area)

输出:

78.5

如果尝试修改:

circle.area = 100

会报错。

因为 area 是根据 radius 计算出来的,不应该直接修改。

这种场景很适合使用只读属性。

能读但不能改,就是只读属性。
17. 计算属性

有些属性并不是直接保存的,而是根据其他属性计算出来的。

例如矩形面积:

classRectangle:
def__init__(self, width, height):
self.width = width
self.height = height
    @property
defarea(self):
returnself.width * self.height
rect = Rectangle(34)
print(rect.area)

输出:

12

这里 area 没有直接保存。

它是通过:

self.width * self.height

计算出来的。

这种方式可以保证:

只要 width 或 height 变化,area 也会自动得到新的计算结果。
18. 私有方法

除了私有属性,也可以定义私有方法。

私有方法以两个下划线 __ 开头。

示例:

classStudent:
def__init__(self, name, score):
self.name = name
self.__score = score
def__check_score(self, score):
return0 <= score <= 100
defset_score(self, score):
ifself.__check_score(score):
self.__score = score
else:
print("成绩不合法")
defget_score(self):
returnself.__score
stu = Student("张三"80)
stu.set_score(90)
print(stu.get_score())

输出:

90

这里:

__check_score() 是私有方法。
它只给类内部使用。
外部不需要直接调用。

如果外部这样调用:

stu.__check_score(90)

会报错。

19. 私有方法适合放什么

私有方法通常用于类内部的小步骤。

例如:

检查成绩是否合法
格式化数据
计算内部结果
校验密码格式
处理内部状态

示例:

classUser:
def__init__(self, username, password):
self.username = username
self.__password = password
def__check_password_length(self, password):
returnlen(password) >= 6
defchange_password(self, new_password):
ifself.__check_password_length(new_password):
self.__password = new_password
print("密码修改成功")
else:
print("密码长度不能少于 6 位")
user = User("alice""123456")
user.change_password("abc")
user.change_password("abcdef")

输出:

密码长度不能少于 6 位
密码修改成功
20. 封装中的公开接口

封装后,外部代码通过类提供的公开方法来使用对象。

这些公开方法可以理解为对象的“接口”。

例如:

classBankAccount:
def__init__(self, owner, balance):
self.owner = owner
self.__balance = balance
defdeposit(self, money):
if money > 0:
self.__balance += money
else:
print("存款金额必须大于 0")
defwithdraw(self, money):
if money <= 0:
print("取款金额必须大于 0")
elif money > self.__balance:
print("余额不足")
else:
self.__balance -= money
defget_balance(self):
returnself.__balance

外部使用:

account = BankAccount("张三"1000)
account.deposit(500)
account.withdraw(200)
print(account.get_balance())

外部只需要知道:

deposit() 存钱。
withdraw() 取钱。
get_balance() 查看余额。

不需要知道余额在内部如何保存。

这就是封装带来的好处。

21. 银行账户案例

下面是一个比较完整的封装案例。

classBankAccount:
def__init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
defdeposit(self, money):
if money <= 0:
print("存款金额必须大于 0")
return
self.__balance += money
print(f"成功存入 {money} 元")
defwithdraw(self, money):
if money <= 0:
print("取款金额必须大于 0")
return
if money > self.__balance:
print("余额不足")
return
self.__balance -= money
print(f"成功取出 {money} 元")
defget_balance(self):
returnself.__balance
account = BankAccount("张三"1000)
account.deposit(500)
account.withdraw(300)
account.withdraw(2000)
print(account.get_balance())

输出:

成功存入 500 元
成功取出 300 元
余额不足
1200

这个类中:

owner 是公开属性。
__balance 是私有属性。
deposit() 是公开方法。
withdraw() 是公开方法。
get_balance() 是公开方法。

为什么 __balance 要私有?

因为余额不能让外部随便改。
必须通过存款和取款方法按规则修改。
22. 学生成绩案例
classStudent:
def__init__(self, name, score):
self.name = name
self.__score = 0
self.set_score(score)
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩必须在 0 到 100 之间")
defget_score(self):
returnself.__score
defis_passed(self):
returnself.__score >= 60
stu = Student("张三"90)
print(stu.get_score())
print(stu.is_passed())
stu.set_score(150)
print(stu.get_score())

输出:

90
True
成绩必须在 0 到 100 之间
90

这里有一个细节:

self.__score = 0
self.set_score(score)

先给 __score 一个默认值,然后通过 set_score() 设置真实成绩。

这样创建对象时也会进行成绩校验。

23. 使用 property 改写学生成绩案例
classStudent:
def__init__(self, name, score):
self.name = name
self.__score = 0
self.score = score
    @property
defscore(self):
returnself.__score
    @score.setter
defscore(self, value):
if0 <= value <= 100:
self.__score = value
else:
print("成绩必须在 0 到 100 之间")
defis_passed(self):
returnself.__score >= 60
stu = Student("张三"90)
print(stu.score)
print(stu.is_passed())
stu.score = 150
print(stu.score)
stu.score = 95
print(stu.score)

输出:

90
True
成绩必须在 0 到 100 之间
90
95

这个版本中:

外部使用 stu.score,看起来像普通属性。
内部实际通过 property 控制读写。
24. 商品库存案例

商品库存不能小于 0

可以使用封装来控制。

classProduct:
def__init__(self, name, price, stock):
self.name = name
self.price = price
self.__stock = 0
self.add_stock(stock)
defadd_stock(self, count):
if count > 0:
self.__stock += count
else:
print("增加库存数量必须大于 0")
defsell(self, count):
if count <= 0:
print("销售数量必须大于 0")
elif count > self.__stock:
print("库存不足")
else:
self.__stock -= count
print(f"成功卖出 {count} 件")
defget_stock(self):
returnself.__stock
product = Product("苹果"5100)
product.sell(3)
product.sell(200)
product.add_stock(50)
print(product.get_stock())

输出:

成功卖出 3 件
库存不足
147

这里:

库存通过 __stock 私有保存。
外部不能直接乱改库存。
增加库存用 add_stock()。
销售商品用 sell()。
查看库存用 get_stock()。
25. 用户密码案例

密码不应该随便被外部读取。

可以这样设计:

classUser:
def__init__(self, username, password):
self.username = username
self.__password = password
defcheck_password(self, password):
returnself.__password == password
defchange_password(self, old_password, new_password):
ifnotself.check_password(old_password):
print("原密码错误")
return
iflen(new_password) < 6:
print("新密码长度不能少于 6 位")
return
self.__password = new_password
print("密码修改成功")
user = User("alice""123456")
print(user.check_password("111111"))
print(user.check_password("123456"))
user.change_password("111111""abcdef")
user.change_password("123456""abc")
user.change_password("123456""abcdef")

输出:

False
True
原密码错误
新密码长度不能少于 6 位
密码修改成功

这个案例中:

密码是私有属性。
外部不能直接读取密码。
只能检查密码是否正确,或按规则修改密码。
26. 封装和普通属性的选择

不是所有属性都必须写成私有属性。

如果属性很普通,外部直接访问没有风险,可以使用公开属性。

例如:

classBook:
def__init__(self, title, author):
self.title = title
self.author = author

这里 title 和 author 公开通常没问题。

如果属性需要校验,或者不希望外部直接修改,就可以封装。

例如:

成绩
余额
库存
密码
年龄
价格

这些数据通常需要规则限制。

能随便读写的数据,可以公开。
需要规则控制的数据,适合封装。
27. 封装不是越多越好

初学者容易产生一种误解:

所有属性都必须写成 __私有属性。

这不是必须的。

封装的目的不是让代码变复杂。

封装的目的是:

保护重要数据。
隐藏内部细节。
让外部使用更清晰。

如果一个属性没有复杂规则,公开使用也可以。

例如:

classPoint:
def__init__(self, x, y):
self.x = x
self.y = y

对于简单坐标点,直接公开 x 和 y 通常很自然。

28. 封装中的命名习惯

常见命名建议:

类型
示例
说明
公开属性
name
外部可以直接访问
受保护属性
_score
约定内部使用
私有属性
__balance
外部不应直接访问
公开方法
deposit()
给外部调用
私有方法
__check_money()
类内部使用

示例:

classBankAccount:
def__init__(self, owner, balance):
self.owner = owner
self.__balance = balance
def__check_money(self, money):
return money > 0
defdeposit(self, money):
ifself.__check_money(money):
self.__balance += money

这里:

owner 公开。
__balance 私有。
__check_money() 私有。
deposit() 公开。
29. 单下划线和双下划线的区别
29.1 单下划线
self._score = score

含义:

约定内部使用。
外部不建议访问。
但语法上可以访问。

示例:

classStudent:
def__init__(self):
self._score = 90
stu = Student()
print(stu._score)

可以输出:

90
29.2 双下划线
self.__score = score

含义:

Python 会进行名称改写。
外部不能直接用 stu.__score 访问。

示例:

classStudent:
def__init__(self):
self.__score = 90
stu = Student()
print(stu.__score)

会报错。

_name 是提醒别人不要直接用。
__name 是更强一点的限制。
30. 封装与数据校验

封装最常见的用途之一,就是数据校验。

例如年龄不能为负数。

classPerson:
def__init__(self, name, age):
self.name = name
self.__age = 0
self.set_age(age)
defset_age(self, age):
if0 <= age <= 150:
self.__age = age
else:
print("年龄必须在 0 到 150 之间")
defget_age(self):
returnself.__age
person = Person("张三"18)
print(person.get_age())
person.set_age(-5)
print(person.get_age())

输出:

18
年龄必须在 0 到 150 之间
18

如果没有封装:

person.age = -5

就可能让对象进入不合理状态。

31. 封装与隐藏实现细节

封装不仅是为了保护数据,也可以隐藏实现细节。

例如,订单金额的计算可能比较复杂。

外部只需要调用:

order.total_price()

不需要知道内部如何计算。

示例:

classOrder:
def__init__(self, price, count, discount):
self.price = price
self.count = count
self.discount = discount
deftotal_price(self):
        original = self.price * self.count
return original * self.discount
order = Order(10030.8)
print(order.total_price())

输出:

240.0

外部只关心结果,不关心计算细节。

这也是封装。

32. 封装与修改内部实现

封装还有一个好处:

内部实现可以改变,但外部使用方式尽量不变。

例如,原来余额直接保存在 __balance 中:

defget_balance(self):
returnself.__balance

后来想增加手续费、冻结金额等内部逻辑。

只要 get_balance() 的使用方式不变,外部代码就不需要大改。

这就是封装的价值:

外部依赖公开方法。
内部实现可以逐步调整。
33. 常见错误 1:以为双下划线是绝对安全

错误理解:

__password 写成私有后,别人绝对访问不到。

实际情况:

Python 的私有属性只是名称改写,不是绝对安全机制。

不要把敏感信息的安全完全依赖于双下划线。

双下划线是提醒和保护,不是保险箱。
34. 常见错误 2:私有属性外部直接访问

错误写法:

classStudent:
def__init__(self):
self.__score = 90
stu = Student()
print(stu.__score)

会报错。

正确做法:

classStudent:
def__init__(self):
self.__score = 90
defget_score(self):
returnself.__score
stu = Student()
print(stu.get_score())
35. 常见错误 3:setter 中忘记校验

不推荐:

classStudent:
def__init__(self):
self.__score = 0
defset_score(self, score):
self.__score = score

这样写虽然用了私有属性,但没有起到保护作用。

更推荐:

classStudent:
def__init__(self):
self.__score = 0
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩不合法")

封装的重点不只是“藏起来”,还要“按规则访问”。

36. 常见错误 4:在 init 中绕过校验

错误写法:

classStudent:
def__init__(self, score):
self.__score = score
defset_score(self, score):
if0 <= score <= 100:
self.__score = score

这样创建对象时:

stu = Student(999)

仍然可以得到不合法成绩。

更推荐:

classStudent:
def__init__(self, score):
self.__score = 0
self.set_score(score)
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩不合法")

这样创建对象时也会校验数据。

37. 常见错误 5:property 名称和私有属性名混乱

推荐写法:

classStudent:
def__init__(self, score):
self.__score = score
    @property
defscore(self):
returnself.__score
    @score.setter
defscore(self, value):
self.__score = value

不推荐把公开属性和私有属性混在一起乱命名。

例如:

self.score = score

同时又写:

@property
defscore(self):
returnself.score

这种写法可能导致递归错误。

错误示例:

classStudent:
    @property
defscore(self):
returnself.score

这里 return self.score 会再次调用 score 属性,容易无限递归。

正确写法:

classStudent:
def__init__(self, score):
self.__score = score
    @property
defscore(self):
returnself.__score
38. 常见错误 6:把所有方法都写成私有

不推荐:

classStudent:
def__show_info(self):
print("学生信息")

如果外部需要调用这个方法,就不应该写成私有方法。

私有方法适合类内部使用。

公开方法适合外部调用。

判断方法:

外部需要用,就公开。
只给内部辅助用,就私有。
39. 常见错误 7:过度封装

有些初学者会把每个属性都写成:

__name
get_name()
set_name()

如果这个属性没有任何校验规则,也没有隐藏必要,就会让代码变得啰嗦。

例如:

classBook:
def__init__(self, title):
self.__title = title
defget_title(self):
returnself.__title
defset_title(self, title):
self.__title = title

如果 title 只是普通书名,直接公开也可以:

classBook:
def__init__(self, title):
self.title = title
封装是为了清晰和安全,不是为了把简单问题复杂化。
40. 常见错误 8:通过名称改写强行访问私有属性

虽然可以这样访问:

stu._Student__score

但是不推荐。

原因:

这破坏了类的封装。
代码依赖了类的内部实现。
以后类名或属性名变化,外部代码容易出问题。

正确做法:

stu.get_score()

或者使用:

stu.score

前提是类中定义了 property

41. 注意事项 1:明确哪些数据需要保护

不是所有数据都需要私有化。

需要保护的数据通常有:

必须满足范围的数据,比如成绩、年龄、价格
不能随便修改的数据,比如余额、库存
不希望外部知道的数据,比如密码
内部计算使用的数据,比如缓存、状态标记

普通数据可以公开。

例如:

姓名
标题
描述
颜色

是否私有,取决于这个数据是否需要控制访问。

42. 注意事项 2:公开方法要名字清楚

公开方法是给外部使用的,所以名字应该清楚。

推荐:

deposit()
withdraw()
get_balance()
set_score()
change_password()

不推荐:

do()
handle()
change()
process()
43. 注意事项 3:私有方法只做内部辅助

私有方法通常不应该承担外部业务入口。

例如:

def__check_score(self, score):
return0 <= score <= 100

这是合理的内部辅助方法。

外部真正调用的是:

defset_score(self, score):
    ...
44. 注意事项 4:封装要配合清晰的类设计

封装不是孤立的。

一个类应该有清楚的职责。

例如:

Student 管理学生信息和学生相关行为。
BankAccount 管理账户信息和存取款行为。
Product 管理商品信息和库存行为。

不要把很多不相关的功能都塞进一个类。

例如:

Student 类里同时处理银行余额、商品库存、文件下载。

这样会让封装失去意义。

45. 注意事项 5:封装后外部应该少依赖内部细节

如果一个属性是私有的,外部就不应该依赖它的具体名字。

例如,不应该写:

account._BankAccount__balance

应该写:

account.get_balance()

这样即使类内部以后改成:

self.__money

只要 get_balance() 还在,外部代码就不需要改。

46. 注意事项 6:属性校验要考虑边界值

例如成绩:

0 分是否合法?
100 分是否合法?
-1 分是否合法?
101 分是否合法?

通常:

0 <= score <= 100

表示 0 和 100 都合法。

商品数量:

count > 0

表示必须大于 0

47. 注意事项 7:setter 不一定必须返回值

很多 setter 方法只负责修改属性,不需要返回值。

例如:

defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩不合法")

如果需要告诉外部修改是否成功,也可以返回布尔值。

defset_score(self, score):
if0 <= score <= 100:
self.__score = score
returnTrue
returnFalse
48. 注意事项 8:print 和 return 要区分

方法中经常会用到 print 和 return

defget_score(self):
returnself.__score

return 是把结果交给调用者。

defshow_score(self):
print(self.__score)

print 是直接打印结果。

如果方法名是 get_score(),通常应该使用 return

如果方法名是 show_score(),通常可以使用 print

49. 综合案例:封装版学生类
classStudent:
def__init__(self, name, age, score):
self.name = name
self.__age = 0
self.__score = 0
self.set_age(age)
self.set_score(score)
defset_age(self, age):
if0 <= age <= 150:
self.__age = age
else:
print("年龄必须在 0 到 150 之间")
defget_age(self):
returnself.__age
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩必须在 0 到 100 之间")
defget_score(self):
returnself.__score
defis_passed(self):
returnself.__score >= 60
defshow_info(self):
print(f"姓名:{self.name},年龄:{self.__age},成绩:{self.__score}")
stu = Student("张三"1890)
stu.show_info()
stu.set_age(-5)
stu.set_score(200)
stu.show_info()
print(stu.is_passed())

输出:

姓名:张三,年龄:18,成绩:90
年龄必须在 0 到 150 之间
成绩必须在 0 到 100 之间
姓名:张三,年龄:18,成绩:90
True

这个案例中:

name 是公开属性。
__age 是私有属性。
__score 是私有属性。
set_age() 和 set_score() 负责修改并校验数据。
get_age() 和 get_score() 负责读取数据。
50. 综合案例:封装版矩形类
classRectangle:
def__init__(self, width, height):
self.__width = 0
self.__height = 0
self.width = width
self.height = height
    @property
defwidth(self):
returnself.__width
    @width.setter
defwidth(self, value):
if value > 0:
self.__width = value
else:
print("宽度必须大于 0")
    @property
defheight(self):
returnself.__height
    @height.setter
defheight(self, value):
if value > 0:
self.__height = value
else:
print("高度必须大于 0")
    @property
defarea(self):
returnself.__width * self.__height
    @property
defperimeter(self):
return (self.__width + self.__height) * 2
rect = Rectangle(34)
print(rect.width)
print(rect.height)
print(rect.area)
print(rect.perimeter)
rect.width = -10
print(rect.area)

输出:

3
4
12
14
宽度必须大于 0
12

这个案例适合讲:

property 可以控制属性读写。
area 和 perimeter 是只读计算属性。
51. 练习 1:封装学生成绩

要求:

1.
定义 Student 类。
2.
有公开属性 name
3.
有私有属性 __score
4.
提供 set_score() 修改成绩。
5.
提供 get_score() 查看成绩。
6.
成绩必须在 0 到 100 之间。

参考答案:

classStudent:
def__init__(self, name, score):
self.name = name
self.__score = 0
self.set_score(score)
defset_score(self, score):
if0 <= score <= 100:
self.__score = score
else:
print("成绩不合法")
defget_score(self):
returnself.__score
stu = Student("张三"90)
print(stu.get_score())
stu.set_score(120)
print(stu.get_score())
52. 练习 2:封装银行账户

要求:

1.
定义 BankAccount 类。
2.
有公开属性 owner
3.
有私有属性 __balance
4.
提供 deposit() 方法存款。
5.
提供 withdraw() 方法取款。
6.
提供 get_balance() 方法查看余额。
7.
取款金额不能超过余额。

参考答案:

classBankAccount:
def__init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
defdeposit(self, money):
if money > 0:
self.__balance += money
else:
print("存款金额必须大于 0")
defwithdraw(self, money):
if money <= 0:
print("取款金额必须大于 0")
elif money > self.__balance:
print("余额不足")
else:
self.__balance -= money
defget_balance(self):
returnself.__balance
account = BankAccount("张三"1000)
account.deposit(500)
account.withdraw(300)
print(account.get_balance())
53. 练习 3:使用 property 封装年龄

要求:

1.
定义 Person 类。
2.
有私有属性 __age
3.
使用 property 让外部通过 person.age 读取年龄。
4.
使用 setter 限制年龄必须在 0 到 150 之间。

参考答案:

classPerson:
def__init__(self, age):
self.__age = 0
self.age = age
    @property
defage(self):
returnself.__age
    @age.setter
defage(self, value):
if0 <= value <= 150:
self.__age = value
else:
print("年龄不合法")
person = Person(18)
print(person.age)
person.age = -5
print(person.age)
54. 练习 4:只读面积属性

要求:

1.
定义 Circle 类。
2.
有 radius 属性。
3.
使用 @property 定义只读属性 area
4.
area 返回圆的面积。

参考答案:

classCircle:
def__init__(self, radius):
self.radius = radius
    @property
defarea(self):
return3.14 * self.radius * self.radius
circle = Circle(5)
print(circle.area)
55. 练习 5:封装商品库存

要求:

1.
定义 Product 类。
2.
有公开属性 name
3.
有私有属性 __stock
4.
提供 add_stock() 增加库存。
5.
提供 sell() 销售商品。
6.
提供 get_stock() 查看库存。
7.
库存不能小于 0

参考答案:

classProduct:
def__init__(self, name, stock):
self.name = name
self.__stock = 0
self.add_stock(stock)
defadd_stock(self, count):
if count > 0:
self.__stock += count
else:
print("增加库存数量必须大于 0")
defsell(self, count):
if count <= 0:
print("销售数量必须大于 0")
elif count > self.__stock:
print("库存不足")
else:
self.__stock -= count
defget_stock(self):
returnself.__stock
product = Product("苹果"100)
product.sell(3)
print(product.get_stock())
56. 练习 6:判断代码错误

下面代码有什么问题?

classStudent:
def__init__(self):
self.__score = 90
stu = Student()
print(stu.__score)

参考答案:

__score 是私有属性,不能在类外通过 stu.__score 直接访问。
应该提供 get_score() 方法,或使用 property。
57. 练习 7:判断是否需要封装

下面哪些属性更适合封装?

1. 学生姓名
2. 学生成绩
3. 银行账户余额
4. 商品库存
5. 文章标题
6. 用户密码

参考答案:

更适合封装:
2. 学生成绩
3. 银行账户余额
4. 商品库存
6. 用户密码
可以公开:
1. 学生姓名
5. 文章标题

原因:

成绩、余额、库存、密码需要访问控制或数据校验。
姓名、标题通常可以直接访问和修改。
58. 练习 8:补全代码

补全代码,让价格不能小于 0

题目:

classProduct:
def__init__(self, price):
self.__price = 0
self.set_price(price)
defset_price(self, price):
# 请补全这里
defget_price(self):
returnself.__price

参考答案:

classProduct:
def__init__(self, price):
self.__price = 0
self.set_price(price)
defset_price(self, price):
if price >= 0:
self.__price = price
else:
print("价格不能小于 0")
defget_price(self):
returnself.__price
59. 练习 9:把 getter/setter 改成 property

原代码:

classStudent:
def__init__(self, score):
self.__score = score
defget_score(self):
returnself.__score
defset_score(self, score):
if0 <= score <= 100:
self.__score = score

请改成 property 写法。

参考答案:

classStudent:
def__init__(self, score):
self.__score = 0
self.score = score
    @property
defscore(self):
returnself.__score
    @score.setter
defscore(self, value):
if0 <= value <= 100:
self.__score = value
else:
print("成绩不合法")
60. 练习 10:设计封装类

要求设计一个 Temperature 类:

1.
私有属性 __celsius 表示摄氏温度。
2.
使用 property 读取和修改摄氏温度。
3.
摄氏温度不能低于 -273.15
4.
提供只读属性 fahrenheit,返回华氏温度。

参考答案:

classTemperature:
def__init__(self, celsius):
self.__celsius = 0
self.celsius = celsius
    @property
defcelsius(self):
returnself.__celsius
    @celsius.setter
defcelsius(self, value):
if value >= -273.15:
self.__celsius = value
else:
print("温度不能低于绝对零度")
    @property
deffahrenheit(self):
returnself.__celsius * 9 / 5 + 32
temp = Temperature(25)
print(temp.celsius)
print(temp.fahrenheit)
temp.celsius = -300
print(temp.celsius)
61. 总结

封装是 Python 面向对象编程中的重要思想。

一句话总结:

封装就是把数据和操作数据的方法放在类中,
并控制外部如何访问和修改这些数据。

核心知识:

1.
公开属性可以直接访问。
2.
_属性名 表示受保护属性,约定内部使用。
3.
__属性名 表示私有属性,外部不能直接访问。
4.
私有属性通常通过公开方法访问。
5.
getter 用来读取数据。
6.
setter 用来修改数据。
7.
setter 中常常进行数据校验。
8.
property 可以让方法像属性一样使用。
9.
私有方法适合类内部辅助逻辑。
封装不是越多越好,要根据数据是否需要保护来决定。

常用代码模板:

class类名:
def__init__(self, value):
self.__value = value
defget_value(self):
returnself.__value
defset_value(self, value):
if 条件:
self.__value = value
else:
print("数据不合法")

property 模板:

class类名:
def__init__(self, value):
self.__value = value
    @property
defvalue(self):
returnself.__value
    @value.setter
defvalue(self, new_value):
if 条件:
self.__value = new_value
else:
print("数据不合法")

记忆口诀:

公开属性随便用,
单下划线别乱动,
双下划线藏内部,
读取修改走方法。
getter 负责读,
setter 负责改,
property 更像属性,
校验数据更安全。

最后记住:

封装不是为了把代码藏起来,
而是为了让数据更安全,让使用更简单,让代码更清楚。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-22 00:23:26 HTTP/2.0 GET : https://f.mffb.com.cn/a/506156.html
  2. 运行时间 : 0.294166s [ 吞吐率:3.40req/s ] 内存消耗:5,073.25kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=6cb5975c303f4b10f6d0e77efab85629
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000864s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000753s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.013719s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.016790s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000728s ]
  6. SELECT * FROM `set` [ RunTime:0.009150s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000736s ]
  8. SELECT * FROM `article` WHERE `id` = 506156 LIMIT 1 [ RunTime:0.031378s ]
  9. UPDATE `article` SET `lasttime` = 1787329406 WHERE `id` = 506156 [ RunTime:0.036432s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.004436s ]
  11. SELECT * FROM `article` WHERE `id` < 506156 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.024037s ]
  12. SELECT * FROM `article` WHERE `id` > 506156 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.003896s ]
  13. SELECT * FROM `article` WHERE `id` < 506156 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002020s ]
  14. SELECT * FROM `article` WHERE `id` < 506156 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001631s ]
  15. SELECT * FROM `article` WHERE `id` < 506156 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003063s ]
0.296036s