Appearance
26|类与对象
程序需要描述具有相同特征和行为的一组事物。学生有姓名、年龄、成绩,能学习、能考试;商品有名称、价格、库存,能上架、能售出。类(class)是这类事物的抽象定义,对象(object)是类的具体实例。
Python 支持面向对象编程,但不像 Java 那样强制所有代码都放在类里。类在需要封装数据和行为时使用,简单脚本可以用函数和模块解决。
一、定义类
python
class Student:
"""学生类。"""
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"我是{self.name},今年{self.age}岁"class 关键字定义类。__init__ 是构造方法,创建对象时自动调用。self 代表对象本身,必须通过 self 访问对象的属性和方法。
创建对象:
python
alice = Student("Alice", 20)
print(alice.name) # Alice
print(alice.introduce()) # 我是Alice,今年20岁二、属性和方法
类中定义的变量叫属性,函数叫方法。
python
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
rect = Rectangle(5, 3)
print(rect.area()) # 15
print(rect.perimeter()) # 16三、self 的本质
self 是方法的第一个参数,代表调用该方法的对象。Python 在调用方法时自动传入这个参数:
python
rect.area() # 等价于 Rectangle.area(rect)方法定义时必须有 self,调用时不需要传。
四、类属性 vs 实例属性
实例属性绑定到具体对象,每个对象有自己的一份:
python
alice = Student("Alice", 20)
bob = Student("Bob", 21)
alice.age = 21 # 只修改 alice,不影响 bob类属性绑定到类本身,所有对象共享:
python
class Student:
school = "第一中学" # 类属性
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
alice = Student("Alice", 20)
bob = Student("Bob", 21)
print(alice.school) # 第一中学
print(bob.school) # 第一中学
Student.school = "第二中学"
print(alice.school) # 第二中学,所有实例都变了通过对象修改类属性会创建实例属性,不影响其他对象:
python
alice.school = "实验中学" # 给 alice 创建实例属性 school
print(alice.school) # 实验中学
print(bob.school) # 第二中学,没变五、动态添加属性
Python 允许给对象动态添加属性:
python
alice = Student("Alice", 20)
alice.score = 95 # 动态添加属性
print(alice.score) # 95这个特性很灵活,但也容易出错——拼写错误不会报错,只是创建了一个新属性:
python
print(alice.scroe) # AttributeError,拼写错误六、私有属性
Python 没有真正的私有属性。以双下划线开头的属性会被改名(name mangling),不容易从外部直接访问:
python
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 伪私有属性
def get_balance(self):
return self.__balance
account = BankAccount(1000)
print(account.get_balance()) # 1000
print(account.__balance) # AttributeError
print(account._BankAccount__balance) # 1000,通过改名后的名称仍可访问单下划线开头的属性(如 _balance)是约定俗成的"内部使用",不会阻止访问,只是提示"不要直接碰"。
记忆锚点:class 定义类,__init__ 构造方法;self 代表对象本身,定义时写、调用时不传;实例属性每个对象独立,类属性所有对象共享;动态添加属性灵活但容易拼写出错;双下划线属性被改名,单下划线是约定内部使用。