封装、property特性、绑定方法与非绑定方法
一、封装
1.1 封装
封装就是将数据和功能都整合到一起
在封装的基础上,针对被封装到类或者对象中的属性,我们可以严格控制对他们的访问,分两步实现,隐藏和接口
1.2 隐藏
(1)在定义类或者初始化对象时,在属性前加__,就会将属性隐藏起来
但是这种隐藏只是一种变形 _类名__属性名,并没有 真正的隐藏起来
(2)该变形操作是定义阶段扫描语法时产生的变形,类定义之后赋值的以__开头的属性不会发生变形
(3)这种隐藏是对外不对内的,在类内部可以通过self.__属性名 来访问
(4)在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
class Student:
__school = '外婆教大' # _Student__school = '外婆教大'
def __init__(self, name, age):
self.__name = name # _Student__name = name
self.age = age
stu1 = Student('jason', 18)
stu1.__x = 111
print(stu1.__dict__) # {'_Student__name': 'jason', 'age': 18, '__x': 111}
print(stu1._Student__school) # 外婆教大
print(stu1.__x) # 111 因为不是在类定义时加的__,所以可以直接访问
1.3 隐藏属性的意义
① 把数据属性隐藏起来的意义:在类内开放接口的,让外界使用者通过接口来操作属性值,
我们可以在接口之上附加任意的逻辑来严格控制外界使用者对属性的操作
class Student:
__school = '外婆教大' # _Student__school = '外婆教大'
def __init__(self, name, age):
self.__name = name # _Student__name = name
self.__age = age # _Student__age = age
def set_age(self, x):
if type(x) is not int:
print('年龄必须是整数')
return
self.__age = x
stu1 = Student('jason', 18)
stu1.set_age(19) # 可以通过调用set_age来执性行对属性__age的修改
print(stu1._Student__age)
② 把功能属性隐藏起来:隔离复杂度
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()
在调用withdraw的时候背后调用的一些其他功能可以隐藏起来,使用者并不需要知道这个功能是由哪几个功能拼接而成的,
隔离了复杂度的同时还提高了安全性
二、特性(property)
2.1 直接添加装饰器
property是一种特殊的属性,访问它的时候会执行一段功能(函数),然后返回值
示例:将BMI指数功能做成一个数据一样的属性,而不是一个功能调用
class People:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
@property # 装饰器
def bmi(self):
return self.weight / (self.height ** 2)
p = People('cc', 70, 1.7)
print(p.bmi) # # 24.221453287197235
代码中的特性bmi不能被直接赋值,只能根据属性weight和height计算结果然后被调用访问
2.2 一种比较旧的方法
示例:
class Student:
def __init__(self,name, age):
self.__name = name
self.__age = age
def get_age(self):
return self.__age
def set_age(self, x):
if not isinstance(x,int):
print('年龄必须是整数数字!')
return
self.__age = x
def del_age(self):
return 'age不能被删除!'
age = property(get_age, set_age, del_age)
stu_obj1 = Student('jason', 18)
print(stu_obj1.age) # 18 (自动触发get_age功能)
stu_obj1.set_age("19") # 年龄必须是整数数字!
stu_obj1.set_age(19)
print(stu_obj1.age) # 19
del stu_obj1.age # age不能被删除!
示例3:
class Student:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def name(self):
print('访问控制')
return self.__name
@name.setter
def name(self, x):
print('赋值控制')
self.__name = x
@name.deleter
def name(self):
print('删除控制')
del self.__name
stu_obj1 = Student('jason', 18)
res = stu_obj1.name # 访问控制
print(res) # jason
del stu_obj1.name # 删除控制
print(stu_obj1.__dict__) # {'_Student__age': 18}
使用property的好处:
将一个类中的函数定义成特性以后,对象再去使用stu_obj1.name的时候就会发现不了:调用的其实是一个函数,得到的是函数计算后返回的结果
三、绑定方法与非绑定方法
针对类中定义的函数
3.1 绑定方法
谁来调用就会将谁作为第一个参数传入
(1)绑定给对象的方法:类中定义的函数默认就是绑定给对象的方法,应该是由对象调用,调用时会将对象作为第一个参数传入
(2)绑定给类的方法:在类的函数上加一个装饰器@classmethod,
该函数就绑定给类了,应该由类来调用,调用时会将类作为第一个参数传入
3.2 非绑定方法
既不与类绑定,也不与对象绑定,就是作为一个普通的函数使用,没有自动传参的效果,谁都可以来调用
class People:
def __init__(self, name, age):
self.__name = name
self.__age = age
def tell_info(self): # 绑定给对象使用的方法
print(f"姓名:{self.__name}, 年龄:{self.__age}")
@classmethod # 绑定给类使用的方法
def func1(cls):
print(cls)
@staticmethod # 非绑定的方法
def func2(x, y):
print(x, y)