当前位置: 首页 > news >正文

【Python】面向对象(一)

目录

  • 面向对象
    • 面向对象概念
    • 类和对象
    • 类属性
    • 类方法
    • 静态方法
    • 构造函数
    • 访问修饰符

面向对象

面向对象概念

什么是 OOP?

OOP(Object-Oriented Programming,面向对象编程)是一种编程范式,它用 对象(Object) 来模拟现实世界的实体。

  • 对象(Object) = 属性(数据) + 方法(行为)
  • 举例:
    • 学生(Student):属性 = 姓名、学号、成绩;方法 = 学习、考试、计算平均分
    • 汽车(Car):属性 = 品牌、马力、速度;方法 = 启动、加速、刹车

所以,对象是数据和行为的结合体

过程式 vs 面向对象

  1. 过程式编程(Procedural Programming)

    • 重点是 函数流程控制,按步骤执行。

    • 问题:

      • 太多全局变量 → 维护困难
      • 数据和函数分离 → 不符合现实世界的建模习惯
  2. 面向对象编程(OOP)

    • 数据函数(方法) 封装进一个整体(类和对象)。

    • 优点:

      • 更符合现实思维方式
      • 易扩展、易维护
      • 提供了继承、多态、封装等机制

OOP 的四大基本特性:

  1. 类(Class)和对象(Object)
  2. 封装(Encapsulation)
  3. 继承(Inheritance)
  4. 多态(Polymorphism)

类(Class)与对象(Object)

类(Class)

  • 类是对象的 蓝图模板
  • 类里定义了对象 有什么属性能做什么事

对象(Object)

  • 对象是类的 实例(instance)
  • 一个类可以创建多个对象。

代码示例:

# 定义类
class Smartphone:def __init__(self, device, brand):  # 构造方法self.device = deviceself.brand = branddef description(self):return f"{self.device} of {self.brand} supports Android 14"# 创建对象
phoneObj = Smartphone("Smartphone", "Samsung")
print(phoneObj.description())

输出:

Smartphone of Samsung supports Android 14

封装(Encapsulation)

  • 封装就是 隐藏对象的内部实现,只暴露必要的接口给外部使用。
  • 在 Python 里:
    • 普通属性 → 可以直接访问
    • 私有属性(前缀 __)→ 不能直接访问,只能通过方法(getter/setter)来修改

代码示例:

class Desktop:def __init__(self):self.__max_price = 25000  # 私有属性def sell(self):return f"Selling Price: {self.__max_price}"def set_max_price(self, price):if price > self.__max_price:self.__max_price = pricedesktopObj = Desktop()
print(desktopObj.sell())# 直接改属性(失败)
desktopObj.__max_price = 35000
print(desktopObj.sell())# 用 setter 改属性(成功)
desktopObj.set_max_price(35000)
print(desktopObj.sell())

输出:

Selling Price: 25000
Selling Price: 25000
Selling Price: 35000

继承(Inheritance)

  • 子类继承父类,可以复用父类的属性和方法。
  • 子类还可以:
    • 新增自己的方法
    • 重写(override)父类的方法

代码示例:

class Parent:parentAttr = 100def __init__(self):print("Calling parent constructor")def parentMethod(self):print("Calling parent method")def setAttr(self, attr):Parent.parentAttr = attrdef getAttr(self):print("Parent attribute:", Parent.parentAttr)class Child(Parent):def __init__(self):print("Calling child constructor")def childMethod(self):print("Calling child method")# 创建子类对象
c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()

输出:

Calling child constructor
Calling child method
Calling parent method
Parent attribute: 200

Python 还支持 多重继承,可用 issubclass()isinstance() 检查关系。

多态(Polymorphism)

  • 多态 = 多种形态
  • 不同的类可以实现相同的方法接口,但表现不同。
  • 方法重写(Override) 是多态的核心。

代码示例:

class Parent:def myMethod(self):print("Calling parent method")class Child(Parent):def myMethod(self):print("Calling child method")c = Child()
c.myMethod()   # 子类重写父类方法

输出:

Calling child method

类和对象

类与对象的基本概念

  • 类(Class)
    类是用户自定义的数据类型,定义了对象的属性(数据)**和**行为(方法)。它就像一个模板或蓝图。
    例如:我们可以写一个 Smartphone 类,属性包括 RAMROM屏幕大小,行为包括 打电话发短信
  • 对象(Object)
    对象是类的一个实例化结果。类只描述结构,不占内存;当创建对象时,才会为对象分配内存。
    举例:类是“人类”,对象是“张三”“李四”。
  • Python 是面向对象语言:整数、字符串、列表、字典,甚至函数,本质上都是对象,属于内置类的实例。

类的定义

在 Python 中使用 class 关键字:

class ClassName:"可选的类文档字符串"# 类体:定义属性、方法

例如:

class Employee:"Common base class for all employees"empCount = 0   # 类变量def __init__(self, name, salary):  # 构造方法self.name = name               # 实例变量self.salary = salaryEmployee.empCount += 1def displayCount(self):  # 方法print("Total Employee %d" % Employee.empCount)def displayEmployee(self):print("Name:", self.name, ", Salary:", self.salary)

说明:

  • __init__ 是构造函数,创建对象时自动执行。
  • self 表示对象本身(类似 Java 的 this)。
  • 类变量 empCount 在所有实例之间共享。
  • 实例变量 self.nameself.salary 属于各自对象。

对象的创建与使用

对象的创建就是 调用类名,传入构造函数参数:

emp1 = Employee("Zara", 2000)  # 第一个对象
emp2 = Employee("Manni", 5000) # 第二个对象emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)

输出:

Name: Zara , Salary: 2000
Name: Manni , Salary: 5000
Total Employee 2

类变量和实例变量

  • 类变量:所有对象共享(如 Employee.empCount)。
  • 实例变量:每个对象独立(如 self.name)。

我们也可以动态地添加/修改/删除属性:

emp1.age = 7      # 添加属性
emp1.age = 8      # 修改属性
del emp1.age      # 删除属性

对象属性的操作函数

除了点运算符,还可以用内置函数:

hasattr(emp1, 'age')       # 判断是否存在属性
getattr(emp1, 'name')      # 获取属性值
setattr(emp1, 'age', 10)   # 设置属性值(如果没有则创建)
delattr(emp1, 'age')       # 删除属性

Python 内置类属性

每个类都有一些内置属性,可以用 __dict__ 查看:

print("Employee.__doc__:", Employee.__doc__)       # 文档字符串
print("Employee.__name__:", Employee.__name__)     # 类名
print("Employee.__module__:", Employee.__module__) # 定义所在模块
print("Employee.__bases__:", Employee.__bases__)   # 基类
print("Employee.__dict__:", Employee.__dict__)     # 类的命名空间字典

输出类似:

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__module__': '__main__', '__doc__': 'Common base class for all employees', 'empCount': 0, '__init__': <function Employee.__init__ at 0x7fdaa2e09300>, 'displayCount': <function Employee.displayCount at 0x7fdaa2e6ce00>, 'displayEmployee': <function Employee.displayEmployee at 0x7fdaa2e6cea0>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>}

内置数据类型其实都是类对象

Python 内置的数字、字符串、列表、字典,本质上也是类的对象:

num = 20
print(type(num))   # <class 'int'>
s = "Hello"
print(type(s))     # <class 'str'>
dct = {'a':1}
print(type(dct))   # <class 'dict'>def SayHello(): pass
print(type(SayHello))  # <class 'function'>

垃圾回收与对象销毁

Python 使用引用计数来管理内存:

  • 当变量引用对象时,引用计数+1;
  • 删除引用时,计数-1;
  • 当计数为 0,对象会被垃圾回收。

示例:

a = 40   # 对象 <40> 引用+1
b = a    # 引用+1
c = [b]  # 引用+1
del a    # 引用-1
b = 100  # 引用-1
c[0] = -1 # 引用-1,引用计数为0,对象销毁

我们也可以定义 析构方法 __del__

class Employee:"Common base class for all employees"empCount = 0   # 类变量def __init__(self, name, salary):  # 构造方法self.name = name               # 实例变量self.salary = salaryEmployee.empCount += 1print("Point created")def __del__(self):Employee.empCount -= 1print("Point destroyed")def displayCount(self):  # 方法print("Total Employee %d" % Employee.empCount)def displayEmployee(self):print("Name:", self.name, ", Salary:", self.salary)emp1 = Employee("Zara", 2000)  # 第一个对象
emp2 = Employee("Manni", 5000) # 第二个对象emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)del emp1
del emp2
print("Total Employee %d" % Employee.empCount)

输出:

Point created
Point created
Name: Zara , Salary: 2000
Name: Manni , Salary: 5000
Total Employee 2
Point destroyed
Point destroyed
Total Employee 0

数据隐藏(封装)

Python 并没有真正的私有属性,但可以通过 双下划线前缀 来“伪私有”:

class JustCounter:__secretCount = 0  # 私有变量def count(self):self.__secretCount += 1print(self.__secretCount)counter = JustCounter()
counter.count()
counter.count()print(counter.__secretCount)  # 报错

输出:

1
2
AttributeError: 'JustCounter' object has no attribute '__secretCount'

但其实仍然可以通过以下方式访问(名字改写):

print(counter._JustCounter__secretCount)  # 2

类属性

在 Python 中,类属性就是在类里面(class 代码块中),但不在构造方法 __init__()定义的变量。

  • 类属性 → 属于整个类,所有对象(实例)共享同一份数据。
  • 实例属性 → 属于对象,每个对象都有独立的数据。

类属性一般用于表示 所有对象都应共享的值,例如:员工总数、学校名称、公司名称等。

定义类属性与实例属性

class Employee:# 类属性(所有对象共享)company = "OpenAI"  def __init__(self, name, age):# 实例属性(每个对象独有)self.name = nameself.age = age

访问类属性

类属性既可以通过 类名 访问,也可以通过 对象 访问:

emp1 = Employee("Alice", 25)
emp2 = Employee("Bob", 30)# 通过类名访问
print(Employee.company)  # OpenAI# 通过对象访问
print(emp1.company)  # OpenAI
print(emp2.company)  # OpenAI

输出:

OpenAI
OpenAI
OpenAI

无论多少个对象,类属性的值相同。

修改类属性

修改类属性时,必须用类名修改,否则就会变成实例属性。

class Employee:empCount = 0  # 类属性def __init__(self, name, age):self.name = nameself.age = ageEmployee.empCount += 1   # 修改类属性print("Name:", self.name, ", Age:", self.age)print("Employee Count:", Employee.empCount)# 创建对象时,empCount 自动 +1
e1 = Employee("Bhavana", 24)
print()
e2 = Employee("Rajesh", 26)

输出:

Name: Bhavana , Age: 24
Employee Count: 1Name: Rajesh , Age: 26
Employee Count: 2

这里 empCount 是所有对象共享的,如果新建一个对象,计数会继续递增。

类属性的意义

  1. 表示所有对象共享的数据
    比如“公司名称”“学校名称”“员工总数”等。
  2. 设置默认值
    如果很多对象需要一个相同的初始值,可以放在类属性里。
  3. 实现单例模式(Singleton)
    利用类属性来控制对象的唯一性(比如只允许创建一个对象)。

Python 内置类属性

Python 中每个类都有一些内置的类属性,可以用来获取类的元信息:

  • __dict__:类的命名空间(属性字典)
  • __doc__:类的文档字符串
  • __name__:类名
  • __module__:类所在的模块
  • __bases__:基类(父类)

示例:

class Employee:"""员工类"""def __init__(self, name="Bhavana", age=24):self.name = nameself.age = agedef displayEmployee(self):print("Name:", self.name, ", Age:", self.age)print("Employee.__doc__:", Employee.__doc__)
print("Employee.__name__:", Employee.__name__)
print("Employee.__module__:", Employee.__module__)
print("Employee.__bases__:", Employee.__bases__)
print("Employee.__dict__:", Employee.__dict__)

输出:

Employee.__doc__: 员工类
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__module__': '__main__', '__doc__': '员工类', '__init__': <function Employee.__init__ at 0x7fd054119300>, 'displayEmployee': <function Employee.displayEmployee at 0x7fd05417ce00>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>}

实例属性

与类属性不同,实例属性是定义在 __init__ 中的,每个对象都有自己独立的一份。

class Student:def __init__(self, name, grade):self.name = name      # 实例属性self.grade = grade    # 实例属性print("Name:", self.name, ", Grade:", self.grade)student1 = Student("Ram", "B")
student2 = Student("Shyam", "C")

输出:

Name: Ram , Grade: B
Name: Shyam , Grade: C

student1student2namegrade 各不相同,互不影响。

类属性 vs 实例属性

实例属性类属性
定义在 __init__()定义在类中但不在方法里
通过对象访问可通过类名或对象访问
每个对象独立,互不共享所有对象共享一份
修改只影响当前对象修改会影响所有对象

高级用法

  1. 动态添加类属性

    class Car:passCar.brand = "Toyota"  # 运行时动态添加
    print(Car.brand)
    
  2. 动态修改/删除类属性

    Car.brand = "Tesla"
    print(Car.brand)   # Tesladel Car.brand
    print(hasattr(Car, "brand"))  # False
    
  3. 类属性和实例属性“遮蔽”现象

    class Demo:x = 10   # 类属性d = Demo()
    print(d.x)   # 10 (访问类属性)d.x = 20     # 创建实例属性,遮蔽类属性
    print(d.x)   # 20
    print(Demo.x)  # 10 (类属性未变)
    

    如果实例对象创建了同名属性,会“屏蔽”类属性。

类方法

什么是方法(Method)

在 Python 的类中,方法就是定义在类里面的函数,用来对对象或类执行某些操作。

方法分为三类:

  1. 实例方法(Instance Method)
    • 默认的普通方法,参数第一个是 self(对象本身),可以访问和修改 实例属性,也能访问类属性。
  2. 类方法(Class Method)
    • 参数第一个是 cls(类本身),绑定在类上,不能访问实例属性,但可以访问和修改类属性。
  3. 静态方法(Static Method)
    • 没有 selfcls,与类只是“放在一起”,不能访问实例或类的状态,逻辑上属于类。

什么是 Class Method(类方法)

  • 类方法是绑定在类上的方法,而不是绑定在实例上的方法。
  • 调用时可以直接通过 类名 调用,而不必先创建对象。
  • 参数第一个是 cls,代表类本身,可以用来访问和修改 类属性

类方法常用于:

  • 访问/修改类属性
  • 定义“备用构造函数”(Alternate Constructor)
  • 工厂模式、单例模式等

创建类方法的两种方式

方式一:classmethod() 函数

class Employee:empCount = 0   # 类属性def __init__(self, name, age):self.name = nameself.age = ageEmployee.empCount += 1def showcount(self):   # 实例方法print(self.empCount)# 把实例方法转成类方法counter = classmethod(showcount)e1 = Employee("Bhavana", 24)
e2 = Employee("Rajesh", 26)
e3 = Employee("John", 27)e1.showcount()      # 用对象调用
Employee.counter()  # 用类调用

输出:

3
3

方式二:@classmethod 装饰器(推荐)

class Employee:empCount = 0   # 类属性def __init__(self, name, age):self.name = nameself.age = ageEmployee.empCount += 1@classmethoddef showcount(cls):print(cls.empCount)@classmethoddef newemployee(cls, name, age):  # 备用构造函数return cls(name, age)e1 = Employee("Bhavana", 24)
e2 = Employee("Rajesh", 26)
e3 = Employee("John", 27)
e4 = Employee.newemployee("Anil", 21)  # 通过类方法创建对象Employee.showcount()

输出:

4

推荐使用 装饰器写法,比 classmethod() 简洁直观。

在类方法中访问类属性

类方法可以通过 cls.属性名 访问或修改类属性:

class Cloth:price = 4000   # 类属性@classmethoddef showPrice(cls):return cls.priceprint(Cloth.showPrice())  

输出:

4000

动态操作类方法

Python 允许我们 动态添加或删除 类方法。

  1. 动态添加类方法

    class Cloth:pass@classmethod
    def brandName(cls):print("Name of the brand is Raymond")# 动态添加类方法
    setattr(Cloth, "brand_name", brandName)c = Cloth()
    c.brand_name()
    

    输出:

    Name of the brand is Raymond
    
  2. 动态删除类方法

    class Cloth:@classmethoddef brandName(cls):print("Name of the brand is Raymond")# 删除类方法
    del Cloth.brandName
    print("Method deleted")
    

    输出:

    Method deleted
    

    删除后,如果再调用 Cloth.brandName() 会报错 AttributeError

类方法 vs 实例方法 vs 静态方法

特性实例方法类方法静态方法
绑定对象实例无绑定
第一个参数self(实例对象)cls(类对象)
可访问实例属性、类属性类属性(不能直接访问实例属性)都不能
调用方式obj.method()Class.method()obj.method()Class.method()obj.method()
常见用途操作对象数据操作类数据、备用构造函数工具函数

高级用法

  1. 备用构造函数

    class Date:def __init__(self, year, month, day):self.year = yearself.month = monthself.day = day@classmethoddef from_string(cls, date_str):y, m, d = map(int, date_str.split("-"))return cls(y, m, d)d = Date.from_string("2025-09-21")
    print(d.year, d.month, d.day)
    

    输出:

    2025 9 21
    

    类方法能创建对象的“另一种构造方式”。

  2. 工厂模式

    class Shape:def __init__(self, name):self.name = name@classmethoddef circle(cls):return cls("Circle")@classmethoddef square(cls):return cls("Square")s1 = Shape.circle()
    s2 = Shape.square()
    print(s1.name, s2.name)
    

    输出:

    Circle Square
    

静态方法

静态方法的定义(是什么?)

在 Python 中,静态方法(static method) 是一种属于类的方法,但它 既不需要实例(self),也不需要类引用(cls) 作为第一个参数。

  • 实例方法:默认第一个参数是 self,能操作对象的实例属性。
  • 类方法:默认第一个参数是 cls,能操作类属性。
  • 静态方法:没有 self、也没有 cls,就是一个“普通函数”,但被放在类里面,为了逻辑上的归类和组织。

直白理解:

  • 静态方法和普通函数几乎没区别,只是 放在类里面,便于和类产生关联。
  • 静态方法更像是“工具方法”,常用于一些通用逻辑,不依赖于对象或类的状态。

静态方法的创建方式

Python 提供两种方式:

  1. 使用 staticmethod() 内置函数

    这是最原始的写法,把一个普通函数“转化”为静态方法。

    class Employee:empCount = 0def __init__(self, name, age):self.__name = nameself.__age = ageEmployee.empCount += 1# 定义普通方法def showcount():print(Employee.empCount)# 把方法转化为静态方法counter = staticmethod(showcount)# 创建对象
    e1 = Employee("Bhavana", 24)
    e2 = Employee("Rajesh", 26)
    e3 = Employee("John", 27)e1.counter()       # 对象调用
    Employee.counter() # 类调用
    

    输出:

    3
    3
    
  2. 使用 @staticmethod 装饰器(推荐方式)

    这是更简洁的写法,也是实际开发中的 标准写法

    class Student:stdCount = 0def __init__(self, name, age):self.__name = nameself.__age = ageStudent.stdCount += 1@staticmethoddef showcount():print(Student.stdCount)# 创建对象
    s1 = Student("Bhavana", 24)
    s2 = Student("Rajesh", 26)
    s3 = Student("John", 27)print("Number of Students:")
    Student.showcount()
    

    输出:

    Number of Students:
    3
    

    说明:

    • showcount 里面既没有 self 也没有 cls
    • 它只能直接通过 类名访问类变量(例如 Student.stdCount)。

静态方法和类方法的区别

特点实例方法类方法静态方法
第一个参数self(对象本身)cls(类本身)
是否能访问实例属性
是否能访问类属性❌(只能硬编码访问类名)
绑定对象实例无绑定
调用方式实例调用类/实例调用类/实例调用
常见用途操作实例属性工厂方法、操作类属性工具函数

总结一句话:

  • 实例方法:和对象打交道
  • 类方法:和类打交道
  • 静态方法:和类没啥关系,只是放在类里“逻辑归类”

静态方法的使用场景

静态方法虽然看起来“鸡肋”,但在实际开发里有几个经典用法:

  1. 工具函数(通用逻辑)

    比如写个判断逻辑,放在类里面,和类语义相关,但不需要访问类的属性。

    class MathUtils:@staticmethoddef add(a, b):return a + b@staticmethoddef is_even(num):return num % 2 == 0print(MathUtils.add(5, 3))       # 8
    print(MathUtils.is_even(10))     # True
    
  2. 数据验证

    class Validator:@staticmethoddef is_valid_email(email):return "@" in email and "." in emailprint(Validator.is_valid_email("abc@example.com"))  # True
    print(Validator.is_valid_email("not_email"))        # False
    
  3. 保证方法不依赖类状态

    有些方法你就是不希望它访问或修改类属性,这时候用静态方法能“强制隔离”。

    class Config:setting = "DEBUG"@staticmethoddef greet():print("Hello, world!")Config.greet()   # 不依赖 setting
    

静态方法的优点

  • 逻辑组织性:和类语义相关的方法放在类里,而不是全局函数。
  • 更易维护:不用在全局找函数,类名就能找到对应工具。
  • 调用灵活:类调用、对象调用都行。
  • 行为可预测:不会受对象或类属性影响,输出固定。
  • 防止误用:用静态方法明确告诉使用者:别想在这里改类或对象状态

动态添加静态方法

class Tool:passdef say_hello():print("Hello!")# 动态设置为静态方法
Tool.hello = staticmethod(say_hello)Tool.hello()

输出:

Hello!

静态方法 vs 普通函数

其实静态方法和普通函数几乎一样,区别是:

  • 普通函数在全局命名空间;
  • 静态方法在类命名空间,调用时需要类名。

所以更多是 代码组织层面的意义

构造函数

构造函数是什么?

在 Python 中,构造函数(Constructor) 是类里的一个特殊方法:

  • 它的名字固定为 __init__()
  • 当你创建类的对象时,会自动被调用;
  • 作用:用来 初始化对象的属性,确保对象一创建出来就有合适的初始值。

构造函数其实就是对象的“出生证明”。

语法与基本用法

class ClassName:def __init__(self, parameters):# 初始化对象属性self.attr = parameters
  • 第一个参数通常是 self,代表实例对象本身(你也可以改名字,但强烈推荐用 self)。
  • 其他参数可以是你希望在创建对象时传入的初始化值。

构造函数的类型

  1. 默认构造函数(Default Constructor)

    没有额外参数,只接受 self

    class Employee:def __init__(self):self.name = "Bhavana"self.age = 24e1 = Employee()
    print("Name:", e1.name)
    print("Age:", e1.age)
    

    输出:

    Name: Bhavana
    Age: 24
    

    特点:

    • 每个对象的初始值都相同。
  2. 参数化构造函数(Parameterized Constructor)

    构造函数接受多个参数,创建对象时传入不同的值。

    class Employee:def __init__(self, name, age):self.name = nameself.age = agee1 = Employee("Bhavana", 24)
    e2 = Employee("Bharat", 25)print("Name:", e1.name, "Age:", e1.age)
    print("Name:", e2.name, "Age:", e2.age)
    

    输出:

    Name: Bhavana Age: 24
    Name: Bharat Age: 25
    
  3. 带默认参数的构造函数

    Python 支持给构造函数参数设置 默认值,这样可以在传参或不传参时都能创建对象。

    class Employee:def __init__(self, name="Bhavana", age=24):self.name = nameself.age = agee1 = Employee()                # 用默认值
    e2 = Employee("Bharat", 25)    # 用传入值print("Name:", e1.name, "Age:", e1.age)
    print("Name:", e2.name, "Age:", e2.age)
    

    输出:

    Name: Bhavana Age: 24
    Name: Bharat Age: 25
    

构造函数 + 实例方法

构造函数通常配合 实例方法(Instance Methods) 使用。
实例方法的第一个参数是 self,它能访问对象的属性。

class Employee:def __init__(self, name="Bhavana", age=24):self.name = nameself.age = agedef displayEmployee(self):print("Name:", self.name, ", Age:", self.age)e1 = Employee()
e2 = Employee("Bharat", 25)e1.displayEmployee()
e2.displayEmployee()

输出:

Name: Bhavana , Age: 24
Name: Bharat , Age: 25

对象属性的动态操作

Python 是动态语言,类和对象的属性可以随时 增加 / 修改 / 删除

e1 = Employee("Bhavana", 24)# 增加属性
e1.salary = 7000  
print(e1.salary)  # 7000# 修改属性
e1.name = "XYZ"
print(e1.name)    # XYZ# 删除属性
del e1.salary

还可以用内置函数操作:

  • getattr(obj, name[, default]) → 获取属性
  • hasattr(obj, name) → 检查属性是否存在
  • setattr(obj, name, value) → 设置属性(不存在就创建)
  • delattr(obj, name) → 删除属性
print(hasattr(e1, "salary"))       # False
print(getattr(e1, "name"))         # Bhavana
setattr(e1, "salary", 8000)        # 动态增加
print(e1.salary)                   # 8000
delattr(e1, "age")                 # 删除 age

Python 中的多构造函数问题

Java / C++ 里,可以重载多个构造函数,但 Python 不支持 多个 __init__ 并存

  • 如果你写了多个 __init__,只有最后一个会生效,前面的会被覆盖。

Python 可以用 可变参数*args, **kwargs)来模拟多个构造函数。

class Student:def __init__(self, *args):if len(args) == 1:self.name = args[0]elif len(args) == 2:self.name = args[0]self.age = args[1]elif len(args) == 3:self.name = args[0]self.age = args[1]self.gender = args[2]st1 = Student("Shrey")
print("Name:", st1.name)st2 = Student("Ram", 25)
print("Name:", st2.name, "Age:", st2.age)st3 = Student("Shyam", 26, "M")
print("Name:", st3.name, "Age:", st3.age, "Gender:", st3.gender)

输出:

Name: Shrey
Name: Ram Age: 25
Name: Shyam Age: 26 Gender: M

这样就实现了类似 构造函数重载 的效果。

访问修饰符

什么是访问修饰符?

在面向对象编程中,访问修饰符(Access Modifiers) 是用来限制类成员(变量、方法)的可访问范围的。
它体现了 封装(Encapsulation) 的思想:

  • 对象的内部实现细节不应该被随意访问或修改
  • 外部只能通过公开接口(方法)与对象交互

C++/Java 中,有明确的 publicprotectedprivate 关键字。
但是在 Python 中,没有强制性的访问控制关键字,而是通过 命名约定 + 解释器机制 来实现。

Python中的三种访问控制

Python 提供了 三种访问修饰符(通过命名约定实现):

类型语法表示含义可访问范围
Public普通名称(如 name默认情况,任何地方都能访问类内、子类、类外
Protected单下划线 _var一般约定为“受保护”,不要在类外直接使用类内、子类
Private双下划线 __var私有,不能直接在类外访问,会触发 Name Mangling类内

Python的语法规则(命名约定)

  • Public(公开)

    self.name = "公开"
    

    没有下划线前缀 → 任何地方都能访问。

  • Protected(受保护)

    self._salary = 10000
    

    单下划线 _ → 只是一种约定,表示“内部使用”,类外访问虽然能用,但不建议。

  • Private(私有)

    self.__age = 24
    

    双下划线 __ → Python会进行 名字改编(Name Mangling),变成 _ClassName__变量名,因此类外不能直接访问。

示例:Public / Protected / Private

class Employee:def __init__(self, name, age, salary):self.name = name         # publicself._salary = salary    # protectedself.__age = age         # privatedef display(self):print(f"姓名: {self.name}, 年龄: {self.__age}, 薪资: {self._salary}")e = Employee("张三", 25, 10000)# 公开成员:类外可直接访问
print(e.name)       # ✅ 正常访问# 受保护成员:能访问,但不建议
print(e._salary)    # ⚠️ 虽然能用,但按约定不要在类外用# 私有成员:直接访问会报错
print(e.__age)      # ❌ AttributeError

输出:

张三
10000Warnings/Errors:
Traceback (most recent call last):File "/home/cg/root/523f7e26/main.py", line 20, in <module>print(e.__age)      # ❌ AttributeError^^^^^^^
AttributeError: 'Employee' object has no attribute '__age'

Name Mangling(名字改编)

虽然 __age 是私有的,但 Python只是改名了,仍然可以通过 _类名__变量名 访问:

print(e._Employee__age)  # ✅ 访问到 25

这说明 Python 并不是“强制私有”,只是依靠开发者自觉遵守约定。

property() 实现封装

由于私有属性不能直接访问,我们通常用 property() 提供统一接口:

class Employee:def __init__(self, name, age):self.__name = nameself.__age = age# getter 方法def get_name(self):return self.__namedef get_age(self):return self.__age# setter 方法def set_name(self, name):self.__name = namedef set_age(self, age):self.__age = age# 定义属性name = property(get_name, set_name, doc="员工姓名")age = property(get_age, set_age, doc="员工年龄")e = Employee("张三", 25)print(e.name)   # ✅ 自动调用 get_name()
e.name = "李四" # ✅ 自动调用 set_name()
print(e.name)

输出:

张三
李四

使用 @property 装饰器(更优雅)

现代写法一般用 @property@属性.setter

class Employee:def __init__(self, name, age):self.__name = nameself.__age = age@propertydef name(self):return self.__name@name.setterdef name(self, value):self.__name = value@propertydef age(self):return self.__age@age.setterdef age(self, value):if value < 18:raise ValueError("年龄不能小于18")self.__age = valuee = Employee("张三", 25)
print(e.name, e.age)e.age = 30
print(e.age)# e.age = 10   # ❌ ValueError: 年龄不能小于18

优点:

  • 访问方式像属性(e.age
  • 内部依然受控(加校验逻辑)
http://www.dtcms.com/a/394182.html

相关文章:

  • Jetson 设备监控利器:Jtop 使用方式(安装、性能模式、常用页面)
  • 「数据获取」《商洛统计年鉴》(2001-2024)
  • 链表的探索研究
  • 2025年工程项目管理软件全面测评
  • JAVA算法练习题day17
  • Nacos:服务注册和配置中心
  • Linux 命令行快捷键
  • EasyClick JavaScript Number
  • LeetCode:42.将有序数组转化为二叉搜索树
  • 海外代理IP网站有哪些?高并发场景海外代理IP服务支持平台
  • JavaScript数据交互
  • 11.2.5 自定义聊天室
  • 力扣:字母异味词分组
  • Linux视频学习笔记
  • 2014/12 JLPT听力原文 问题四
  • Elasticsearch面试精讲 Day 21:地理位置搜索与空间查询
  • 华为数字化实战指南:从顶层设计到行业落地的系统方法论
  • 外部 Tomcat 部署详细
  • 【回文数猜想】2022-11-9
  • 216. 组合总和 III
  • Bugku-请攻击这个压缩包
  • 2. NumPy数组属性详解:形状、维度与数据类型
  • 【css特效】:实现背景色跟随图片相近色处理
  • vuex原理
  • 内存泄露怎么排查?
  • nginx配置防盗链入门
  • Kafka 多机房、跨集群复制、多租户、硬件与操作系统、全栈监控
  • leetcode136.只出现一次的数字
  • 力扣hot100:环形链表II(哈希算法与快慢指针法思路讲解)
  • 【算法】【Leetcode】【数学】统计1的个数 数位统计法