Python Day 26

  阅读目录

  ##封装

#什么是封装?
对外部隐藏内部的属性,以及实现细节  , 给外部提供使用的接口 

注意:封装有隐藏的意思,但不是单纯的隐藏 

学习封装的目的.就是为了能够限制外界对内部数据的访问 

python中属性的权限分为两种

1.公开的

​    没有任何限制 谁都能访问 

2.私有的 

​    只有当前类本身能够访问 
默认为公共的
 
#为什么需要封装
1.提高安全性  

​    封装属性    

2.隔离复杂度     

​    封装方法

#一个类中分为两种数据,属性和方法

#如何封装
在属性名或者方法名前添加两个下划线__,将其设置为私有的

#思考:封装可以明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,然而定义属性的目的终归是要用,外部要想用类隐藏的属性,需要为其提供接口,
让外部能够间接地使用到隐藏起来的属性,那这么做的意义何在?
   答:可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。


  ##封装属性

class Student:
    def __init__(self,name,age,gender,id_card):
        self.name = name
        self.age = age
        self.gender = gender
        self.__id_card = id_card


    # 访问器
    def get_id_card(self,pwd):
        # 可以在这里添加额外的任何逻辑代码 来限制外部的访问
        # 在类的内部 可以访问
        if pwd =="123":
            return self.__id_card
        raise Exception("密码错误!")


    # 修改被封装的属性   称之为设置器
    def set_id_crad(self,new_id):
        # 身份证必须是字符串类型
        # 长度必须是18位
        if isinstance(new_id,str) and len(new_id) == 18:
            self.__id_card = new_id
        else:
            raise Exception("身份证号码 必须是字符串 且长度必须为18!")

# stu1 = Student("rose",20,"man","111111111111111111")
#
# print(stu1.name)
# print(stu1.id_card)
# stu1.id_card = "123"
# print(stu1.id_card)

stu1 = Student("rose",20,"man","111111111111111111")
# print(stu1.id_card)
# print(stu1.__id_card)
# stu1.show_id_card()
# stu1.set_id_crad("222222222222222222")

# stu1.show_id_card()

# id = stu1.get_id_card()
# print(id)

# stu1.set_id_crad(123)
stu1.set_id_crad("555555555555555555")
# print(stu1.get_id_card())

print(stu1.get_id_card("1232"))

  ##封装方法

什么样的方法应该被封装起来 ?

​    答:一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 ,如下例中的 user_auth等...

#示例1
class ATM:

    def withdraw(self):
        self.__user_auth()
        self.__input_money()
        self.__save_record()
        # 输入账号和密码
        # 显示余额
        # 输入取款金额
        # 保存记录

    def __user_auth(self):
        print("请输入账号密码....")

    def __input_money(self):
        print("余额为100000000,请输入取款金额!")

    def  __save_record(self):
        print("记录流水....")
atm = ATM()
# atm.user_auth()
# atm.input_money()
# atm.save_record()

# atm.withdraw()

# atm.save_record()

  ##封装原理

python是通过 变形的方式来实现的封装
如何变形 在名称带有双下划线开头的变量名字前添加_类名  如_Person__id_card
当然通过变形后的名字可以直接访问被隐藏的属性  但通过不应该这么做
变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形  就是普通属性 

#示例1
class Person:
    def __init__(self,name,age,id_card):
        self.name = name
        self.age = age
        self.__id_card = id_card

    def get_id_card(self):
        return self.__id_card

p = Person("rose",20,"321123123123123123")
print(p.name)


# p.__id_card = "321"
# print(p.__dict__)

# print(p._Person__id_card)
p.__gender = "man"

print(p.__dict__)

  ##property装饰器

作用: 将一个方法伪装成普通属性 

为什么用 property    希望将访问私有属性和普通属性的方式变得一致

与property相关的 两个装饰器 

setter 

​    用点语法 给属性赋值时触发   

deleter 

​    用点语法删除属性时触发 

#示例
class Teacher:
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.__salary = salary

    @property  # getter   # 用于访问私有属性的值   也可以访问普通属性
    def salary(self):
        return self.__salary

    @salary.setter   # 用来设置私有属性的值  也可以设置普通属性
    def salary(self,new_salary):
        self.__salary = new_salary

    @salary.deleter # 用来设置私有属性的值  也可以删除普通属性
    def salary(self):
        # print("can not delete salary!")
        del self.__dict__["_Teacher__salary"]
        # del self.__salary

    #通常property 用于操作私有的属性
t = Teacher("egon",38,100000)
#
# print(t.get_salary())
#
# t.set_salary(5000)
#
# print(t.get_salary())
# print(t.name)

# 被封装的属性在访问时  需要调用方法  而普通属性直接点就ok 这样一来对于对象的使用者而言
# 必须知道要访问的属性 是私有的还是公开 然后调用对于的方法    用起来麻烦
# 此时  我们的目标是 让访问私有属性 和访问普通属性的方式一直
# property 装饰器  就是用来将一个方法伪装成属性


# print(t.salary)
# t.salary = 500
# print(t.salary)

# 删除对象属性
# del t.name
#
# print(t.name)


# del t.salary


# a = {"name":123}
# # a.pop("name")
#
# del a["name"]
#
# print(a)

del t.salary
#
# t.del_salary()


# t.salary = 1
#
#
# # print(t.salary)
#
# del t.salary


# t.get_salary()
# t.set_salary(800)
# t.delete_salary()

# t.salary
# t.salary = 800
# del t.salary

  ##property的另一种使用场景:计算属性

什么是计算属性   一个属性 它的值不是固定死的 而是通过计算动态产生的。
例如:BMI指数

#示例1
class Person:
    def __init__(self,name,height,weight):
        self.name = name
        self.height = height
        self.weight = weight
        # self.BMI = weight / (height ** 2)
    @property
    def BMI(self):
        return self.weight / (self.height ** 2)

    @BMI.setter
    def BMI(self,new_BMI):
        print("BMI 不支持自定义.....")

p = Person("egon",1.7,80)
# print(p.BMI)
#
#
# p.weight = 60
# print(p.BMI)


# print(p.get_BMI())
# p.weight = 60
#
# print(p.get_BMI())
#
# print(p.name)
# print(p.get_BMI())

#
# print(p.BMI)
# p.weight = 60
# print(p.BMI)
# p.BMI = 10

  ##封装能不能被继承问题

# 被封装的内容(私有的)  不可以被继承
# class A:
#     __name =  "rose"  # _A__name
#
#     def __say_hi(self):
#         print("A say: hi")
# class B(A):
#     def test(self):
#         # print(super().__name)  #_B__name
#         print(A._A__name)
#     # pass
# b = B()
# b.test()

  ##多态

多态不是一个具体的技术  或代码

指的是 多个不同类型对象 可以响应同一个方法 ,产生不同结果

例如 水:   气态  固态  液态
     动物: 人  猫  猪
     汽车人:  汽车 飞机  人型

OOP中 标准解释: 多个不同类型对象 可以响应同一个方法  并且产生不同结果

多态的带来的好处:
    只需要学习基类中的使用方法即可, 不需要关心具体的哪一个类 以及实现的   以不变应万变   提高了灵活性
    提高扩展性 
    
    如果没有多态  需要分别学习 person  cat pig 的不同使用方法 这对于使用者而言太麻烦了

如何实现多态:
    鸭子类型 就是典型的多态 多种不同类型 使用方法一样 

#示例1
class Person():

    def bark(self):
        print("Hello!")

    def run(self):
        print("两条腿跑!")

    def sleep(self):
        print("躺着睡!")


class Cat():

    def bark(self):
        print("喵喵喵")

    def run(self):
        print("四条腿跑!")

    def sleep(self):
        print("趴着睡!")

class Pig():
    def bark(self):
        print("哼哼哼!")

    def run(self):
        print("四条腿跑!")

    def sleep(self):
        print("侧躺着睡!")


# person1 = Person()
# cat1 = Cat()
# pig1 = Pig()

# person1.sleep()
# cat1.sleep()
# pig1.sleep()

# 如果没有多态  需要分别学习 person  cat pig 的不同使用方法 这对于使用者而言太麻烦了

  ##重用的内置函数

#__str__
类中的__str__
    该方法在object中有定义 默认行为 返回对象类型以及地址  <__main__.Person object at 0x0000016F450C7390>
    在将对象转为字符串时执行
    注意:返回值必须为字符串类型
    子类可以覆盖该方法来完成 对打印内容的自定义

#示例1
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # 将对象转换为字符串时执行
    def __str__(self):
        print("str run")
        return "my name is %s , age is %s" % (self.name,self.age)


p = Person("rose",20)
# print(p) #在打印前都会现将要打印的内容转为字符串  通过调用__str__函数

str(p)

#__del__
"""
__del__
当对象被删除前会自动调用 该方法
声明时候会删除对象?
    1.程序运行结束 解释器退出 将自动删除所有数据
    2.手动调用del 时也会删除对象

注意:该函数不是用来删除对象的

使用场景
当你的对象在创建时,开启了不属于解释器的资源 例如打开了一个文件
必须保证当对象被删除时 同时关闭额外的资源  如文件


也称之为析构函数  构造 的反义词
    构造 指的是从无到有
    析构 值从有到无
    简单的说就对象所有数据全部删除


总结:__del__该函数 用于 在对象删除前做一些清理操作
"""

#示例1
# 假设要求每一个person对象都要绑定一个文件
class Person:
    def __init__(self,name,path,mode="rt",encoding="utf-8"):
        self.name = name
        self.file = open(path,mode,encoding=encoding)



    # 读取数据的方法
    def read_data(self):
        return self.file.read()


    def __del__(self):
        print("del run!")
        self.file.close()


# p = Person("jack")

# a = 10

# f = open("test.txt")
# print(f.read())
# f.close()

p2 = Person("rose","本周内容")
print(p2.read_data())

  ##反射

#英文中叫反省 (自省)   

面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;   

一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性 

反射就是通过字符串来操作对象属性

涉及到的方法:
1、hasattr 判断是否存在某个属性

2、getattr    获取某个属性的值

3、setattr    新增或修改某个属性 

4、delattr 删除某个属性 

#示例1
import os
class  Student:

    def __init__(self,name):
        self.name = name


stu = Student("rose")
# stu.age = 18
#
# print(stu.name)
# print(hasattr(stu,"name"))
print(getattr(stu,"name"))
#
# setattr(stu,"name","jack")
# print(getattr(stu,"name"))
#
# delattr(stu,"name")
# print(stu.name)


#示例2

class MY_CMD:

    def dir(self):
        os.system("dir")

    def ipconfig(self):
        os.system("ipconfig")

cmd = MY_CMD()

while True:
    name = input("请输入要执行的功能:")
    if hasattr(cmd,name):
        method = getattr(cmd,name)
        print(method)
        method()
    else:
        print("sorry this method is not exists....!")

  ##动态导入模块

直接写import 称之为静态导入  建立在一个基础时 提前已经知道有这个模块

动态导入  指的时  在需要的任何时候 通过指定字符串类型包名称来导入需要的模块
import importlib
mk = importlib.import_module(m_name)
mk 即导入成功的模块

该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类

#示例
import importlib

m_name = input("请输入要导入的模块名称:")  #执行要输入模块名称:build_house。core
mk = importlib.import_module(m_name)
print(mk)


from build_house import conf
print(conf)

注解:print(mk) 和print(conf) 结果一样的

  ##反射在框架中的应用

#core.py文件
import importlib
from 代码.build_house import conf
def building():
    print("毛坯房建造完成.......")
    # 读取用户提供配置信息 来加载用户所需要的一系列装饰品
    for cls_info in conf.decorations:
        # print(cls_info)
        # 切割类名和模块路径
        m_name,cls_name = cls_info.rsplit(".",1)
        # print(m_name,cls_name)
        # 导入模块
        mk = importlib.import_module(m_name)
        # print(mk)
        # 从模块中获取类
        if not hasattr(mk,cls_name):
            continue
        cls = getattr(mk,cls_name)
        obj = cls()
        print(obj)

building()

#conf.py文件
decorations = ["build_house.my_decoration.Table",
               "build_house.my_decoration.Bed",
               "build_house.my_decoration.Light",
               "other_decoration.Sofa"]

#my_decoration.py文件
class Table:
    pass

class Light:
    pass

class Bed:
    pass

猜你喜欢

转载自www.cnblogs.com/liangzhenghong/p/10895381.html