Python第14讲

封装

引入

  • 封装是面向对象的三大特性之一
  • 如果不封装的话,可以直接通过对象.属性的方式来修改属性的值,数据会非常不安全
  • 封装是一种增强数据安全的方式
    1. 属性不能随意修改(可修改,但不要轻易修改,遵循OCP原则)
    2. 属性不能修改成任意值

使用

  • 定义 —— 指隐藏对象中一些不希望被外界访问到的属性和方法
弱封装
  • 将对象的属性名修改成外界不知道的名字
  • 提供一个getter和setter方法,使外部可以访问并修改属性
  • 封装增加了类定义的复杂度,但也确保了数据的安全性
    1. 隐藏属性名,使调用者无法随意的修改对象的属性
    2. 增加了getter和setter方法,很好的控制属性是否只读和修改
    3. 使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
    4. 读取和修改属性的时候可以做一些其他处理
# 简单封装方法
class Person:
	def __init__(self,name):
		self.hidden_name = name
	def run(self):
		print('%s跑步' % self.hidden_name)
p = Person('黑寡妇')
p.run()  # 黑寡妇跑步
p.name = '绿巨人'
p.run()  # 黑寡妇跑步
dir(p)	# p.name 是给p对象新增了一个name属性
'''
 [...,'hidden_name', 'name', 'run']
'''
p.name	# '绿巨人'
p.hidden_name('绿巨人')
p.run()  # 绿巨人跑步

# 简单封装的访问和修改属性方法,并增加数据验证或其他操作环节
class Person:
	def __init__(self,age):
		self.hidden_age = age
	def get_age(self):
		# get_age()方法用来获取对象的name属性
		return self.hidden_age
	def set_age(self,age):
		if age >= 0:
			self.hidden_age = age
p = Person(3)
p.get_age()  # 3
p.set_age(5)
p.get_age()  # 5
p.set_age(-3) 
p.get_age()  # 5  由于不符合判断条件,因此无法修改
强封装
  • 方法 —— 对象的属性使用双下划线的方式(__属性名)
    • 这种方法的属性在类对象中变成 _类名__属性名
class Person:
	def __init__(self,name)
		self.__name = name
	def get_name(self):
		return self.__name
p = Person('绿巨人')
p.get_name  # 绿巨人
p.__name = '黑寡妇'  # 相当于给实例对象增加了一个__name属性,并没有修改初始化属性
dir(p)
'''
['_Person__name',...,'get_name']
'''
p._Person__name  # 绿巨人
常用封装方法
  • 方法 —— 通常在属性名前加单下划线,告知别人是封装的属性即可,因为任何封装都可以修改属性。
  • 如果需要修改属性,增加getter和setter方法即可
class Person:
	def __init__(self,name):
		self._name = name

类的装饰器

@property

  • 功能 —— 修饰方法
    1. 将方法转换成相同名称的属性,并且为只读属性
    2. 不能创建一个被property修饰的属性
class Person:
	def __init__(self,name):
		self._name = name
	@property
	def name(self):
		return self._name
p = Person('哈哈')
p.name   # 哈哈  方法变成属性了
p.name = '呵呵'  # AttributeError: can't set attribute

@属性名.setter

  • 功能 —— 修改属性值方法
    1. 通常不会和property对同一个方法使用
    2. 可以修改属性的值
# property和setter对比
class Person:
	def __init__(self,name):
		self._name = name
	@property
	def name(self):
		return self._name
	@name.setter
	def name(self,name):
		self._name = name
p = Person('haha')
p.name  # haha
p.name = 'hehe'
p.name  # hehe

@属性名.deleter

  • 功能 —— 删除属性名
    1. deleter装饰器不能单独使用,必须配合property装饰器使用
    2. 将属性删除
# 不添加deleter装饰器
class Person:
	def __init__(self,name):
		self._name = name
	@property
	def name(self):
		return self._name
	def name(self):
		del self._name
p = Person('haha')
p.name  # <bound method Person.p of <__main__.Person object at 0x00000250A88E7430>>
p.name()  # None
dir(p)
'''
[...,'_name', 'name']
'''

# 添加deleter装饰器
class Person:
	def __init__(self,name):
		self._name = name
	@property
	def name(self):
		return self._name
	@name.deleter
	def name(self):
		del self._name
p = Person('haha')
p.name  # haha
del p.name
p.name  # AttributeError: 'Person' object has no attribute '_name'
dir(p)
'''
[...,'name']
'''

继承

  • 继承是面向对象的三大特性之一
    1. 提高了代码的复用性
    2. 让类与类之间产生了关系(多态的特性有此衍生)
  • 使用方法
    1. 在定义类的时候,可以在类名后面的括号中指定当前类的父类(超类、基类)
    2. 在创建类的时候,如果省略了父类,则默认父类为object(object是所有类的父类)

方法的重写

  • 如果子类中有和父类同名的方法,则通过子类调用方法时,会调用子类的方法而不是父类的方法。这个特点称之为方法的重写(覆盖,override)
# 继承及方法重写
class Person:
	def __init__(self,name):
		self._name = name
	def run(self):
		print('%s跑步' % self._name)
	def sleep(self):
		print('%s睡觉' % self._name)

class Doctor(Person):
	def sleep(self):
		print ('%s正在睡觉...' % self._name)
d = Doctor('医生')
d.run()  # 医生跑步
d.sleep()  # 医生正在睡觉...
d.speak() # AttributeError: 'Doctor' object has no attribute 'speak'
Doctor.__mro__  # 继承调用顺序查看(<class '__main__.Doctor'>, <class '__main__.Person'>, <class 'object'>)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值