一、要学会看源码了(略微)
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