【一】面向对象的三大特性
【二】什么是封装
- 封装是对具体对象的一种抽象
- 意思就是将某部分功能和代码隐藏起来,在程序外边看不到,只能在程序内部使用
【三】为什么要封装?
- 封装数据的主要原因是:保护隐私(把不想别人知道的东西封装起来)
【四】封装的方法
- 自己的身体其实也有封装的部分
- 自己有并且自己能用但是别人看不到也用不了
- 方法:
【五】封装隐藏属性
【1】数据属性
- Python的Class机制采用双下划线开头的方式将属性隐藏起来(设置成私有的)
- 但其实这仅仅只是一种变形操作,类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成
_类名__属性名
的形式:
class Person:
__NAME = "Dream"
def __init__(self):
self.__age = 18
def __run(self):
print('__f1 run')
def walk(self):
self.__run()
print(Person.__N)
obj = Person()
print(obj.__x)
class Person:
__SCHOOL_NAME = '清华'
def __init__(self, name):
self.name = name
student = Person(name='dream')
print(student.name)
print(Person.__dict__)
print(student.__SCHOOL_NAME)
print(student._Person__SCHOOL_NAME)
【2】函数属性
- 在类内部是可以直接访问双下滑线开头的属性的,比如
self.__f1()
,因为在类定义阶段类内部双下滑线开头的属性统一发生了变形。
class Person:
__SCHOOL_NAME = '清华'
def __init__(self, name):
self.name = name
def __change_name(self):
self.name = 'nb_' + self.name
student = Person(name='dream')
print(student.name)
print(Person.__dict__)
print(student.__change_name())
class Person:
__NAME = "Dream"
def __init__(self):
self.__age = 18
def __run(self):
print('__f1 run')
def walk(self):
self.__run()
print(self.__NAME)
【3】变形操作只会发生一次
- 变形操作只在类定义阶段发生一次,在类定义之后的赋值操作,不会变形。
class Person:
__NAME = "Dream"
def __init__(self):
self.__age = 18
def __run(self):
print('__f1 run')
def walk(self):
self.__run()
print(self.__NAME)
Person.__NAME = "Hope"
print(Person.__dict__)
person = Person()
person.__sex = "男"
person.__age = 22
print(person.__dict__)
print(person.__sex)
【六】开放接口
【1】隐藏数据属性
- 将数据隐藏起来就限制了类外部对数据的直接操作,然后类内部应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制
class Teacher:
def __init__(self, name, age):
self.__name = name
self.__age = age
def set_info(self, name, age):
if not name.startswith('lj_'):
raise ValueError("名字必须是 lj 前缀")
if not age.isdigit():
raise ValueError("年龄必须是数字")
if int(age) < 0:
raise ValueError("年龄超出常人,建议回炉重造!")
self.__name = name
self.__age = age
def tell_info(self):
print(f"当前讲师是 :>>>> {self.__name} 年龄是 :>>>> {self.__age}")
teacher = Teacher(name="dream", age=18)
teacher.set_info(name='lj_opp',age='1')
teacher.tell_info()
【2】隐藏函数属性
- 目的的是为了隔离复杂度
- 例如ATM程序的取款功能,该功能有很多其他功能组成,
- 而对使用者来说,只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来
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()
obj = ATM()
obj.withdraw()
【3】总结
- 隐藏属性和开放接口本质上都是为了明确的区分内外,在类内部可以随意修改我的代码,但是在类的外部不允许使用者修改代码
- 类外部只需要拿到一个接口,只要接口名不变,里面的逻辑就可以随意实现
- 接口只要基础不变,代码就可以任意修改
【七】装饰器 property
【1】什么是property
- property 是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
- 将函数的返回值作为数据属性返回
class Student:
def __init__(self, name):
self.name = name
@property
def vip_name(self):
return self.name
student = Student(name='chosen')
print(student.name)
print(student.vip_name)
【2】BMI例子
- MI指数是用来衡量一个人的体重与身高对健康影响的一个指标
- 成人的BMI数值:
- 过轻:低于18.5
- 正常:18.5-23.9
- 过重:24-27
- 肥胖:28-32
- 非常肥胖, 高于32
- 计算公式
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
- 身高或体重是不断变化的
- 所以在每次要查看BMI值都需要通过计算才能得到,但很明显BMI听起来更像是一个特征而不是功能,所以就有了装饰器 property
- 可以将类中的函数“伪装成”对象的数据属性,对象在访问该特殊属性时会触发功能的执行,然后将返回值作为本次访问的结果
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)
obj = People('dream', 62, 1.70)
print(obj.bmi)
【3】为什么要使用property
- 在所有编程语言中都有三种封装方式
- public : 公开
- protected : 对外不公开,对内公开
- private : 对谁都不公开
class Foo:
def __init__(self, val):
self.__NAME = val
@property
def name(self):
return self.__NAME
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError('%s must be str' % value)
self.__NAME = value
@name.deleter
def name(self):
raise PermissionError('Can not delete')
f = Foo('dream')
print(f.name)
f.name = 'Hope'
f.name = 123
del f.name
class Foo:
def __init__(self, val):
self.__NAME = val
def get_name(self):
return self.__NAME
def set_name(self, value):
if not isinstance(value, str):
raise TypeError('%s must be str' % value)
self.__NAME = value
def del_name(self):
raise PermissionError('Can not delete')
name = property(get_name, set_name, del_name)
f = Foo('dream')
print(f.name)
f.name = 'Hope'
f.name = 123
del f.name
【八】员工管理系统(使用类方法)
import hashlib
import json
import os
import random
class Tools(object):
def __init__(self):
self.BASE_DIR = os.path.dirname(__file__)
self.DB_DIR = os.path.join(self.BASE_DIR, 'data')
os.makedirs(self.DB_DIR, exist_ok=True)
self.file_path = os.path.join(self.DB_DIR, 'emp_data.json')
def check_data_type(self):
...
def get_username_password(self):
username = input("请输入用户名 :>>>> ").strip()
password = input("请输入 密码 :>>>> ").strip()
return username, password
@property
def salt(self):
code = ''
for i in range(5):
num = random.randint(0, 9)
alf = chr(random.randint(65, 90))
add = random.choice([num, alf])
code = "".join([code, str(add)])
return code
def encrypt_password(self, salt=None, password=None):
original_data = str(salt) + str(password)
encrypted_data = original_data.encode()
md5 = hashlib.md5()
md5.update(encrypted_data)
return md5.hexdigest()
def read_data(self):
try:
with open(file=self.file_path, mode='r', encoding='utf-8') as fp:
data = json.load(fp)
return data
except:
return {}
def save_data(self, data):
with open(file=self.file_path, mode='w', encoding='utf-8') as fp:
json.dump(obj=data, fp=fp, ensure_ascii=False)
class Worker(object):
def __init__(self):
self.func_menu = f'''
------------------ 功能菜单 ------------------
1.注册
2.登录
3.添加员工信息
4.删除员工信息
5.查看员工信息
q.退出系统
'''
self.func_dict = {
'1': self.register,
'2': self.login,
'3': self.add_emp,
'4': self.del_emp,
'5': self.check_emp,
}
self.tools = Tools()
self.login_dict = {}
def __exist_user(self, username):
emp_data_dict_all = self.tools.read_data()
emp_data_dict = emp_data_dict_all.get(username)
if not emp_data_dict:
return False
else:
return True
def login(self):
print(f'欢迎来到登录功能!')
username, password = self.tools.get_username_password()
exist_user = self.__exist_user(username)
if not exist_user:
return False, f'当前用户 {username} 不存在!请先注册!'
user_data_dict_all = self.tools.read_data()
user_data_dict = user_data_dict_all.get(username)
salt = user_data_dict.get('salt')
old_password = user_data_dict.get('password')
new_password = self.tools.encrypt_password(salt=salt, password=password)
if old_password != new_password:
return False, f'当前密码错误!'
self.login_dict['username'] = username
return True, f'当前用户 {username} 登录成功!'
def register(self):
print(f"欢迎来到注册功能!")
user_data_dict_all = self.tools.read_data()
username, password = self.tools.get_username_password()
user_exist = self.__exist_user(username=username)
if user_exist:
return False, f'当前用户 {username} 已存在!请登录!'
salt = self.tools.salt
encrypted_password = self.tools.encrypt_password(salt=salt, password=password)
user_data_dict_all[username] = {
'username': username,
'password': encrypted_password,
'salt': salt
}
self.tools.save_data(data=user_data_dict_all)
return True, f'当前用户 {username} 注册成功!'
def login_auth(func):
def inner(*args, **kwargs):
self = args[0]
if not self.login_dict.get('username'):
return False,'请先登录!'
else:
return func(*args, **kwargs)
return inner
@login_auth
def add_emp(self):
...
def del_emp(self):
print(self)
...
def check_emp(self):
...
def main(self):
while True:
print(self.func_menu)
func_id = input("请输入功能ID :>>>> ").strip()
if not func_id.isdigit():
print(f"当前ID格式不正确!")
continue
if func_id not in self.func_dict:
print(f"当前ID不存在!")
continue
func = self.func_dict[func_id]
flag, msg = func()
if not flag:
print(msg)
continue
else:
print(msg)
if __name__ == '__main__':
s = Worker()
s.main()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!