#内容概览
- 派生方法的实战演练
- 面向对象三大特性之封装
- property伪装属性
- 面向对象三大特性之封装
- 面向对象之反射
- 反射实战案例
###派生方法的实战演练
import datetime
import json
d = {
'time1' : datetime.datetime.today(),
'time2' : datetime.date.today()
}
res = json.dumps(d)
print(res)
"""
上述代码会直接报错:
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable因为json序列化python对数据类型有限制
不是所有类型都能序列化
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str | string |
+-------------------+---------------+
| int, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
只有上面的数据类型才能够被序列化
"""
# 解决方案1:直接将不能序列化的数据类型转换成可以被序列化的数据类型
d = {
'time1' : str(datetime.datetime.today()),
'time2' : str(datetime.date.today())
}
res = json.dumps(d)
print(res)
# 解决方案2:使用派生方法
d = {
'time1' : datetime.datetime.today(),
'time2' : datetime.date.today()
}
res = json.dumps(d)
print(res)
"""
查看JSONEncoder源码发现序列化报错是由default方法触发的
如果想要避免报错,那么就需要使用派生方法对default方法做修改
"""
class MyJsonEncode(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime.datetime): # 如果是datetime类型数据,格式化处理
return o.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(o, datetime.date): # 如果是date类型数据,格式化处理
return o.strftime('%Y-%m-%d')
return super().default(o) # 如果是可以序列化的类型,就直接使用原来的方法即可
res = json.dumps(d, cls=MyJsonEncode)
print(res)
json.dumps(d, cls=MyJsonEncode)
###面向对象三大特性之封装
封装其实就是将数据或功能隐藏起来,不能从外界轻易调用
但封装的目的不是让用户无法使用,而是给这些数据设定了一个接口,让用户通过接口才能使用到,我们在接口中添加一些额外的操作
"""
在类定义阶段,使用双下划线开头的名字,就是隐藏的属性,在当前类以外不能直接获取
在python中不会真正的限制任何代码,隐藏的属性只是经过了变形,其实还是可以访问到(__变量名>>>_类名__变量名),只不过这样做隐藏的意义也就没有了
"""
class Person(object):
def __init__(self, name, age):
self.__name = name
self.__age = age
def check_info(self): # 专门定义一个访问查看数据的接口
print(f"""
姓名:{self.__name}
年龄:{self.__age}
""")
def set_info(self, name, age): # 定义一个修改数据的接口
if len(name) == 0:
print('用户名不能为空')
return
if not isinstance(age, int):
print('年龄必须是数字')
return
self.__name = name
self.__age = age
p1 = Person('jason', 20)
print(p1.__name) # 'Person' object has no attribute '__name' 报错
p1.check_info()
p1.__age = 60 # 会新增一个属性
print(p1.__dict__)
p1.set_info('kevin', 30)
p1.check_info()
###property伪装属性
可以使方法的调用方式和属性相同(不用加括号就能调用方法)
class Myclass(object):
def __init__(self, name):
self.__name = name # 将属性隐藏起来
@property # 将方法伪装成属性
def name(self):
return self.__name
@name.setter # 使伪装方法可以赋值修改
def name(self, value):
if not isinstance(value, str):
raise TypeError(f'{value] must be str')
self.__name = value
@name.delter # del伪装方法时执行
def name(self):
raise PermissionError('can not delete')
obj = Myclass('jason')
print(obj.name)
obj.name = 123 # 因为设置了只能修改为字符串,这里会主动抛错
del obj.name # 主动抛错
###面向对象三大特性值多态
多态:一种事物的多种形态
一种事物有多种形态,但是相同的功能应该有相同的名字
这样的话,无论是什么形态,只要想调用同样的功能调用同一个名字即可
class Animal(object):
def eat(self):
pass
class Cat(Animal):
def eat(self):
print('猫吃饭')
class Dog(Animal):
def eat(self):
print('狗吃饭')
c1 = Cat()
d1 = Dog()
c1.eat()
d1.eat()
"""python也提供了强制性的操作"""
import abc
# 指定metaclass属性将类设置为抽象类,抽象类只为了限制子类,不能被实例化
class Animal(metaclass=abc.ABCMeta)
@abc.abctractmethod # 限制子类必须定义一个被这个装饰的方法
def eat((self):
pass
class Dog(Animal):
def eat(self): # 继承了Animal的子类都必须重写eat方法
pass
"""
鸭子类型:
只要你长得像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子
"""
class Teacher(object):
def run(self):
pass
def eat(self):
pass
class Student(object):
def run(self):
pass
def eat(self):
pass
###面向对象之反射
"""
反射:通过字符串来操作对象的数据或方法
反射主要有四个方法:
hasattr():判断对象有没有字符串指定的属性或方法
getattr():获取字符串指定的属性或方法
setattr():根据字符串给对象设置属性
delattr():根据字符串给对象删除属性
"""
class Myclass(object):
name = '小明'
def func(self):
print('from func')
obj = Myclass()
print(hasattr(obj, 'name')) # True 查询到属性或方法后返回True
res = getattr(obj, 'func') # 获取对应名字的属性或方法,如果没有则报错
res() # from func
setattr(obj, 'age', 18)
print(obj.age) # 18
delattr(obj, 'age')
print(obj.__dict__) # {}
###反射实战案例
class FtpServer:
def serve_forever(self):
while True:
inp = inpput('input your cmd>>>:').strip() # 获取用户输入
com, file = inp.split()
if hasattr(self, com): # 判断输入的指令是否存在
func = getattr(self, cmd) # 获取对应的属性或方法
func(file)
def get(self, file):
print(f'Downloading {file}...')
def put(self, file):
print(f'Uploading {file}...')
obj = FtpServer()
obj.serve_forever()



