面向对象之封装,多态,反射

面向对象之封装,多态,反射

派生实际应用

  import datetime
  import json

  class MyJsonEncoder(json.JSONEncoder):
      def default(self, o):
          # 形参o就是即将要被序列化的数据对象
          # print('重写了', o)
          '''将o处理成json能够序列化的类型即可'''
          if isinstance(o,datetime.datetime):
              return o.strftime('%Y-%m-%d %X')
          elif isinstance(o, datetime.date):
              return o.strftime('%Y-%m-%d')
          return super().default(o)  # 调用父类的default(让父类的default方法继续执行 防止有其他额外操作)

  d1 = {'t1': datetime.datetime.today(), 't2': datetime.date.today()}
  res = json.dumps(d1, cls=MyJsonEncoder)
  print(res)
  """
  TypeError: Object of type 'datetime' is not JSON serializable
  json不能序列化python所有的数据类型 只能是一些基本数据类型
      json.JSONEncoder

  1.手动将不能序列化的类型先转字符串
      {'t1': str(datetime.datetime.today()), 't2': str(datetime.date.today())}
  2.研究json源码并重写序列化方法
      研究源码发现报错的方法叫default
          raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)
      我们可以写一个类继承JSONEncoder然后重写default方法
"""
能够被序列化的数据是有限的>>>:必须是下列左边的类型
+-------------------+---------------+
| Python            | JSON          |
+===================+===============+
| dict              | object        |
+-------------------+---------------+
| list, tuple       | array         |
+-------------------+---------------+
| str               | string        |
+-------------------+---------------+
| int, float        | number        |
+-------------------+---------------+
| True              | true          |
+-------------------+---------------+
| False             | false         |
+-------------------+---------------+
| None              | null          |
+-------------------+---------------+

面向对象三大特性之封装

封装的含义:
就是将数据与功能隐藏起来,不能直接调用,必须使用单独开发的接口来调用这些隐藏起来的数据并利用该接口添加额外的操作。分为 封装与隐藏

1.封装: 就是将数据和功能封装起来。

2.隐藏: 将数据与功能隐藏起来,只能通过接口调用并增加额外的操作

class Student(object):
    school_name = '考上大学啦'
    __school = '家里蹲大学'

# 类在定义阶段变量名前有两个下划线,就是隐藏该名字
    def __choice_course(self):
        print('丢人不,隐藏了')


# 功能也可以使用两个下划线来隐藏
'怎么访问呢'
print(Student.__dict__)  # 可以看到我们访问其名称空间此名字并未消失
# print(Student.__school)  # 直接报错 无法使用
# print(Student.__choice_course)  # 也报错 无法使用
  我们可以直接通过'_Student__school' 与 '_Student__choice_course'这两个名字来访问,但是这样是不可取的,隐藏就是为了让你不要直接去访问他,你这样还有啥意思。自觉遵守。
    
   """要注意的是类只有在定义阶段才可以隐藏,如果你在下面使用 类名.隐藏名 修改数据 那么隐藏就无效了"""

对象也可以拥有隐藏属性

class Student(object):
    school_name = '考上大学啦'
    __school = '家里蹲大学'

    def __init__(self, name, age):
        self.__name = name
        self.__age = age
    # 开放修改接口,并增加一些特殊功能,
    '如果年龄也需要修改,只需在形参里加上年龄'
    def set_name(self,new_name):
        if len(new_name)== 0:  # 判断用户输入的名字是否为空
            raise ValueError('你啥都不输什么意思')
        if new_name.isdigit():  # 判断用户输的名字是否是数字
            raise ValueError('让你输个名字你输数字搞毛啊')
        self.__name = new_name

obj = Student('tank',18)
print(obj.__dict__)  # {'_Student__name': 'tank', '_Student__age': 18}
obj.set_name('jason')  # 利用接口修改隐藏名字的数据
print(obj.__dict__)  # {'_Student__name': 'jason', '_Student__age': 18}

"我们在隐藏一些名字的同时,应该开放一个修改这些 名字的数据值 的接口,同时还能加上一些判断或别的"

伪装

 @property  可以将方法伪装成数据
class Person(object):
    def __init__(self, name, height, weight):
        self.name = name
        self.height = height
        self.weight = weight

    @property
    def BMI(self):
        return '%s您的BMI指数是%s' % (self.name, self.weight / (self.height ** 2))

obj = Person('lxj',1.78,75)
obj.BMI()  # 报错 此时方法已经被转成基本数据
print(obj.BMI) # lxj您的BMI指数是23.671253629592222

三大特性之多态

多态:一种事物的多种形态
eg:
    动物:猪狗牛羊猫

    
class Animal(object):
    def speak(self):
        pass

class Chicken(Animal):
    def speak(self):
        print('咯咯咯')

class Duck(Animal):
    def speak(self):
        print('嘎嘎嘎')

class Sheep(Animal):
    def speak(self):
        print('咩咩咩')

"动物,我们只要提起动物那么第一时间就想起了动物们都会叫,那么他们就应该有一个共同的方法 叫"
C1 = Chicken() # 模拟鸡
D1 = Duck()  # 模拟鸭
S1 = Sheep()  # 模拟羊
C1.speak()  # 咯咯咯
D1.speak()  # 嘎嘎嘎
S1.speak()  # 咩咩咩
"""面向对象中多态意思是 一种事物可以有多种形态但是针对相同的功能应该定义相同的方法
这样无论我们拿到的是哪个具体的动物 都可以通过相同的方法调用功能。

我们如何来寻找共同的特征的方法:
在python中称为:鸭子类型:只要你看上去像鸭子 走路像鸭子 说话像鸭子 那么你就是鸭子
"""

多态提供了强制约束子类的方法: 不推荐使用
import abc
# 指定metaclss 属性将设置为抽象类,抽象类本身只能用于约束子类
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod  # 使用 该装饰器 现在子类必须要有 speak方法
    def speak(self):
        pass

class Chicken(Animal):  # 只要继承Animal 必须要有 speak方法
    def speak(self):
        print('咯咯咯')

class Duck(Animal):
    def jiao(self):   # 没有speak方法
        print('嘎嘎嘎')

D1 = Duck()  # 直接报错  TypeError: Can't instantiate abstract class Duck with abstract methods speak

"""
在linux系统中有一句话>>>:一切皆文件!!!
    内存可以存取数据
    硬盘可以存取数据
    那么多有人都是文件
"""
class Memory(object):  # 内存
    def read(self):
        pass
    def write(self):
        pass
class Disk(object):  # 磁盘
    def read(self):
        pass
    def write(self):
        pass
# 得到内存或者硬盘对象之后 只要想读取数据就调用read 想写入数据就调用write 不需要考虑具体的对象是谁

三大特性之反射

利用字符串操作对象的数据和方法
1.hasattr() 
	'判断对象是否含有某个字符串对应的属性名或方法名'
2.getattr() 
	'根据字符串获取对象对应的属性名(属性的值)或方法名(函数名及代码)'
3.setattr()
	根据字符串给对象设置或修改数据
4.delattr()
	根据字符串删除对象里面的名字

在于用户交互的情况下,我们得到用户输入的值都是字符串,无法通过字符串来直接找到该名字。此时就有了反射
class A:
    name = 'tank'

    def get(self):
        pass


obj = A()
target_name = input('请输入你想要对象使用的名字').strip()
hasattr() 
print(hasattr(obj,target_name))  # 用户输入name   得到True  
print(hasattr(obj,target_name))  # 用户输入get     True
print(hasattr(obj,target_name))  # 用户输入age   此时类的名称空间内并没有这个名字False


getattr()
print(getattr(obj,target_name))   # 用户输入name  得到  值 tank
 
    
利用反射编写一个小程序:
class A:
    name = 'tank'

    def get(self):
        print('给你一个大逼兜')

obj = A()
while True:
    target_name = input('请输入你想要用的名字').strip()
    if hasattr(obj,target_name):  # 判断类有没有 用户输入的名字
        print('找到啦')
        # 获取该名字的数据
        target_Valus = getattr(obj,target_name)
        # 判断能不能+括号调用,使用内置方法 callable
        if callable(target_Valus):
            print('你使用的是个方法')
            target_Valus()
        else:
            print('这只是个数据')
            print(target_Valus)
    else:
        print('没有这名字')

反射实际案例

1.什么时候应该考虑使用反射 只要需求中出现了关键字
	对象....字符串....
 
2.实战案例
	1.模拟cmd终端
    	class WinCmd:
        def tasklist(self):
            print("""
            1.学习编程
            2.学习python
            3.学习英语
            """)
        def ipconfig(self):
            print("""
            地址:127.0.0.1
            地址:上海浦东新区
            """)
        def get(self, target_file):
            print('获取指定文件',target_file)
        def put(self, target_file):
            print('上传指定文件',target_file)
        def server_run(self):
            print('欢迎进入简易版本cmd终端')
            while True:
                target_cmd = input('请输入您的指令>>>:')
                res = target_cmd.split(' ')
                if len(res) == 1:
                    if hasattr(self, res[0]):
                        getattr(self, res[0])()
                    else:
                        print(f'{res[0]}不是内部或者外部命令')
                elif len(res) == 2:
                    if hasattr(self, res[0]):
                        getattr(self, res[0])(res[1])
                    else:
                        print(f'{res[0]}不是内部或者外部命令')


        obj = WinCmd()
        obj.server_run()
	2.一切皆对象
    	  # 利用反射保留某个py文件中所有的大写变量名及对应的数据值
        import settings
        print(dir(settings))  # dir列举对象可以使用的名字

        useful_dict = {}
        for name in dir(settings):
            if name.isupper():
                useful_dict[name] = getattr(settings, name)
        print(useful_dict)

        # while True:
        #     target_name = input('请输入某个名字')
        #     if hasattr(settings, target_name):
        #         print(getattr(settings, target_name))
        #     else:
        #         print('该模块文件中没有该名字')
posted @ 2022-11-07 19:31  李阿鸡  阅读(24)  评论(0编辑  收藏  举报
Title