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

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

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

进行封装了的类:

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)这三个错误的属性值进行了报错并取消了修改

name:Alice, age:25, height:140,width:100
Invalid age!
Invalid height!
Invalid width!
name:Bob, age:25, height:140,width:100

未进行封装的类:

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

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

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类,并创建实例进行图形绘制

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()

生成的图片:

在Python中进行封装-LMLPHP

 

03-31 13:16