? ? ? ? 当然:封装不仅仅是把数据和功能组合在一起,更重要的是要对外部世界隐藏实体的实现细节,提供合理的接口和访问权限,保证程序的可维护性、安全性。
?????????在程序设计中,封装(Encapsulation)是一种面向对象编程的特性,它不仅仅是对具体对象的抽象,更是对数据和行为的抽象,它将数据和方法封装在一个实体中,对外部世界隐藏实体内部的复杂性,只暴露必要的接口供外部使用。
? ? ? ? 封装就不得不提私有化?Private Encapsulation)是指将类的某些属性或方法设置为私有访问权限,使其只能在类内部被访问和修改,而不能被外部程序直接访问。
????????通过将属性或方法设置为私有(private),可以实现对类内部实现细节的隐藏,避免外部程序对类的内部状态进行非法访问或修改,从而提高程序的安全性和稳定性。私有化可以有效地封装类的内部实现,使得外部程序只能通过公共接口来与类进行交互。
在面向对象编程中,私有属性或方法通常使用访问修饰符 private 来标识,它们只能在类的内部被访问和修改。这样可以确保类的内部状态不会被外部程序随意修改,而只能通过公共接口提供的方法来操作和获取数据。
例如,一个银行账户类中的密码属性可以被私有化,外部程序无法直接访问和修改密码,只能通过提供的公共方法来验证密码或修改密码。这样可以保护用户的隐私和账户安全。
私有化的优点包括:
????????总之,私有化是封装特性的一部分,它通过限制外部程序对类的访问权限来保护类的内部实现,提高代码的安全性和稳定性。
????????封装的方法是指将类中的行为(方法)封装在类的内部,通过公共接口(公共方法)来对外暴露和调用。
????????封装的方法通常使用访问修饰符来标识其访问权限,常见的修饰符包括 public、private 和 protected。
公共方法(public methods):公共方法是类的公开接口,可以被外部程序直接访问和调用。公共方法被声明为 public 访问修饰符,可以在类的内部和外部被访问和调用。
私有方法(private methods):私有方法是类的私有接口,只能在类的内部被访问和调用。私有方法被声明为 private 访问修饰符,外部程序无法直接访问和调用私有方法。
受保护方法(protected methods):受保护方法是类的受保护接口,只能在类的内部和其子类中被访问和调用。受保护方法被声明为 protected 访问修饰符,外部程序无法直接访问和调用受保护方法。
????????通过封装方法,可以将类的内部实现隐藏起来,只暴露必要的公共接口。这样可以提高代码的安全性和稳定性,同时也使得类的使用更加简单和清晰。外部程序只需要通过公共方法来与类进行交互,而不需要了解类的具体实现细节。
????????总结起来,封装的方法是将类的行为封装在类的内部,通过公共接口来对外暴露和调用。这种封装的方式可以提高代码的安全性和稳定性,同时也提供了一种清晰、简洁的方式来与对象进行交互。
????????隐藏属性的方法是通过将类的属性设置为私有(private)访问权限来实现的。私有属性只能在类的内部被访问和修改,外部程序无法直接访问和修改私有属性。
????????隐藏属性的方法可以确保类的内部状态不会被外部程序随意修改,只能通过公共接口提供的方法来操作和获取数据。这样可以保护对象的数据完整性和安全性,并减少对外部的暴露。
隐藏属性的方法步骤如下:
将属性声明为私有:在类中将需要隐藏的属性声明为私有,使用 private 访问修饰符标识,例如 private int age;。
提供公共方法:在类中提供公共方法(getters 和 setters)来操作和获取私有属性的值。公共方法被声明为公共访问修饰符(public),可以被外部程序访问和调用。
Getter 方法(访问器):用于获取私有属性的值,通常以 get 开头,例如 public int getAge() { return age; }。
Setter 方法(修改器):用于设置私有属性的值,通常以 set 开头,例如 public void setAge(int age) { this.age = age; }。
????????通过提供公共方法来操作私有属性,可以实现对属性的控制和验证。例如,在 Setter 方法中可以添加验证逻辑,确保赋予属性的值满足一定的条件,如年龄不能为负数。
????????隐藏属性的方法可以保护对象的数据,防止外部程序对属性的非法访问和修改。同时,公共方法还提供了一种清晰、统一的方式来与对象进行交互,使得代码更易读和维护。
class YinCan:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
if age >= 0:
self.__age = age
else:
print('年龄不能为为负数!')
# 创建Person 对象并使用公告方法操作隐藏属性
person = YinCan('maodada',26)
print(person.get_name()) # maodada
print(person.get_age()) # 26
person.set_name("BOB")
person.set_age(30)
print(person.get_name()) # BOB
print(person.get_age()) # 30
person.set_age(-56) # 年龄不能为为负数!
name和_name以及__name的实例
class Person:
def __init__(self,name):
self.name = name # 公共属性
self._name = name # 受保护
self.__name = name # 私有属性
def get_name(self):
return self.name
# 创建 Person对象
person = Person('xidada')
print(person.name) # xidada
print(person._name) # xidada
print(person.__name) # AttributeError: 'Person' object has no attribute '__name'. Did you mean: '_name'?
在上面的例子中,我们使用了三种不同的命名方式来表示属性的可访问性。
self.name
:这是最简单的方式,属性没有任何特殊的命名规则。外部程序可以直接访问和修改这个属性。
self._name
:这是一种约定俗成的命名方式,以单下划线开头表示属性是受保护的,外部程序可以访问这个属性,但是建议遵守惯例,尽量使用公共的getter和setter方法来访问和修改属性。
self.__name
:这是一种使用双下划线开头的命名方式,表示属性是私有的。私有属性只能在类的内部访问,外部程序无法直接访问。在示例中,我们使用get_private_name()
方法在类的内部间接访问私有属性。
????????需要注意的是,以双下划线开头的属性名会进行名称修饰(name mangling)以避免命名冲突。在类的外部,我们无法直接访问__name
属性,会导致AttributeError错误。
????????总结起来,
name
属性是公共的,_name
属性是受保护的,__name
属性是私有的。根据属性的可访问性需求,选择适当的命名方式来表示属性的访问权限。
?在Python中,property
是一种特殊的装饰器,它允许你将一个方法转换为一个属性,从而实现对该属性的访问和修改。通过使用property
装饰器,可以自定义属性的读取、写入和删除行为,并提供更加灵活的访问控制。
????????使用property
装饰器时,需要定义一个getter方法、一个setter方法和一个deleter方法(可选)。这些方法分别用于获取属性的值、设置属性的值和删除属性。
class ShiLi():
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,value):
if value >= 0:
self._name = value
else:
raise ValueError('里面的值不能为负数!')
@name.deleter
def name(self):
del self._name
# 创建x对象
x = ShiLi(5)
print(x.name) # 5
x.name = 10
print(x.name) # 10
del x.name
print(x.name)
# AttributeError: 'ShiLi' object has no attribute '_name'. Did you mean: 'name'?
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
面向对象的封装有三种方式:
????????使用property
的主要目的是为了实现对类的属性访问和修改的控制,以提供更加灵活和可靠的代码。
封装性:通过将属性的获取、设置和删除封装在方法中,可以隐藏底层实现细节,使代码更加清晰和易于维护。这样,其他代码只需要通过属性访问接口来操作属性,而不需要了解属性的具体实现。
访问控制:使用property
可以为属性的读取和写入过程添加额外的逻辑。例如,可以在设置属性值之前进行验证或转换。这样,可以确保属性的值符合特定的规则,并防止无效数据的出现。
兼容性:通过property
装饰器,可以将现有的方法转换为属性,而不会破坏现有的代码结构。这意味着可以在不修改现有代码的基础上,为类添加新的属性访问方式。这对于与现有代码库的兼容性和扩展性非常重要。
代码一致性和易用性:使用property
可以使代码更加一致和易用。属性访问方式更接近于直接访问属性,而不是使用方法调用。这使得代
class Rctena:
def __init__(self, width, height):
self._width = width # 初始化宽度
self._height = height # 初始化高度
@property
def width(self):
return self._width
@width.setter
def width(self, value):
if value > 0:
self._width = value
else:
raise ValueError('宽度必须大于0')
@property
def height(self):
return self._height
@height.setter
def height(self, value):
if value > 0:
self._height = value
else:
raise ValueError('高度必须大于0')
x = Rctena(10,6)
print(x.width,x.height)
x.height = 15
print(x.height) # 输出:15
x.height = -5 #ValueError: 高度必须大于0
码更加自然和简洁,同时提高了代码的可读性和可维护性。
可变性控制:通过在setter
方法中添加逻辑,可以对属性的修改过程进行控制。这可以防止属性的意外修改或非法修改,并确保类的内部状态保持一致。
????????总之,使用
property
装饰器可以提供更好的封装性、访问控制、可兼容性、代码一致性和易用性,以及对属性修改过程的控制能力。它是一种有效的编程技术,有助于编写高质量、可维护的代码。
????????封装指的是将类的属性和方法隐藏起来,防止外部直接访问和修改。这样可以保护类的数据和实现细节,同时提供公共接口供外部使用。通过封装,我们可以控制对类的访问,防止意外修改导致程序出错。
????????扩展性指的是在不修改原有代码的基础上,通过添加新的功能或修改现有功能来满足新需求。扩展性良好的代码可以灵活应对变化,减少代码重复和修改,提高代码的可维护性和可扩展性。
class Rectangle:
def __init__(self, width, height):
self._width = width # 初始化宽度
self._height = height # 初始化高度
@property
def width(self):
"""获取矩形的宽度"""
return self._width
@width.setter
def width(self, value):
"""设置矩形的宽度"""
if value > 0:
self._width = value
else:
raise ValueError("宽度必须大于0")
@property
def height(self):
"""获取矩形的高度"""
return self._height
@height.setter
def height(self, value):
"""设置矩形的高度"""
if value > 0:
self._height = value
else:
raise ValueError("高度必须大于0")
def area(self):
"""计算矩形的面积"""
return self._width * self._height
x = Rectangle(10, 6)
print(x.width, x.height) # 输出:10 6
print(x.area()) # 输出:60
x.width = 15
print(x.width) # 输出:15
print(x.area()) # 输出:90