面向对象三大特性之封装

Posted yafeng666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象三大特性之封装相关的知识,希望对你有一定的参考价值。

面向对象三大特性之封装

一、继承json模块,并派生出新的功能

  • 继承json模块中的JSONEncoder,并派生出新的功能
import json
from datetime import date, datetime

#在原来json模块中可序列化的数据型优先
# print(type(datetime.now()))
#<class 'datetime.datetime'>

#json不可以变化集合,类

# dict1 = {
#     # 'time1': str(datetime.now())
#     'time1': datetime.now()
# }
# res = json.dumps(dict1)
# print(res)  #Object of type datetime is not JSON serializable

#现在想要自定义一个可以被json化的类

class MyJson(json.JSONEncoder):
    #datetime.now() ---->o
    def default(self, o):
        #isinstance:判断一个对象是否是一个类的实例
        if isinstance(o, datetime): #True
            return datetime.strftime(o, '&Y-%m-%d %X')

        else:
            return super().default(self, o)

dict1 = {
    'time1': datetime.now(),
    'name': 'yafeng'
}

#指定自定义的一个MyJson 派生类
#cls= 自定义的类
res = json.dumps(dict1, cls=MyJson)
print(res)
#{"time1": "&Y-11-27 14:32:22", "name": "yafeng"}

二、组合

  • 夺命三问
'''
夺命三问:
    1、什么是组合?
        组合指的是一个对象中,包含另一个或多个对象
    2、为什么要用组合?
        减少代码的冗余
    3、如何使用组合?

耦合度:
    藕:莲藕---> 藕断丝连
    - 耦合度越高:程序的可扩展性越低
    - 耦合度越低:程序的可扩展性越高

总结:
    - 继承:
        继承是类与类之间的关系,子类继承父类的属性与方法,子类与父类是一种'从属'关系
    - 组合:
        组合是对象与对象的关系,一个对象拥有另一个中的属性/方法,是一种什么有什么的关系

'''
  • 用组合去实现的实例
# #继承
# #父类
# class People:
#     def __init__(self, name, age, sex, year, month, day):
#         self.name = name
#         self.age = age
#         self.sex = sex
#         self.year = year
#         self.month = month
#         self.day = day
#
#     def tell_birth(self):
#         print(f'''
#         =====出生年月日=====
#             年:{self.year}
#             月:{self.month}
#             日:{self.day}
#
#         ''')
#
#
# #老师类
# class Teacher(People):
#     def __init__(self, name, age, sex, year, month, day):
#         super().__init__(name, age, sex, year, month, day)
#
# #学生类
# class Student(People):
#     def __init__(self, name, age, sex, year, month, day):
#         super().__init__(name, age, sex, year, month, day)
#
#
# tea1 = Teacher('tank', 18, 'male', 2001, 1, 11)
# stu1 = Student('yafeng', 16, 'male', 2003, 12, 11)
#
# print(tea1.name, tea1.age, tea1.sex, tea1.year, tea1.month, tea1.day)
# tea1.tell_birth()
#
# '''
# tank 18 male 2001 1 11
#
#         =====出生年月日=====
#             年:2001
#             月:1
#             日:11
# '''
# print(stu1.name, stu1.age, stu1.sex, stu1.year, stu1.month, stu1.day)
# stu1.tell_birth()
# '''
# yafeng 16 male 2003 12 11
#
#         =====出生年月日=====
#             年:2003
#             月:12
#             日:11
#
# '''


#用组合去实现
class People:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

#老师类
class Teacher(People):
    def __init__(self, name, age, sex):
        super().__init__(name, age, sex)

#学生类
class Student(People):
    def __init__(self, name, age, sex):
        super().__init__(name, age, sex)

#日期类
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def tell_birth(self):
        print(f'''
        =====出生年月日=====
            年:{self.year}
            月:{self.month}
            日:{self.day}
        ''')

tea1 = Teacher('tank', 25, 'female')
date_obj = Date('1994', 1, 11)
#老师对象中包含一个自定义的日期对象
tea1.date_obj = date_obj
tea1.date_obj.tell_birth()
'''
        =====出生年月日=====
            年:1994
            月:1
            日:11
        
'''

stu1 = Student('yafeng', 18, 'male')
date_obj = Date('1196', 1, 30)

stu1.date_obj = date_obj
stu1.date_obj.tell_birth()
'''
        =====出生年月日=====
            年:1196
            月:1
            日:30
        
'''
  • 组合练习
'''
练习需求:
    选课系统:
        1、有学生类,老师类,学生与老师有属性'名字,年龄,性别,课程'
        2、有方法,老师与学生可以添加课程,打印学习/教授的课程
        #用组合实现
'''


# 父类
class People:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    # 打印出生日期
    def tell_birth(self):
        # pass
        print(f'''
        年:{self.date_obj.year}#在后面stu1.date_obj= date_obj
        月:{self.date_obj.month}
        日:{self.date_obj.day}
        ''')

    # 添加课程
    def add_course(self, course_obj):
        self.course_list.append(course_obj)

        # pass

    # 打印当前课表内的所有课程信息
    def tell_all_course(self):
        # 从当前对象课程列表中取出所有的课程对象
        for couser_obj in self.course_list:
            couser_obj.tell_course_info()

class Student(People):
    def __init__(self, name, age, sex):
        super().__init__(name, age, sex)
        # 学生自己的课程列表
        self.course_list = []


class Teacher(People):
    def __init__(self, name, age, sex):
        super().__init__(name, age, sex)
        # 老师自己的教授的课程列表
        self.course_list = []


class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day


# 定义一个课程类:课程有:课程名称,课程价格,课程周期
class Course:
    def __init__(self, course_name, course_price, course_time):
        self.course_name = course_name
        self.course_price = course_price
        self.course_time = course_time

        # 定义打印课程方法: 只打印一个课程信息

    def tell_course_info(self):
        print(f'''
        =====课程信息如下=====
            课程名称:{self.course_name}
            课程价格:{self.course_price}
            课程时间:{self.course_time}
        ''')


# 创建学生对象
stu1 = Student('yafeng', 18, 'male')
date_obj = Date(2001, 1, 30)
stu1.date_obj = date_obj

# 创建课程对象
python_obj = Course('python', 66666, 6)
go_obj = Course('go', 29998, 5)

# 给当前学生对象添加课程对象
# 添加python课程
stu1.add_course(python_obj)

# 添加go课程
stu1.add_course(go_obj)

# 当前学生打印所有课程的信息
stu1.tell_all_course()

三、封装

  • 封装介绍
'''
夺命三问
    1、什么是封装?
        封:比如一个袋子,封起来
        装:比如将一堆小猫,小狗装在袋子里
        #对象---->相当于一个袋子
        封装指的是可将一堆属性和方法。封装到对象中

        ps: 对象就好比一个‘袋子/容器’, 可以存放一堆属性和方法
        ps: 存不是目的,目的是为了取,可以通过‘对象.’的方式获取属性或方法

    2、为什么要封装?
        可以通过‘对象.’的方式‘存放/获取’属性或方法
        对象拥有‘.’的机制
        方便数据的存取

    3、如何封装?
        class user:
            x = 10
            def func():
                pass

            obj = user()
            obj.y = 20
            obj ---->x,func,y

'''

四、访问限制机制

  • 访问限制机制
'''
夺命三问:
    1、什么是访问限制机制?
        凡是在类内部定义的属性或方法,
        以__开头的属性或方法名,都会被限制,外部不能'直接访问'该属性的原型
        ps: 看起来像是将该属性或方法隐藏起来了

        #python特有的
        注意:凡是在类内部定义__开头的属性或方法,都会变形为_类名__属性/方法。

    2、为什么要有访问限制?
        比如:将一些隐私的数据,隐藏起来,不让外部轻易获取

        -接口:
            可以将数据封装成一个接口,可以让用户调用接口,
            并且通过相应的逻辑,最后再将数据返回给用户

    3、如何实现?


'''


# # demo1
# class User:
#
#     #__开头的属性
#     __name = 'yafeng'   #__name变形为--->  _类名__name
#
#     #__开头的方法
#     def __run(self):
#         print('yafeng is running')
#
#
# # print(User.__name)  #AttributeError: type object 'User' has no attribute '__name'
# #不能直接访问
#
# obj = User()
# print(obj._User__name)  #yafeng


# #demo2
# class User:
#     #__开头的属性
#     __name = 'yafeng'
#     __age = 18
#     __sex = 'male'
#     __ID = '12345678966'
#     __bal = 12345678910
#
#     def __init__(self, name, age, sex):
#         self.__naem = name
#         self.__age = age
#         self.__sex = sex
#
#
#     #校验接口,获取用户信息
#     def parse_user(self, username, password):
#         if username == 'yafeng_handsome' and password == '666':
#             print(f'''
#             通过验证,获取用户信息
#             用户名:{self.__naem}
#             用户年龄:{self.__age}
#             用户性别:{self.__sex}
#             用户ID:{self.__ID}
#             用户资产:{self.__bal}
#             ''')
#         else:
#             print('校验失败,无法查询用户信息!')
#
#     #__开头的方法
#     def __run(self):
#         print('yafeng is running...')
#
# obj = User('yafeng', 18, 'male')
# obj.parse_user('yafeng_handsome', '666')
# '''
#             通过验证,获取用户信息
#             用户名:yafeng
#             用户年龄:18
#             用户性别:male
#             用户ID:12345678966
#             用户资产:12345678910
# '''
#

#demo3
class ATM:
    #取钱功能
    #1、插入银行卡
    def __insert_card(self):
        print('开始插卡...')
        pass

    #2、输入密码
    def __input_pwd(self):
        print('输入密码...')
        pass

    #3、输入取款金额
    def __input_bal(self):
        print('输入取款金额...')
        pass

    #4、出钱
    def __output_money(self):
        print('开始吐钱...')
        pass

    #5、打印流水账单
    def __print_flow(self):
        print('打印流水账单...')
        pass

    #取款顺序接口
    def withdraw(self):
        #1、插入银行卡
        self.__insert_card()

        #2、输入密码
        self.__input_pwd()

        #3、输入取款金额
        self.__input_bal()

        #4、出钱
        self.__output_money()

        #5、打印流水账单
        self.__print_flow()

atm_obj = ATM()
atm_obj.withdraw()

五、propetry

  • property的应用
'''
夺命三问:
    1、什么是property?
        是一个python内置的装饰器,可以装饰在'类内部的方法'上。
        可以将该方法调用方式有由---->对象.方法()----> 对象.方法

    2、为什么用property?
        ps:在某些场景下,调用的方法只是用来获取计算后的某个值
        ps:必须通过 对象.方法() 方式调用,让该方法看起来像动词

        让名词的方法,调用时更为合理
        目的是为了,迷惑调用者,调用的方法误以为是 属性

    3、如何用?
'''


#需求:计算人体BMI指数
#公式:BMI=体重/身高的平方
#value = weight/(height*height)
class User:
    def __init__(self, name, height, weight):
        self.__name = name
        self.weight = weight
        self.height = height

    #获取BMI指数的方法
    @property
    def BMI(self):

        return self.weight/(self.height**2)

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

    @name.deleter
    def name(self):  #删除属性
        del self.__name






user_obj = User('yafaneg', 1.77, 64)

# user_obj.BMI()
# print(user_obj.BMI())
#20.428357113217785


#@property以后
print(user_obj.BMI)
#20.428357113217785
#注意此时不能在BMI后面加(),否则会报错

# print(user_obj.BMI())
#TypeError: 'float' object is not callable

# print(user_obj.name)  #yafaneg
#
#
# #修改属性
# user_obj.name = '亚峰'
# print(user_obj.name)  #亚峰


#删除属性
del user_obj.name
print(user_obj.name)  #AttributeError: 'User' object has no attribute '_User__name'

以上是关于面向对象三大特性之封装的主要内容,如果未能解决你的问题,请参考以下文章

19.Python面向对象之:三大特性:继承,封装,多态。

面向对象之:三大特性:继承(已讲),封装,多态

面向对象之三大特性

Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)

面向对象三大特性之封装

面向对象三大特性之封装