面向对象封装:
封装就是隐藏对象的属性和实现细节,仅对外提供公共访问方式。
封装的真谛在于明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,
然而定义属性的目的终归是要用,外部要想用类隐藏的属性,需要我们为其开辟接口,
让外部能够间接地用到我们隐藏起来的属性;被封装的内容的特点:1.外界不能直接访问,2.内部依然可以使用。
两个目的:
? 1.为了保证 关键数据的安全性。
? 2.对外部隐藏实现细节,隔离复杂度。
封装原则:
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。
学习了封装后就可以控制属性的权限;在python只要两种权限,
1.公开的.默认就是公开的。
2.私有的,只能由当前类自己使用。
在外界访问私有的内容:
属性虽然被封装了,但是还是需要使用的,在外界如何访问。
通过定义方法类完成对私有属性的修改和访问。
什么时候应该封装:
? 当有一些数据不希望外界可以直接修改时
? 当有一些函数不希望给外界使用时
如何使用封装呢?语法如下:
"""
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形
类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式:
"""
class A:
__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
def __init__(self):
self.__X=10 #变形为self._A__X
def __foo(self): #变形为_A__foo
print(‘from A‘)
def bar(self):
self.__foo() #只有在类内部才可以通过__foo的形式访问到.
#A._A__N是可以访问到的,
#这种,在外部是无法通过__x这个名字访问到。
封装方法:
其目的是隔离复杂度。
"""
在编程语言里,对外提供的接口(接口可理解为了一个入口),
可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。
"""
# 取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
# 对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
# 隔离了复杂度,同时也提升了安全性
class ATM:
def __card(self):
print(‘插卡‘)
def __auth(self):
print(‘用户认证‘)
def __input(self):
print(‘输入取款金额‘)
def __print_bill(self):
print(‘打印账单‘)
def __take_money(self):
print(‘取款‘)
def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
a=ATM()
a.withdraw()
封装数据:
"""
将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,
然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
"""
class Teacher:
def __init__(self,name,age):
# self.__name=name
# self.__age=age
self.set_info(name,age)
def tell_info(self):
print(‘姓名:%s,年龄:%s‘ %(self.__name,self.__age))
def set_info(self,name,age):
if not isinstance(name,str):
raise TypeError(‘姓名必须是字符串类型‘)
if not isinstance(age,int):
raise TypeError(‘年龄必须是整型‘)
self.__name=name
self.__age=age
t=Teacher(‘jack‘,18)
t.tell_info()
t.set_info(‘jack‘,19)
t.tell_info()
property装饰器:
property就是将一个类的函数定义成特性以后,对象再去使用的时候obj.name,
根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。
"""
property装饰就是为了使得调用方式一致;有三个相关的装饰器 :
1.property 该装器用在获取属性的方法上
2.@key.setter 该装器用在修改属性的方法上
3.@key.deleter 该装器用在删除属性的方法上
key是被property装饰的方法的名称 也就是属性的名称
内部会创建一个对象 变量名称就是函数名称
所以在使用setter和deleter时 必须保证使用对象的名称取调用方法
所以是 key.setter
"""
class Foo:
def __init__(self,val):
self.__NAME=val #将所有的数据属性都隐藏起来
@property
def name(self):
return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)
@name.setter
def name(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError(‘%s must be str‘ %value)
self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME
@name.deleter
def name(self):
raise TypeError(‘Can not delete‘)
f=Foo(‘egon‘)
print(f.name)
# f.name=10 #抛出异常‘TypeError: 10 must be str‘
del f.name #抛出异常‘TypeError: Can not delete‘
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;
而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。
这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
abc模块的使用:
抽象类概念
抽象类是一个特殊的类,只能被继承,不能实例化
2.为什么要有抽象类
其实在未接触抽象类概念时,我们可以构造香蕉、苹果、梨之类的类,然后让它们继承水果这个的基类,水果的基类包含一个eat函数。
但是你有没有想过,我们可以将香蕉、苹果、梨实例化,去吃香蕉、苹果、梨。但是我们却不能将水果实例化,因为我们无法吃到叫水果的这个东西。
所以抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。
3.抽象类的作用
在不同的模块中通过抽象基类来调用,可以用最精简的方式展示出代码之间的逻辑关系,让模块之间的依赖清晰简单。
抽象类的编程,让每个人可以关注当前抽象类的方法和描述,而不需要考虑过多的实现细节,这对协同开发有很大意义,也让代码可读性更高。
"""
abc 不是随意取的 而是单词的缩写
abstract class
翻译为抽象类
抽象类的定义 :
类中包含 没有函数体的方法
"""
import abc
class AClass(metaclass=abc.ABCMeta):
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def run1(self):
pass
class B(AClass):
def run(self):
print("runrunrurn...")
b = B()
接口:
接口是一套协议规范,明确子类们应该具备哪些功能;抽象类是用于强制要求子类必须按照协议中规定的来实现;
然而,python不推崇限制你的语法, 我们可以设计成鸭子类型,既让多个不同类对象具备相同的属性和方法;
对于使用者而言,就可以以不变应万变,轻松的使用各种对象;只要遵循了USB接口协议,都能够被电脑所调用;
接口主要是方便了对象的使用者,降低使用者的学习难度;只要学习一套使用方法,就可以以不变应万变。
class Interface:
def f1(self):
‘‘‘
to do something
:return:
‘‘‘
class Something(Interface):
def f1(self):
print(‘to do something...‘)
def f2(self):
print(‘to do other..‘)
原文:https://www.cnblogs.com/sweet-i/p/11252771.html