- 派生方法的实战演练
- 面向对象三大特性之封装
- property伪装属性
- 面向对象三大特性之多态
- 面向对象之反射
- 什么是反射?
- getattr(核心)
- hasattr
- settattr
- delattr
- 反射实战案例
import datetime
import json
d = {
't1': datetime.datetime.today(),
't2': 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 serializablejson序列化python数据类型是有限制的 不是所有的类型都可以
ps:即将要被序列化的数据 里里外外都必须是满足的类型才可以
最简单的解决办法
import datetime
import json
d = {
't1': str(datetime.datetime.today()),
't2': str(datetime.date.today())
}
res = json.dumps(d)
print(res) # {"t1": "2022-07-28 16:08:56.479959", "t2": "2022-07-28"}
但是这种方法显得很low,有一种高级的方法
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')
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 16:21:29", "t2": "2022-07-28"}
json.dumps(d, cls=MyJsonEncode)
面向对象三大特性之封装
-
理解
封装其实就是将数据或者功能隐藏起来(包起来 装起来)
-
封装的目的
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口 让用户使用接口才可以去使用 我们在接口中添加一些额外的操作
-
注意
1.在类定义阶段使用双下划线开头的名字,都是隐藏的属性
后续类和对象都无法直接获取
2.在python中不会真正的限制任何代码
隐藏的属性如果真的需要访问 也可以 只不过需要做变形处理
__变量名, _类名__变量名既然隐藏了 就不改使用变形之后的名字去访问 这样就失去了隐藏的意义
-
举例说明
class MyClass(object): school = '清华大学' def __init__(self, name, age): self.__name = name self.__age = age def info(self): print(f''' 学生名字:{self.__name} 学生年龄:{self.__age} ''') def view(self, name, age): if len(name) == 0: print('用户名不能为空') return if not isinstance(age, int): print('必须为数字') return self.__name = name self.__age = age obj = MyClass('lzq', 21) obj.info() obj.view('gsy', 21) obj.info() ''' 学生名字:lzq 学生年龄:21 学生名字:gsy 学生年龄:21 '''我们编写python很多时候都是大家墨守成规的东西 不需要真正的限制
-
理解
可以简单的理解为 将方法伪装成数据
obj.name # 数据只需要点名字
obj.func() # 方法至少还要加括号
伪装之后可以将func方法伪装成数据 obj.func -
扩展了解
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('jason', 78, 1.83) res = p1.BMI # 不用加括号 print(res) # 23.291229956104985 p2 = Person('lzq', 70, 1.83) res = p2.BMI # 不用加括号 print(res) # 20.902385858042937```@property``` 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
子类可以从父类继承相同的属性或者方法,比如相同的函数名,在子类中可以有不同的实现,即子类可以有自己的特殊性,这就叫做多态。
多态的话按照我的理解就是一个物体的多种形态,比如可口可乐,在原先的基础上现在又有了樱桃味的,无糖等等。就是让原本功能比较简单的类,去在原基础上可以添加其他功能,官方点说就是增加它的灵活性。
为了更加生动的理解多态,再次利用上面的例子:
现在就可以对子类增加一些方法
举例说明
class Animal(object):
def spark(self):
pass
class Cat():
def spark(self):
print('喵喵喵')
class Dog():
def spark(self):
print('汪汪汪')
class Pig():
def spark(self):
print('哼哼哼')
c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.spark() # 喵喵喵
d1.spark() # 汪汪汪
p1.spark() # 哼哼哼
一种事物有多种形态 但是相同的功能应该有相同的名字
这样的话 以后我无论拿到哪个具体的动物 都不需要管到底是谁 直接调用相同的功能即可
无论你是鸡 鸭 猫 狗 猪 只要你想叫 你就调固定的叫的功能
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()
现在就可以总结出实现多态有两个前提:
1.继承:多态必须发生在父类与子类之间 2.重写:子类重写父类方法
操作系统
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:一切皆对象
只要你有数据 有功能 那么你就是对象
文件名 文件对象
模块名 模块对象
反射就是通过字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动
可以使用反射的地方:
1.反射类中的变量 : 静态属性,类方法,静态方法
2.反射对象中的变量、对象属性、普通方法
3. 反射模块中的变量
4. 反射本文件中的变量
getattr(核心)变量名school 与字符串school 区别大不大
stu.school
stu.‘school’两者虽然只差了引号 但是本质是完全不一样的
判断类、对象或者模块中是否有相应的属性或方法。用法:getattr(obj,str,default=None) 判断obj中是否有str属性,有就返回,没有时有传入第三参数就返回第三参数,没有就报错。
class MyClass:
name = 'lzq'
age = 21
print(getattr(MyClass, 'name')) # lzq
print(getattr(MyClass, 'hobby')) # 报错
print(getattr(MyClass, 'hobby', 'not')) # not
hasattr
判断时候有某个属性,有就返回True,没有就返回False
class MyClass:
name = 'lzq'
age = 21
print(hasattr(MyClass, 'name')) # Ture
print(hasattr(MyClass, 'hobby')) # Flase
settattr
设置属性,第三方参数为新的属性
class MyClass:
name = 'lzq'
age = 21
setattr(MyClass, 'hobby', 'read')
print(getattr(MyClass, 'hobby')) # read 新增
setattr(MyClass, 'name', 'gsy')
print(getattr(MyClass, 'name')) # gsy 修改
delattr
删除某个属性
class MyClass:
name = 'lzq'
age = 21
print(getattr(MyClass, 'name')) # lzq
delattr(MyClass, 'name') # 删除属性
print(getattr(MyClass, 'name')) # 报错,因为已经被删除了
反射实战案例
class MyClass:
def view(self):
while True:
choice = input('请输入你的指令:').strip()
cmd, flag = choice.split() # 以空格为分隔符分开
if hasattr(self, cmd): # 判断是否存在
func = getattr(self, cmd) # 取得值
func(flag) # 加括号调用,并传参
else:
print('没有该执行任务')
def get(self, flag):
print('正在下载%s' % flag)
def put(self, flag):
print('正在升级%s' % flag)
obj = MyClass() # 产生对象
obj.view()
'''
请输入你的指令:get a.txt
正在下载a.txt
请输入你的指令:put a.txt
正在升级a.txt
请输入你的指令:a a.txt
没有该执行任务
'''



