派生方法的实战演练 面向对象三大特性之一:封装 property伪装属性 面向对象三大特性之一:多态 面向对象之反射
作者:互联网
目录
派生方法的实战演练
一、发现问题:
import datetime
import json
d = {
't1':datetime.datetime.today(),
't2':datetime.date.today()
}
res = json.dumps(d)
print(res)
上述代码会报错,无法正常序列化
raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)
TypeError: Object of type 'datetime' is not JSON serializable
json序列化python数据是有限制的,不是所有的数据类型都可以
json模块默认:将要序列化的数据必须是以下表格中的类型
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 |
+-------------------+---------------+
二、解决问题
解决方法 1:手动将数据类型转成符合要求的
import datetime
import json
d = {
't1':str(datetime.datetime.today()),
't2':str(datetime.date.today())
}
res = json.dumps(d)
print(res)
# 输出:{"t1": "2022-07-29 19:25:34.672788", "t2": "2022-07-29"}
解决方法2:利用派生方法
if cls is None:
cls = JSONEncoder
return cls(
skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
separators=separators, default=default, sort_keys=sort_keys,**kw).encode(obj)
查看JSONEncoder源码发现序列化报错是由default方法触发的
raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)
我们如果想要避免报错,那么肯定需要对default方法做修改(也就是派生)
import datetime
import json
d = {
't1':datetime.datetime.today(),
't2':datetime.date.today()
}
class MyJsonEncode(json.JSONEncoder):
def default(self, o):
'''o:就是json即将要序列化的数据'''
if isinstance(o, datetime.datetime):
return o.strftime('%Y-%m-%d %H:%M:%S')
if isinstance(o, datetime.date):
return o.strftime('%Y-%m-%d')
return super().default(o)
res = json.dumps(d,cls = MyJsonEncode)
print(res)
json.dumps(d,cls=MyJsonEncode)
# 输出 {"t1": "2022-07-29 19:42:02", "t2": "2022-07-29"}
面向对象三大特性之一:封装
一、意义
封装其实就是将数据或功能隐藏起来(包起来 装起来)
隐藏的目的不是让用户无法使用,而是给这些隐藏的数据开设特定的接口
让用户使用接口才可以去使用,我们在接口中可以添加一些额外操作
二、特点
1.在定义阶段使用双下划线开头的名字,都是隐藏的属性
后续类和对象都无法直接获取
2.在Python中不会真正的限制任何代码
隐藏的属性如果真的需要访问,可以通过变形处理去访问
__变量名 -------> _类名__变量名
既然隐藏了,那就不应该使用变形后的名字去访问,因为这样做就失去了隐藏的意义
class Student(object):
__school = '清华大学'
def __init__(self, name, age):
self.__name = name
self.__age = age
def check_info(self):
print('''
学生姓名:%s
学生年龄:%s
''' % (self.__name, self.__age))
# 专门开设一个学生访问数据的通道(接口)
def set_info(self,name,age):
if len(name) == 0:
print('用户名不能为空')
return
self.__name = name
self.__age = age
stu1 = Student('ZHANG',22)
stu1.set_info('','bbb')
# 输出:用户名不能为空
property伪装属性
一、介绍
可以简单理解为,把方法伪装成数据
obj.name # 数据只需要点名字
obj.func() # 方法至少还要加括号
'''伪装之后可以将func方法伪装成数据'''
obj.func
二、扩展了解
体质指数(BMI)= 体重(kg)÷ 身高(m)^2
class Person:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
@property
def BMI(self):
return self.weight / (self.height ** 2)
p1 = Person('JJJ', 200, 180)
res = p1.BMI
print(res)
p2 = Person('SSS',80,200)
res = p2.BMI
print(res)
# 0.006172839506172839
# 0.002
class Foo:
def __init__(self, val):
self.__NAME = val # 将属性隐藏起来
@property
def name(self):
return self.__NAME
@name.setter
def name(self, value):
if not isinstance(value, str): # 在设定值之前进行类型检查
raise TypeError('%s must be str' % value)
self.__NAME = value # 通过类型检查后,将值value存放到真实的位置self.__NAME
@name.deleter
def name(self):
raise PermissionError('Can not delete')
obj = Foo('jason')
# print(obj.name)
# obj.name = 666
# print(obj.name)
del obj.name
面向对象三大特性之一:多态
一、介绍
多态:一种事物的多种形态
eg:水:液态 气态 固态 动物:人 猫 狗 牛
二、代码演示
一种事物有多种形态,但相同的功能应该有相同的名字
这样的话,以后无论拿到那个具体的动物,都不需要管到底是谁,直接调用相同的功能即可
eg:无论是什么动物,猫也好,狗也好,只要想叫,就固定调用speak功能
class Animal(object):
def speak(self):
pass
class Cat(Animal):
def miao(self):
print('喵喵喵')
class Dog(Animal):
def wang(self):
print('汪汪汪')
class Pig(Animal):
def heng(self):
print('哼哼哼')
c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.miao()
d1.wang()
p1.heng()
'''在这种情况下,每种动物都有各自叫的方法,就是多态'''
'''像下面代码这样,就可以解除多态'''
class Animal(object):
def speak(self):
pass
class Cat(Animal):
def speak(self):
print('喵喵喵')
class Dog(Animal):
def speak(self):
print('汪汪汪')
class Pig(Animal):
def speak(self):
print('哼哼哼')
c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.speak()
d1.speak()
p1.speak()
其实上述多态的概念,我们之前就已经接触过
l1 = [11,22,33,44]
d1 = {'name':'zhang','age':19,'hobby':'learn'}
t1 = (1,2,3,4,5)
print(len(l1))
print(len(d1))
print(len(t1))
三、了解知识 —— 抽象类
1.指定metaclass属性将类设置为抽象类
python提供了一种强制性的操作(应该自觉遵守)
import abc
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def talk(self): # 抽象方法中无需实现具体的功能
pass
class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal 规定的标准
def talk(self):
pass
def run(self):
pass
obj = Person()
2.鸭子类型
只要长得像鸭子,走路像鸭子,说话像鸭子,那么它就是鸭子
class Teacher:
def run(self):pass
def eat(self):pass
class Student:
def run(self):pass
def eat(self):pass
'''
操作系统
Linux系统:一切皆文件
只要你能读数据,能写数据,那么你就是文件
'''
class Txt: # txt类有连个与文件类型同名的方法,即read和write
def read(self):
pass
def write(self):
pass
class Disk: # Disk类也有两个与文件类型同名的方法:read和write
def read(self):
pass
def write(self):
pass
class Memory: # Memory类也有两个与文件类型同名的方法:read和write
def read(self):
pass
def write(self):
pass
'''
python解释器:一切皆对象
只要你有数据、有功能,那么你就是对象
文件名 文件对象
模块名 模块对象
'''
面向对象之反射
一、介绍
反射:通过字符串来操作对象的数据或方法
二、反射主要的四个方法:
hasattr():判断对象是否含有某个字符串对应的属性
getattr():判断对象字符串对应的属性
setattr():根据字符串给对象设置属性
delattr():根据字符串给对象删除属性
三、代码演示
1.需求:判断用户提供的名字在不在对象可以使用的范围内
class Student:
school = '清华大学'
def choice_course(self):
print('选课')
stu = Student()
方式一:利用异常处理(过于繁琐)
try:
if stu.school:
print(f'True{stu.school}')
except Exception:
print('没有属性')
方式二:获取用户输入的名字,然后判断该名字的对象有没有
'''
变量名school 与字符串school 看起来区别不大
stu.school
stu.'school'
两者虽然只差了引号,但是本质完全不同
'''
while True:
target_name = input('请输入您的姓名>>>:').strip()
'''上面的异常更难实现,需要反射'''
print(hasattr(stu,target_name))
print(getattr(stu,target_name))
if hasattr(stu,target_name):
print(getattr(stu,target_name))
res = getattr(stu,target_name)
if callable(res):
print('拿到的是一个函数名',res())
else:
print('拿到的是名字是一个数据',res)
else:
print('没在对象里找到这个名字')
2.四个方法试用
print(stu.__dict__) # {}
stu.name = 'zhang'
stu.age = 19
print(stu.__dict__) # {'name': 'zhang', 'age': 19}
setattr(stu,'gender','male')
setattr(stu,'hobby','read')
print(stu.__dict__)
# {'name': 'zhang', 'age': 19, 'gender': 'male', 'hobby': 'read'}
del stu.name
print(stu.__dict__)
# {'age': 19, 'gender': 'male', 'hobby': 'read'}
delattr(stu,'age')
print(stu.__dict__)
# {'gender': 'male', 'hobby': 'read'}
四、反射实战案例
class FtpServer:
def serve_forever(self):
while True:
inp = input('input your cmd>>>:').strip()
cmd, file = inp.split()
if hasattr(self, cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
func = getattr(self, cmd)
func(file)
def get(self, file):
print('Downloading %s...' % file)
def put(self, file):
print('Uploading %s...' % file)
obj = FtpServer()
obj.serve_forever()
标签:name,stu,self,特性,面向对象,三大,print,class,def 来源: https://www.cnblogs.com/Zhang614/p/16536899.html