一、派生方法实战演练
什么是派生方法?
子类中的定义方法和父类定义方法一摸一样的方法并且扩展了新功能
(子类和父类一样 但是子类可以修改父类自定义新功能)
'''将下列数据以Json序列化格式打印出来'''
Like = {
't1': datetime.datetime.today(),
't2': datetime.date.today()
}
1. 导入datetime、json模块直接打印
res = json.dumps(Like)
print(res)
出现报错:TypeError: Object of type datetime is not JSON serializable
我们点击进去查看源码(图1)发现datetime模块不能直接序列化(必须是要图片里面显示的类型)
2. 解决方法1:手动将不符合数据类型转成符合要求的数据类型
Like = {
't1': str(datetime.datetime.today()),
't2': str(datetime.date.today())
}
res = json.dumps(Like)
print(res)
3. 利用派生方法
Like = {
't1': datetime.datetime.today(),
't2': datetime.date.today()
}
res = json.dumps(Like)
出现报错:TypeError: Object of type datetime is not JSON serializable
查看JSONEncoder源码发现序列化报错是有default方法触发的
raise TypeError(f'Object of type {o.__class__.__name__} 'f'is not JSON serializable')
我们如果想要避免报错 那么肯定需要对default方法做修改(派生)
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)
'''让python的不走自己的default走我们自定义的default再放他回去走它的'''
res = json.dumps(Like, cls=MyJsonEncode)
print(res)
json.dumps(Like, cls=MyJsonEncode)
二、面向对象三大特性之封装
什么是封装?
封装就是把数据或者功能隐藏起来包起来
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口
class Student(object):
__school = '清华大学'
def __init__(self, name, age):
self.__name = name
self.__age = age
1.在类的定义阶段使用双下划线开头的名字都是隐藏的属性(后续类和对象都不可以直接获取 会报错)
2.在python中不会真正的限制任何代码 隐藏的属性如果真的需要访问 也可以 只不过需要做变形处理
ex: __隐藏的变量名 实际在名称空间里面_类名__变量名
ps:既然是隐藏 就不应该使用变形之后的名字去访问 那样就没有隐藏的意义了
在这些隐藏的属性里面 怎样获取呢 这就是python给隐藏的属性加一个特定的接口
如果你想要的用到里面的属性就必须使用这个接口
class People(object):
__man = 'LebronJames'
def __init__(self, name, age):
self.__name = name
self.__age = age
# 专门开设一个访问人类数据的通道(接口)
def check_info(self):
print("""
人类姓名:%s
人类年龄:%s
""" % (self.__name, self.__age))
三、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('LebronJames', 113, 2.06)
print(p1.BMI)
BMI虽然需要计算获得 但是更像是人的数据 @property
如何将方法伪装成数据呢 这就有一个装饰器 用这个装饰器装饰之后就可以直接调用
拓展2
我们的属性隐藏起来了 但是我们通过修改数据值发现报错 这就是我们伪装失败了
class Foo:
def __init__(self, val):
self.__NAME = val # 将属性隐藏起来
@property
def name(self):
return self.__NAME
f1 = Foo('LebronJames')
print(f1.name)
f1.name = 'DwightHoward'
print(f1.name)
所谓谎言需要更多谎言去弥补 所以跟伪装方法配套使用的还有两个
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')
f1 = Foo('LebronJames')
print(f1.name)
f1.name = 'DwightHoward'
print(f1.name)
四、面向对象三大特性之多态
什么是多态呢?
多态就是一种事物的形态(水:液态、气态、固态、 人: 黄皮、黑皮、白皮)
一种事物有多中形态 但是相同的功能应该有相同的名字
例如动物类:
class Animal(object):
def speark(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 speark(self):
pass
class Cat(Animal):
def speark(self):
print('喵喵喵')
class Dog(Animal):
def speark(self):
print('汪汪汪')
c1 = Cat()
d1 = Dog()
c1.speark() # 统一一个功能 speark 发声
d1.speark()
其实上述多态的概念 我们很早之前就已经使用过(列表、字典、集合的统计数据方法)
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))
我们的len也就是这种方法 统计数据的个数统一功能
'''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()
操作系统
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():根据字符串给对象删除属性
判断用户提供的名字在不在对象可以使用的范围内
class Student:
school = '清华大学'
def choice_course(self):
print('选课')
stu = Student()
方式1:利用异常处理
try:
if stu.school:
print(f"True{stu.school}")
except Exception:
print("没有属性")
方式2: 获取用户输入的名字 然后判断该名字对象有没有
while True:
target_name = input('请输入您想要核查的名字>>>:').strip()
'''上面的异常更加不好实现 需要用反射'''
if hasattr(stu, target_name):
res = getattr(stu, target_name)
if callable(res):
print('拿到的名字是一个函数', res())
else:
print('拿到的名字是一个数据', res)
else:
print('不好意思 您想要查找的名字 对象没有')
六、反射实战案例
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()
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请
点赞收藏+关注
谢谢支持!