Python 面向对象之封装和装饰器property
【一】概念
封装 是面向对象的三大特征 之一封装:将属性 和方法 打包在一起 ,并对外部提供接口 ,控制外部对内部数据的访问和修改 封装有助于隐藏对象的内部细节 ,提供更清晰的结构,提高 了代码的安全性 和可维护性
【二】隐藏属性和方法
【1】概念
类的设计者不想使用者直接访问到属性,就可以将属性进行隐藏,有隐藏属性 和隐藏方法 python
的class
机制采用双下划线开头 的方式进行隐藏属性和方法 (私有属性、私有方法 )但是并没有真正意义上的隐藏,隐藏的机制 :
在类的定义阶段 ,双下划线开头的属性和方法都会发生变形 属性 变形:_类名__属性 方法 变形:_类名__方法 在类的外部 可以通过访问变形 ,可以使用 这个私有属性或者方法 然而类的内部 是可以通过双下划线访问 的,这是因为在检查类体代码语法时 统一发生 了变形 (类定义阶段 ) 这种变形指在类的定义阶段 (检查类体语法时 )发生一次 ,之后再定义的双下划线开头的属性和方法都不会变形,即可以直接通过双下划线开头访问
【2】代码解释
class A :
name = "bruce"
__private_age = 18
def instance_method ( self) :
print ( "这是是实例方法" )
def __private_method ( self) :
print ( "这是私有方法" )
a = A( )
print ( a. name)
print ( A. name)
a. instance_method( )
A. instance_method( a)
class A :
name = "bruce"
__private_age = 18
def instance_method ( self) :
print ( "这是是实例方法" )
print ( f"name: { self. name} age: { self. __private_age} " )
self. __private_method( )
def __private_method ( self) :
print ( "这是私有方法" )
a = A( )
print ( a. name)
print ( a. _A__private_age)
a. instance_method( )
a. _A__private_method( )
a. __private_age = 20
print ( a. __private_age)
print ( a. _A__private_age)
【三】开放接口
定义了属性和方法,那么这个属性和方法就一定是有一定的作用的,不能仅仅只是隐藏起来 即隐藏不是目的 ,目的是为了更安全更好的使用
【1】隐藏属性
【1】概念
隐藏属性:将属性隐藏起来,限制类外部 对数据的直接访问 ,只 用通过类提供的接口 来允许类外部间接访问 和操做,接口之上 我们可以添加额外的逻辑来对数据进行处理 ,这样更安全可靠
【2】代码解释
在银行系统中,其中金额是极其重要的数据,所以我们要隐藏这个属性,提供接口给类外部间接操作数据
class AtmUser :
def __init__ ( self, name) :
self. username = name
self. __money = 100
def withdraw_money ( self, money: int ) :
if type ( money) != int :
print ( "取款失败:输入非法" )
elif money > self. __money:
print ( "取款失败:你没有这么多钱" )
else :
self. __money -= money
print ( f"取款成功:你还有 { self. __money} 元" )
def recharge_money ( self, money: int ) :
if type ( money) != int :
print ( "充值失败:输入非法" )
else :
self. __money += money
print ( f"充值成功:你还有 { self. __money} 元" )
bruce_atm = AtmUser( "bruce" )
bruce_atm. withdraw_money( 100 )
bruce_atm. recharge_money( 100 )
【2】隐藏方法
【1】概念
【2】代码解释
同样的在银行系统中,客户的操作有存钱取钱等,银行却需要更多的方法,比如检验你登录或者插卡没有,用户的身份验证、金额的验证等方法,这些方法不需要给客户提供,所以要隐藏这些方法,隔离复杂度
class AtmUser :
def __init__ ( self, name) :
self. username = name
self. __money = 100
def __card_check ( self) :
print ( "检查是否插卡" )
pass
def __check_user_info ( self) :
print ( "检查用户信息" )
pass
def __money_chcek ( self) :
print ( "检查金额是否满足要求" )
pass
def withdraw_money ( self, money: int ) :
self. __card_check( )
self. __check_user_info( )
self. __money_chcek( )
self. __money -= 100
【四】装饰器property
property
是一种特殊的装饰器 ,用于将类的方法伪装成类的属性 它能够将一个方法伪装成只读属性 ,使得在访问这个属性时可以像访问普通属性一样 ,实际 上还是调用相应的方法
【1】应用场景一:MyDivmod
在内置函数divmod
中输入 被除数 和除数 就可以得到商 和余数 商和余数 可以用方法计算得到,但是这两个更像是属性 ,所以可以用装饰器property装饰成属性
class MyDivmod :
def __init__ ( self, dividend, divisor) :
self. __dividend = dividend
self. __divisor = divisor
@property
def discuss ( self) :
return self. __dividend // self. __divisor
@property
def remainder ( self) :
return self. __dividend % self. __divisor
result = MyDivmod( 9 , 4 )
print ( f"商: { result. discuss} " )
print ( f"余: { result. remainder} " )
【2】应用场景二:装饰器链
私有属性在类里面定义好了,我们希望在类的外部获取它的值、修改他的值和删除这个值,可以使用提供的接口方法,但是我们更想让他像一个普通的属性一样,直接通过.
号运算符有进行取值、赋值和删除值 注意:三个方法的名字必须一样,形参可以不通过 注意:三个方法的名字必须一样,形参可以不通过 注意:三个方法的名字必须一样,形参可以不通过
class A :
__x = "aaa"
@property
def x ( self) :
print ( "取值方法" )
return self. __x
@x. setter
def x ( self, value) :
print ( "赋值方法" )
self. __x = value
@x. deleter
def x ( self) :
print ( "删除值方法" )
del self. __x
a = A( )
print ( a. x)
a. x = "bb"
del a. x
【3】应用场景三:经典的属性定义方式
在场景二中每个取值赋值删除值的方法前面都需要添加装饰器property对应的内容 为了简化代码 ,我们可以使用property()函数来创建一个属性 ,并将相应的取值、赋值和删除值的方法传递给它 注意:三个方法的名字不能相同,形参可以不同,传入property函数默认是位置传参 注意:三个方法的名字不能相同,形参可以不同,传入property函数默认是位置传参 注意:三个方法的名字不能相同,形参可以不同,传入property函数默认是位置传参
class A :
__x = "aaa"
def get_x ( self) :
print ( "取值方法" )
return self. __x
def set_x ( self, value) :
print ( "赋值方法" )
self. __x = value
def del_x ( self) :
print ( "删除值方法" )
del self. __x
x = property ( get_x, set_x, del_x)
a = A( )
print ( a. x)
a. x = "bb"
del a. x
【五】总结