首页 > 编程语言 >进入python的世界_day28_python基础—— 面向对象三大特性之封装、多态、反射

进入python的世界_day28_python基础—— 面向对象三大特性之封装、多态、反射

时间:2022-11-07 20:12:04浏览次数:46  
标签:__ .__ obj name python self 多态 print day28

一、要学会看源码了(略微)

1.举例

​ 比如说以前学的json,虽然知道是可以把字典转为json格式的数据,但是当时的字典K、V都是可以被转的类型,如果V 不是json支持转的格式,转换时候就会报错,怎么查看json支持哪些数据转换呢?

d = {
    'a': datetime.date.today(),
    'b': datetime.datetime.today(),
    'c': '你好'
}
# 发现没法json.dumps(d)转换
json.JSONEncoder
按住Ctrl 鼠标左键点JSONEncoder进去

可以看到

 Supports the following objects and types by default:

    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+

​ 这个表就是强调,所有要被转换的数据类型,从头到尾都得是表内的数据类型

​ 如果发现刚好手里的数据类型不在列表中,但又想转换为json格式的数据,怎么做?

  • 第一种——直接暴力字符串转换,万物皆可转字符串

    str()包一下

  • 第二种——派生方法

    # 我们继续看JSONEncoder 里面的源码,长的不看,缩起来先,看到眼熟的停下(前面报错就是报错这个内容)
    def default(self, o):
        """
        ...
        """
        raise TypeError(f'Object of type {o.__class__.__name__} '
                        f'is not JSON serializable')
        # 主动报错语法 所以说如果我们在.dump/s()转换时,如果转不了。由default 该方法执行报错
    

那么解决办法就出来了,写一个类,继承JSONEncoder,并重写default方法

class MyJsonEncoder(json.JSONEncoder):
    def default(self, o):
        print(o)

res = json.dumps(d, cls=MyJsonEncoder)
>>>
# 2022-11-07
# 2022-11-07 15:35:38.896436
# 发现c不会被打印
# o就是没法转的数据
————————————————————————————————————————————
class MyJsonEncoder(json.JSONEncoder):
    def default(self, o):
        print(o)
# 在def default(self, o):这句代码底下打""""""会自动出现几行代码,意思让你解释一下o 还有返回值的含义
        """
        
        :param o:
        :return:
        """
____________________________________________
# 接下来可以对o做处理
class MyJsonEncoder(json.JSONEncoder):
    def default(self, o):
        """
        :param o:
        :return:
        """
        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) # 最后又调原来的方法发,


res = json.dumps(d, cls=MyJsonEncoder)
print(res)

>>>
{"a": "2022-11-07", "b": "2022-11-07 15:50:36", "c": "\u4f60\u597d"}

二、面向对象三大特征核心——封装

1.介绍

​ 封装即整合,将数据和功能整合起来

2.隐藏

​ 将封装的属性进行隐藏操作

​ 类在定义阶段,在属性名前加__前缀,就会实现一个对外隐藏属性效果

​ 如果要找这个被藏起来的,用_类名+隐藏的方法名,就可以找到

可以自己试试__dict__,查看所有名称空间,可以看到_类名+隐藏名

​ 对象也是可以有一些隐藏的属性的

​ 如果不是在定义阶段,是后面类新增或者产生的对象新增__啥啥啥,不行,藏不了

class A:
    age = 18
    _ = '猜猜能不能访问到?'
    _hobby = '起飞'
    __city = '你找不到我'

print(A.age)
print(A._)
print(A.__city)

>>>
# 18
# 猜猜能不能访问到?
# AttributeError: type object 'A' has no attribute '__city'
——————————————————————————————————————————————————
print(A._A__city)		>>> # 你找不到我

A.__name = 'jack'   
print(A.__name)         >>> # 可以找到
obj = A()
obj.__id = 999
print(obj.__id)          >>> # 也可以拿到

3.为何要隐藏

​ 隐藏数据属性"将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制

class People:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_info(self):
        # 通过该接口就可以间接地访问到名字属性
        print(f"""
            姓名:{self.__name}
            年龄:{self.__age}
        """)


obj = People('jack', 18)
obj.get_info()
>>>
      #      姓名:jack
      #      年龄:18
————————————————————————————————————————————————
# 但是发现欸类生成的对象改不了数据,这时候我们在类里再开一个接口
     def set_name(self, new_name):
         self.__name = new_name
obj.set_name('john')
obj.get_info()

>>>
      #      姓名:john
      #      年龄:18	
——————————————————————————————————————————————————
# 如果要限制改名字的一些情况,可以在set_name里面加点东西(意思做拓展)
     def set_name(self, new_name):
         if type(new_name) is not str:
             print('兄dei~,必须传字符串类型~')
             return
         self.__name = new_name
obj.set_name(666) 
>>>
      # 兄dei~,必须传字符串类型~
  • 总结:隐藏只是一种变形,可以把一些难看的、复杂的功能藏起来,统一暴露一个或多个好看的接口展示给用户

4.伪装

​ property装饰器——是用来绑定给对象的方法伪造成一个数据属性

​ 当贴着的方法只有一个形参时(多个形参搞不了),以后调用该方法, 不用加括号

​ 伪装成了一个数据而不是方法

class People:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def info(self):
        # 已经装饰了,直接调info就可以访问到
        print(f"""
            姓名:{self.__name}
            年龄:{self.__age}
        """)

obj = People('jack', 18)

obj.info

三、面向对象三大特征核心——多态

1.介绍

​ 同一种事物有多种形态

2.多态性

​ 方便使用者,因为父类统一子类的方法,只需要了解父类的方法,子类一定有

# 比如学车(c1),学成了后可以开吉利牌子的车,长城牌子的车,比亚迪牌子的车

​ 多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

3.鸭子类型

​ 只要长得像,看上去也一样功能,那你们都是鸭子

4.abc模块(了解) 统一所有子类的方法

class Animal(metaclass=abc.ABCMeta):  # 统一所有子类的方法
    @abc.abstractmethod # 装饰以后,只要有一个类继承了Animal,必须写一个say方法,不然就报错
    def say(self):
        print('动物基本的发声...', end='')


class People(Animal):
    def say(self):
        super().say()
        print('啊对对对')


class Dog(Animal):
    def say(self):
        super().say()
        print('汪汪汪')


class Pig(Animal):
    def say(self):
        super().say()
        print('哼哼哼')


obj1 = People()
obj2 = Dog()
obj3 = Pig()

obj1.say()  # 动物基本的发声...啊对对对
obj2.say()  # 动物基本的发声...汪汪汪
obj3.say()  # 动物基本的发声...哼哼哼

面向对象之反射——挺高端

​ 有了反射,面向对象才能与用户交互起来,注意,一旦和用户交互,用户传过来的都是字符串

​ 反射就是利用字符串操作对象的数据和方法,有四个反射的方法

1.hasattr()

​ 判断对象是否有某一个字符串所对应的属性名或方法名

class A:
    name = 'jack'

obj = A()


print(hasattr(obj, 'name'))     # True
print(hasattr(obj, 'x'))        # False

2.getattr()

​ 根据字符串获取对象对应的属性名(值)或方法名(函数体代码) 如果没有会报错的,所以建议先用hasattr判断后再用getattr

class A:
    name = 'jack'

obj = A()


print(getattr(obj, 'name'))     # jack

上面两和起来用实际使用价值:

​ 能交互了!能交互了!

class A:
    name = 'jack'

    def func(self):
        print('一个方法')


obj = A()

while True:
    user_name = input('请输入您要操作的名字>>>:').strip()
    if hasattr(obj, user_name):  # 利用反射做判断
        print('恭喜您找到')
        f = getattr(obj, user_name)
        if callable(f):
            print('您本次使用的是系统中的某个方法')
            f()
        else:
            print('您本次使用的是系统中的某个数据')
            print(f)
    else:
        print('找不到啦')

3.setattr()

​ 就是给对象添加一些东西

​ 这个添加的东西,可以根据用户自己决定,活灵活现起来了

class A:
    name = 'jack'

    def func(self):
        print('一个方法')


obj = A()
print(obj.__dict__)
setattr(obj, 'age', 20)
print(obj.__dict__)
>>>
# {}
# {'age': 20}

4.delattr()

​ 删除数据,用的很少,对象不能去删除不是自己的哈

class A:
    name = 'jack'

    def func(self):
        print('一个方法')

print(A.__dict__)
obj = A()
delattr(A, 'name')
print(A.__dict__)
>>>
# {'__module__': '__main__', 'name': 'jack', 'func': <function A.func at 0x00000234128C75E0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}


# {'__module__': '__main__', 'func': <function A.func at 0x00000234128C75E0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

面试题

class A:
    def __func1(self):
        print('B.foo')

    def wa(self):
        self.__func1()


class C(A):
    def __func1(self):
        print('C.func1')

c = C()
c.wa()
#解题思路:
首先我们看class A,类定义阶段,隐藏函数就已经定下
self. __func1()  = self._A__func1()

而class C中的 __func1() = _C__func1()


当我们在找wa时在class A中 找到了self.__func1(),此时我们在父类是找不到子类的隐藏方法的,于是就在自身找,就找到了self._A__func1()
>>>
# B.foo

标签:__,.__,obj,name,python,self,多态,print,day28
From: https://www.cnblogs.com/wznn125ml/p/16867264.html

相关文章

  • 面向对象之封装,多态,反射
    面向对象之封装,多态,反射派生实际应用importdatetimeimportjsonclassMyJsonEncoder(json.JSONEncoder):defdefault(self,o):#形参o就是......
  • 面向对象之封装和多态
    派生方法实战演练面向对象三大特性之封装面向对象三大特性之多态面向对象之反射反射的实战案例派生方法实战演练importjsonimportdatetimed={'t1':datetim......
  • 派生方法实例、面向对象三大特性之封装、多态和反射
    目录一.派生方法实战演练二.面向对象三大特性之封装封装伪装三.三大特性之多态四.面向对象之反射利用字符串操作对象的数据和方法反射实战案例一.派生方法实战演练import......
  • 面向对象:派生,三大特性封装,多态,反射
    派生实操importjsonimportdatetimed={'t1':datetime.date.today(),'t2':datetime.datetime.today(),'t3':'jason'}res=json.dumps(d)prin......
  • 面向对象之多态/反射
    派生方法的更多应用importjsonimportdatetimea={'t1':datetime.date.today(),'t2':datetime.datetime.today(),'t3':'moon'}res=json.dumps(a)......
  • 面向对象三大特性之封装、多态
    目录一、派生方法实战演练举例:时间对象序列化报错1转换方式一:手动转类型2转换方式二:派生方法二、面向对象三大特性之封装0.封装简介1.隐藏2.伪装属性(1)装饰器@property:......
  • 面向对象三大特性封装,多态,反射
    派生方法实战演练importjsonimportdatetimed={'ti':datetime.date.today()'t2':datetime.datetime.today()'t3':'jason'}res=json.dumps(d)pr......
  • 面向对象之封装、多态、反射
    面向对象之封装、多态、反射面向对象之封装封装:将数据和功能‘封装’起来隐藏:将数据和功能隐藏起来不让用户直接调用,并开发一些接口间接调用,而且可以在接口内添加一些......
  • 【python】机器学习算法(KNN)入门——手写数字识别
    前言嗨喽~大家好呀,这里是魔王呐!最近邻(kNearestNeighbors,KNN)算法是一种分类算法1968年由Cover和Hart提出,应用场景有宁符识别、文本分类、图像识别等领域。手......
  • Python Ujson
    UJson主要记录其安装方式,能使用pipinstallujson进行安装不过好像有点慢,反正我等了很久,也可以使用Python命令进行安装会快一点,命令如下:python-mpipinstallujson ......