今日内容
派生方法的实战演练
import datetime
import json
d = {
't1':datetime.datetime.today(),
't2':datetime.date.today()
}
res = json.dumps(d)
print(res)
# 上述代码会报错 无法正常序列化
'''
o.__class__.__name__)
TypeError: Object of type 'datetime' is not JSON serializable
'''
json序列化python数据类型是有限制的 不是所有的类型都可以
ps:即将要被序列化的数据 里里外外都必须是下述类型才可以
| python | JSON |
|---|---|
| dict | object |
| list,tuple | array |
| str | string |
| int,float | number |
| True | true |
| False | false |
| None | null |
解决方式一、
手动将不符合的数据类型要求的数据转成符合要求的
d = {
't1':str(datetime.datetime.today()),
't2':str( datetime.date.today())
}
res = json.dumps(d)
print(res) # {"t1": "2022-07-28 15:17:22.080005", "t2": "2022-07-28"}
解决方式二、
利用派生方法
class MyJsonEncode(json.JSONEncoder):
def default(self, o):
if isinstance(o,datetime.datetime):
return o.strftime('%Y-%m-%d %H-%M-%S')
elif isinstance(o,datetime.date):
return o.strftime('%Y-%m-%d')
return super().default(o)
res = json.dumps(d,cls=MyJsonEncode)
print(res) # {"t1": "2022-07-28 15:27:21.758345", "t2": "2022-07-28"}
面向对象三大特性之封装
封装其实就是将数据或者功能隐藏起来(包起来 装起来)
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口 让用户使用接口才可以去使用 我们在接口中添加一些额外的操作
1.在类定义阶段使用双下划线开头的名字 都是隐藏的属性
后续类和对象都无法直接获取
2.在python中不会真正的限制任何代码
隐藏的属性如果真的需要访问 也可以 只不过需要做变形处理
__变量名 _类名__变量名
ps:既然隐藏了 就不改使用变形之后的名字去访问 这样就失去了隐藏的意义
小案例、
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
if not isinstance(age, int):
print('年龄必须是数字')
return
self.__name = name
self.__age = age
sut1 = Student('jason', 18)
# print(sut1.__school) # 对象直接调用被隐藏的名字是找不到的 会报错
# print(Student.__school) # 类名直接调用被隐藏的名字是找不到的 会报错
# 可以使用_类名__变量名找到
# print(sut1._Student__school) # 清华大学
# sut1.check_info() # 学生姓名:jason # 学生年龄:18
# sut1.set_info('jasonNB', 28) # 调用set_info才能修改
# sut1.check_info() # 学生姓名:jason # 学生年龄:28
# print(sut1.__dict__) # {'name': 'jasonNB', 'age': 28}
# sut1.set_info('', '我很大') # 用户名不能为空
# sut1.set_info('jason', '我很大') # 年龄必须是数字
pioperty伪装属性
伪装的含义
可以简单的理解为 将方法伪装成数据
obj.name # 数据只需要点名字
obj.func() # 方法至少还要加括号
伪装之后可以将func方法伪装成数据 obj.func
小案例
装饰器关键字:@property
扩展了解
体质指数(BMI)=体重(kg)÷身高^2(m)
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('joker', 65, 1.80)
# res = p1.BMI()
# print(res) # 20.061728395061728
# p1 = Person('lisa', 100, 1.86)
# res = p1.BMI()
# print(res) # 28.905075731298414
"""BMI虽然需要计算获得 但是更像人的数据"""
# 用@property装饰器把一个方法装饰了 就不需要加括号了
# 前提是不能有额外的参数 只需要有一个对象 有额外的参数就不能装饰起来了
p1 = Person('joker', 65, 1.80)
print(p1.BMI) # 20.061728395061728
print(p1.name) # joker
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) # jason
obj.name = 666 # 修改不是str类型 会报错
print(obj.name)
del obj.name # 会报错
面向对象三大特性之多态
多态是指一种事物的多种形态
比如水:液态 气态 固态
比如动物: 狗 猫 猪
class Animal(object):
def spark(self):
pass
class Cat(Animal):
def miao(self):
print('喵喵喵')
class Dog(Animal):
def wang(self):
print('汪汪汪')
c1 = Cat()
d1 = Dog()
c1.miao() # 喵喵喵
d1.wang() # 汪汪汪
一种事物有多种形态 但是相同的功能应该有相同的名字
class Animal(object):
def spark(self):
pass
class Cat(Animal):
def spark(self):
print('喵喵喵')
class Dog(Animal):
def spark(self):
print('汪汪汪')
def spark(animal):
animal.spark()
cat = Cat()
spark(cat) # 喵喵喵
dog = Dog()
dog.spark() # 汪汪汪
其实上述多态的概念 我们很早之前就已经使用过了
l1 = [11, 22, 33, 44]
d1 = {'name': 'jason', 'pwd': 123, 'hobby': 'raed'}
t1 = (11, 22, 33, 44)
print(len(l1))
print(len(d1))
print(len(t1))
python也提供了一种强制性的操作 我们应该自觉遵守(了解即可)
# 指定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() 有两个相同talk的不会报错
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def talk(self): # 抽象方法中无需实现具体的功能
pass
class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
def talk1(self):
pass
def run(self):
pass
obj = Person() 没有两个相同的talk会报错
鸭子类型
如果看起来像 叫声像而且走起路来像鸭子 那么它就是鸭子。
比起继承的方式 鸭子类型在某种程度上实现了程序的松耦合度
eg:
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():根据字符串给对象删除属性
hasattr()使用案例

getattr()使用案例

hasattr()与getattr()使用


setattr()案例
根据'字符串'的方式给对象添加键值对
class Student:
school = '清华大学'
def choice_course(self):
print('正在选课')
stu = Student()
print(stu.__dict__) # {}
stu.name = 'jason'
stu.age = 18
print(stu.__dict__) # {'name': 'jason', 'age': 18}
setattr(stu, 'gender', 'male')
setattr(stu, 'bobby', 'eat')
print(stu.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male', 'bobby': 'eat'}
delattr()
可以让用户指定用'字符串'的方式删除
class Student:
school = '清华大学'
def choice_course(self):
print('正在选课')
stu = Student()
print(stu.__dict__) # {}
stu.name = 'jason'
stu.age = 18
print(stu.__dict__) # {'name': 'jason', 'age': 18}
setattr(stu, 'gender', 'male')
setattr(stu, 'bobby', 'eat')
print(stu.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male', 'bobby': 'eat'}
del stu.name
print(stu.__dict__) # {'age': 18, 'gender': 'male', 'bobby': 'eat'}
delattr(stu, 'age')
print(stu.__dict__) # {'gender': 'male', 'bobby': 'eat'}
反射实战案例
以后只要在需求中看到了关键字
....对象....字符串
那么肯定需要使用反射
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) # 根据字符串cmd,获取对象self对应的方法属性
func(file)
def get(self, file):
print('Downloading %s...' % file)
def put(self, file):
print('Uploading %s...' % file)
obj = FtpServer()
obj.serve_forever()
posted on
浙公网安备 33010602011771号