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

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

原文地址:http://www.cnblogs.com/wznn125ml/p/16867264.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性