在Python中进行封装

在Python中,封装是一种面向对象编程(OOP)的特性,它允许我们将数据(属性)和操作这些数据的方法(函数)捆绑在一起,形成一个独立的对象。封装的主要目的是隐藏对象的内部状态,并只通过对象提供的方法来访问和操作这些状态,用于保护对象的数据完整性,并防止外部代码直接访问或修改对象的内部状态。

Python中的封装可以通过定义类来实现,在类中,我们可以将属性和方法定义为私有(只能在类内部访问)或公有(可以在类外部访问)。

以下是一个案例,在自创建的Person类,使用双下划线前缀进行标识两个私有属性__name__age,以及四个公有方法get_name()get_age()set_name()set_age(),采用公共方法获取其私有属性,同时对修改私有属性进行了合法性检查,在公共方法修改了属性值后如果某个属性值错误,会进行报错并取消该属性的修改

进行封装了的类:

python 复制代码
class Person:  
    def __init__(self, name, age, height, width):  
        # 私有属性,使用双下划线前缀  
        self.__name = name  
        self.__age = age
        self.__height = height
        self.__width = width
  
    # 公有方法,用于获取私有属性的值  
    def get_name(self):  
        return self.__name  
  
    def get_age(self):  
        return self.__age

    def get_height(self):  
        return self.__height

    def get_width(self):  
        return self.__width  
  
    # 公有方法,用于设置私有属性的值  
    def set_name(self, name):  
        self.__name = name  
  
    def set_age(self, age):  
        if age >= 0 and age <= 120:  # 对年龄进行合法性检查  
            self.__age = age  
        else:  
            print("Invalid age!")

    def set_height(self, height):  
        if height >= 0 and height <= 250:  # 对身高进行合法性检查  
            self.__height = height  
        else:  
            print("Invalid height!") 

    def set_width(self, width):  
        if width >= 50 and width <= 500:  # 对体重进行合法性检查  
            self.__width = width  
        else:  
            print("Invalid width!")
  
# 创建Person对象  
person = Person("Alice", 25, 140, 100)  
  
# 通过公有方法访问和修改私有属性  
print(f"name:{person.get_name()}, age:{person.get_age()}, height:{person.get_height()},width:{person.get_width()}")  
person.set_name("Bob")  
person.set_age(-5)
person.set_height(300)
person.set_width(550)  
print(f"name:{person.get_name()}, age:{person.get_age()}, height:{person.get_height()},width:{person.get_width()}")  
 

这里可以看到age(-5)、width(550)、height(300)这三个错误的属性值进行了报错并取消了修改

python 复制代码
name:Alice, age:25, height:140,width:100
Invalid age!
Invalid height!
Invalid width!
name:Bob, age:25, height:140,width:100

未进行封装的类:

直接使用公共类并访问和修改属性

python 复制代码
class Person:    
    def __init__(self, name, age, height, width):    
        self.name = name    
        self.age = age  
        self.height = height  
        self.width = width  
  
# 创建Person对象    
person = Person("Alice", 25, 140, 100)    
    
# 直接访问和修改属性    
print(f"name:{person.name}, age:{person.age}, height:{person.height}, width:{person.width}")    
person.name = "Bob"    
person.age = 30  
person.height = 160  
person.width = 200  
print(f"name:{person.name}, age:{person.age}, height:{person.height}, width:{person.width}")

# 创建一个新的Person对象并尝试设置无效的属性值  
invalid_person = Person("Charlie", -5, 300, 600) 
  
# 输出这个对象属性
print(f"name:{invalid_person.name}, age:{invalid_person.age}, height:{invalid_person.height}, width:{invalid_person.width}")

这里可以看到终端输出的信息中,Charlie的年龄和身高体重存在明显问题,是无效属性值,而且也展示了未进行封装的坏处:

  1. 数据完整性受损:没有对数据进行合法性检查,无效或不合理的数据可以被接受并存储在对象中。

  2. 代码可维护性降低:如果后续需要添加额外的逻辑来处理属性,需要找到并修改所有直接修改属性的代码,而不是只修改一个setter方法。

  3. 安全性问题:对象的内部状态可以被外部代码随意修改,可能导致对象处于不一致或不稳定的状态。

  4. 封装性丧失:封装是面向对象编程的四大基本原则之一,它允许我们隐藏对象的内部实现细节,只通过明确定义的接口与外界交互。未封装的类违反了这一原则。

python 复制代码
name:Alice, age:25, height:140, width:100
name:Bob, age:30, height:160, width:200
name:Charlie, age:-5, height:300, width:600

这里新建一个用于绘制年龄、身高、体重条形图的Python文件,继承上述代码中的Person类,并创建实例进行图形绘制

python 复制代码
import matplotlib.pyplot as plt  
from Encapsulation import Person   
  
class StatisticsPerson(Person):  
    instances = []  # 类变量,用于存储实例  
  
    def __init__(self, name, age, height, width):  
        super().__init__(name, age, height, width)  
        self.instances.append(self)  # 将新创建的实例添加到instances列表中  
  
    # 使用静态方法统计所有人的年龄、身高和宽度,并绘制条状图  
    @staticmethod  
    def plot_statistics():  
        ages = [person.get_age() for person in StatisticsPerson.instances]  
        heights = [person.get_height() for person in StatisticsPerson.instances]  
        widths = [person.get_width() for person in StatisticsPerson.instances]  
  
        x = range(len(StatisticsPerson.instances))  
  
        plt.figure(figsize=(10, 6))  
        plt.bar(x, ages, label='Age', width=0.25)  
        plt.bar([i + 0.25 for i in x], heights, label='Height', width=0.25)  
        plt.bar([i + 0.5 for i in x], widths, label='Width', width=0.25)  
  
        plt.xlabel('Name')  
        plt.ylabel('Values')  
        plt.title('Comparison of Age, Height, and Width')  
        plt.xticks([i + 0.25 for i in x], [person.get_name() for person in StatisticsPerson.instances], rotation=45)  
        plt.legend() 
        plt.savefig("GGboy.png") 
        plt.show()  
  
# 创建StatisticsPerson对象  
person1 = StatisticsPerson("Alice", 25, 140, 100)  
person2 = StatisticsPerson("Bob", 30, 160, 200)  
person3 = StatisticsPerson("Charlie", 40, 175, 150)  
  
# 绘制并保存统计图  
StatisticsPerson.plot_statistics()

生成的图片:

相关推荐
Edward.W12 分钟前
Python uv:新一代Python包管理工具,彻底改变开发体验
开发语言·python·uv
小熊officer12 分钟前
Python字符串
开发语言·数据库·python
月疯25 分钟前
各种信号的模拟(ECG信号、质谱图、EEG信号),方便U-net训练
开发语言·python
荒诞硬汉28 分钟前
JavaBean相关补充
java·开发语言
提笔忘字的帝国43 分钟前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
flysh051 小时前
C# 架构设计:接口 vs 抽象类的深度选型指南
开发语言·c#
2501_941882481 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
bkspiderx1 小时前
C++中的volatile:从原理到实践的全面解析
开发语言·c++·volatile
小鸡吃米…1 小时前
机器学习中的回归分析
人工智能·python·机器学习·回归
沛沛老爹1 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理