面向对象三大特征:
封装:通过将对象的属性和方法组合在一个单独的类中,并对外隐藏这些内部实现细节,来达到特定的设计目标。这样的设计不仅提高了代码的安全性,还增强了代码的可维护性和可重用性。
继承:继承是实现代码重用的有效手段。它允许我们定义一个类(父类/基类)来包含共同的属性和方法,然后创建这个类的一个或多个子类(派生类),子类可以继承父类的属性和方法,也可以添加新的属性或覆盖父类的方法。这样,当多个类具有相似的属性和方法时,我们可以通过继承来避免代码的重复编写,使得代码更加简洁、易读。
多态:不同类型的对象可以调用相同的方法,但每个对象会根据其所属的类的具体实现细节来执行该方法,从而产生不同的结果,这种设计机制能够提高代码的灵活性和可扩展性,使得软件能够更容易的适应未来的变化和需求。
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)增强代码的可读性:封装使得类的接口更加清晰和明确。外部代码只需了解如何使用类的公共接口,而无需关心类的内部实现细节。这有助于降低代码的复杂度,提高代码的可读性。
著作权归文章作者所有。 未经作者允许禁止转载!