53、封装

小白量化 2025-12-13 07:54:40 24 举报

面向对象三大特征:
封装:通过将对象的属性和方法组合在一个单独的类中,并对外隐藏这些内部实现细节,来达到特定的设计目标。这样的设计不仅提高了代码的安全性,还增强了代码的可维护性和可重用性。

继承:继承是实现代码重用的有效手段。它允许我们定义一个类(父类/基类)来包含共同的属性和方法,然后创建这个类的一个或多个子类(派生类),子类可以继承父类的属性和方法,也可以添加新的属性或覆盖父类的方法。这样,当多个类具有相似的属性和方法时,我们可以通过继承来避免代码的重复编写,使得代码更加简洁、易读。

多态:不同类型的对象可以调用相同的方法,但每个对象会根据其所属的类的具体实现细节来执行该方法,从而产生不同的结果,这种设计机制能够提高代码的灵活性和可扩展性,使得软件能够更容易的适应未来的变化和需求。
1. 封装
1.1 含义
将复杂的信息和流程隐藏在内部进行处理,对外仅提供简单、直观的操作接口,让使用者通过简单的操作步骤即可实现所需功能。

1.2 类本质上就是一种封装,将属性和方法封装在内部

# 示例
class Person:
   def __init__(self, name, age): # 构造函数
       self.name = name # 实例属性(公开属性)
       self.age = age   # 实例属性(公开属性)
       
   def say_hello(self):   # 实例方法
       print(f"你好呀,我是{self.name},今年{self.age}岁了")
       
# 此时Person类就实现了封装,里面封装了2个实例属性和1个实例方法!
# print(self.age)     # NameError: name 'age' is not defined;

"""不管是类属性还是实例属性,类的外面都无法直接调用!
实例方法只能通过对象进行调用,不能通过类进行调用!"""

# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象调用封装好的成员
p1.say_hello()
print(p1.name)
print(p1.age)

p1.age = 35 # 类的外面修改实例属性,通过对象名.属性名去修改;这样不太安全,就有下面的类中定义私有!
p1.say_hello()

1.3 类中定义私有

(1)在Python中,没有内置的私有修饰符用于直接声明属性或方法为私有。如果希望某属性或方法不被类外部直接使用,可以在其名称前添加__前缀,可以添加私有属性,也可以添加私有方法!

# 示例1
class Person:
   def __init__(self, name, age): # 构造函数
       self.name = name  # 实例属性(公开属性)
       self.age = age    # 实例属性(公开属性)
       
# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象访问属性
print(p1.name)
p1.age = 30  # 在类的外面修改实例属性(公开属性),不安全!
print(p1.age)
# 示例2
# 定义私有属性
class Person:
   def __init__(self, name, age): # 构造函数
       self.name = name  # 实例属性(公开属性)
       self.__age = age  # 私有属性
       
# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象访问属性
print(p1.name)
print(p1.__age) # 无法访问私有属性
# 示例3
# 定义私有方法
class Person:
    def __init__(self, name, age): # 构造函数
       self.name = name  # 实例属性(公开属性)
       self.__age = age  # 私有属性
       
    def __func(self):
        print('私有方法~')
        
# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象访问属性
print(p1.name)
p1.__func()  # 无法访问私有方法

(2)如果确实需要访问或修改Python中的私有属性(通常不被推荐,因为它破坏了封装的原则),可以通过以下方式来实现:

① 类中定义公开方法(推荐)

# 示例
# 定义公开方法访问私有属性
class Person:
    def __init__(self, name, age):  # 构造函数
        self.name = name  # 实例属性(公开属性)
        self.__age = age  # 私有属性
        
    def get_age(self):
        return self.__age
        
# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象访问属性
print(p1.name)
print(p1.get_age())  # 通过定义公开方法可以访问私有属性

② property方法

# 示例1
# property封装方法,以属性名使用
class Person:
    def __init__(self, name, age):  # 构造函数
        self.name = name  # 实例属性(公开属性)
        self.__age = age  # 私有属性
        
    def get_age(self): 
        return self.__age
        
    # 封装get_age方法,以属性名使用
    age = property(get_age)  # 把get_age方法封装成属性,可以传一个,也可以传多个
    
# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象访问属性
print(p1.name)
print(p1.age)  # 把get_age方法封装成属性,可以访问
# 语法结构
property(fget, fset, fdel, doc)  # 可以传一个参数,也可以传多个参数

参数:

fget:对应获取属性值的方法,可省略
fset:对应设置属性值的方法,可省略

fdel:对应删除属性的方法,可省略

doc:  属性的文档字符串,如果省略,会把fget方法的文档字符串拿来使用

# 示例2
# property封装方法,以属性名使用
class Person:
    def __init__(self, name, age):  # 构造函数
        self.name = name  # 实例属性(公开属性)
        self.__age = age  # 私有属性

    def get_age(self):  # 获取属性值的方法
        """fget方法文档说明信息(文档字符串)"""
        return self.__age

    def set_age(self, age): # 设置属性名的方法
        self.__age = age
        print("修改后的年龄为:", self.__age)   # 一般不需要,只是展示效果

    def del_age(self):  # 删除属性值的方法
        del self.__age
        print('删除完成!')  # 一般不需要,只是展示效果

    # 封装get_age方法,以属性名使用
       # age = property(get_age, set_age, del_age)  # 类属性,类的里面,方法的外面
    age = property(get_age, set_age, del_age, "自定义说明信息")  # 类属性,类的里面,方法的外面


# 实例化对象
p1 = Person("xiaobai", 35)

# 通过对象访问属性
print(Person.age.__doc__)  # 省略doc参数后,打印查看doc
print(p1.age)
p1.age = 28  # 修改属性
print(p1.age)
del p1.age   # 删除属性
# 示例3
# property装饰器
class Person:
    def __init__(self, name, age, height):  # 构造函数
        self.name = name  # 实例属性(公开属性)
        self.__age = age  # 私有属性
        self.__height = height  # 私有属性
        
    @property # 获取私有height
    def height(self):
        return self.__height
        
    @height.setter  # 设置height
    def height(self, height):
        self.__height = height

    @height.deleter  # 删除height
    def height(self, height):
        self.__height = height
        print('删除完成!')

    def say_hello(self):
        print(f'你好呀,我是{self.name}, 今年{self.__age}岁了,身高{self.__height}')

# 实例化对象
p1 = Person("xiaobai", 35, 1.75)

# 通过对象访问属性
print(p1.height)
p1.height = 1.68 # 修改height属性
print(p1.height)
p1.say_hello()

③ 使用python的内部机制(名称改写,小人行为)

使用__开头的属性/方法,实际上是一种命名约定,旨在表明该属性是私有的,不应在类的外部直接访问。

Python解释器通过名称改写机制自动将其转换为_类名__属性/方法名的形式     ---   违背了封装原则,并且如果类的实现发生变化,比如类名更改,代码需要相应的进行更新,降低了代码的可维护性和可读性,完全违背了面向对象设计的初衷.实际开发中应避免这样做.

# 示例
class Person:
   def __init__(self, name, age):
       self.name = name
       self.__age = age  # 私有属性
       
   def __func(self):   # 私有方法
       print("这是私有方法!")
       print("哈哈哈哈哈哈哈哈哈哈哈哈")
       
# 实例化对象
p1 = Person("xiaobai", 35)

print(dir(p1))    # dir函数,查看对象的所有属性和方法
print(p1._Person__age) # 访问私有属性
p1._Person__func()     # 访问私有方法

1.4 封装的意义
(1)数据隐藏和保护:封装允许开发者将类的内部实现细节隐藏起来,只对外提供一套清晰、简洁的接口(即公共方法和属性)。这样做可以保护类的内部状态不被外部代码随意访问或修改,从而避免数据损坏或不一致的问题。
(2)提高代码的安全性:通过封装,可以控制对类成员的访问权限。在Python中,虽然不像某些语言那样有严格的访问修饰符(如private),但可以通过命名约定(如双下划线前缀)来模拟私有成员的效果。这有助于防止外部代码直接访问或修改类的敏感数据,从而提高代码的安全性。
(3)提高代码的可维护性:由于封装隐藏了类的内部实现细节,因此当内部实现发生变化时,只要接口保持不变,就不会影响到外部代码。
(4)增强代码的可读性:封装使得类的接口更加清晰和明确。外部代码只需了解如何使用类的公共接口,而无需关心类的内部实现细节。这有助于降低代码的复杂度,提高代码的可读性。

量化小白,从0开始学量化! 1

著作权归文章作者所有。 未经作者允许禁止转载!

最新回复 ( 0 )
发新帖
0
DEPRECATED: addslashes(): Passing null to parameter #1 ($string) of type string is deprecated (/data/user/htdocs/xiunophp/xiunophp.min.php:48)