面向对象编程3
目录
继承下的派生实际应用
import datetime
import json
# json不能序列化python所有的数据类型,只能序列化一些基本数据类型
dic = {'t1': datetime.datetime.today(), 't2': datetime.date.today()}
res = json.dumps(dic) # Object of type 'datetime' is not JSON serializable
# 方式一:手动将不能序列化的类型先转字符串
dic1 = {'t1': str(datetime.datetime.today()), 't2': str(datetime.date.today())}
res1 = json.dumps(dic1)
print(res1) # {"t1": "2022-04-11 18:25:22.679452", "t2": "2022-04-11"}
# 方式二:研究json源码并重写序列化方法
class MyJsonEncoder(json.JSONEncoder):
def default(self, arg):
# 形参arg就是即将要被json序列化的数据对象
print('提示:重写了json方法', arg)
# 将arg处理成json能够序列化的类型
if isinstance(arg, datetime.datetime):
return arg.strftime('%Y-%m-%d %X')
elif isinstance(arg, datetime.date):
return arg.strftime('%Y-%m-%d')
return super().default(arg) # 调用父类的default
dic2 = {'t1': datetime.datetime.today(), 't2': datetime.date.today()}
res2 = json.dumps(dic2, cls=MyJsonEncoder)
print(res2) # {"t1": "2022-04-11 18:17:28", "t2": "2022-04-11"}
面向对象三大特性之封装
封装的含义
将类中的一些名字'隐藏'起来除了类定义阶段都不能直接调用,隐藏的目的是为了提供专门的调用方式去访问,在调用方式中可以增添额外的功能
class Staff(object):
company = '**IT公司'
__label = '隐藏的值' # python没有真正的隐藏,只是自动转换成了特定的语法
def __init__(self, name, age):
self.name = name
self.age = age
def manufacture_product(self):
print('%s正在制作产品' % self.name)
staff1 = Staff('micheal', 35)
print(staff1.company) # **IT公司
print(staff1.name) # micheal
print(staff1.age) # 35
# print(staff1.__label) # 报错,对象中没有这个属性
staff2 = Staff('david', 40)
print(staff2.company) # **IT公司
print(staff2.name) # david
print(staff2.age) # 40
# print(staff2.__label) # 报错,对象中没有这个属性
print(Staff.__dict__) # {'__module__': '__main__', 'company': '**IT公司', '_Staff__label': '隐藏的值', '__init__': <function Staff.__init__ at 0x00000283C7AAEC80>, 'manufacture_product': <function Staff.manufacture_product at 0x00000283C7AAF378>, '__dict__': <attribute '__dict__' of 'Staff' objects>, '__weakref__': <attribute '__weakref__' of 'Staff' objects>, '__doc__': None}
print(Staff._Staff__label) # 隐藏的值
print(staff1._Staff__label) # 隐藏的值
print(staff2._Staff__label) # 隐藏的值
# 提供专门的调用方式去访问
class Staff(object):
__company = '**IT公司'
def __init__(self, name, age, work_age):
self.__name = name
self.__age = age
self.__work_age = work_age
# 专门开设一个访问员工数据的接口
def observe_info(self):
print("""
员工姓名:%s
员工年龄:%s
员工工龄:%s
""" % (self.__name, self.__age, self.__work_age))
# 专门开设一个修改员工数据的接口
def set_info(self, name, age, work_age):
if len(name) == 0:
print('用户名不能为空')
return
if not isinstance(age, int):
print('年龄必须是数字')
return
if not isinstance(work_age, int):
print('工龄必须是数字')
return
self.__name = name
self.__age = age
self.__work_age = work_age
staff1 = Staff('micheal', 35, 10)
staff1.observe_info() # 员工姓名:micheal\n员工年龄:35\n员工工龄:10
staff1.set_info('micheal', 35, 15)
staff2 = Staff('david', 40, 20)
staff2.observe_info() # 员工姓名:david\n员工年龄:40\n员工工龄:20
staff2.set_info('david_two', 40, 20)
property
作用是将方法伪装成数据
class Person(object):
def __init__(self, name, height, weight):
self.__name = name
self.height = height
self.weight = weight
def BMI(self):
# print('%s的BMI指数是:%s' % (self.name, self.weight / (self.height ** 2)))
return '%s的BMI指数是:%s' % (self.__name, self.weight / (self.height ** 2))
p1 = Person('david', 1.88, 80)
print(p1.BMI()) # david的BMI指数是:22.634676324128566
print(p1.BMI) # <bound method Person.BMI of <__main__.Person object at 0x000002C418E4AEF0>>
p2 = Person('sakura', 1.75, 50)
print(p2.BMI()) # sakura的BMI指数是:16.3265306122449
print(p2.BMI) # <bound method Person.BMI of <__main__.Person object at 0x000002C418E4AF28>>
class Person(object):
def __init__(self, name, height, weight):
self.__name = name
self.height = height
self.weight = weight
@property # 将方法伪装成数据
def BMI(self):
# print('%s的BMI指数是:%s' % (self.name, self.weight / (self.height ** 2)))
return '%s的BMI指数是:%s' % (self.__name, self.weight / (self.height ** 2))
p1 = Person('david', 1.88, 80)
# print(p1.BMI()) # TypeError: 'str' object is not callable
print(p1.BMI) # david的BMI指数是:22.634676324128566
p2 = Person('sakura', 1.75, 50)
# print(p2.BMI()) # TypeError: 'str' object is not callable
print(p2.BMI) # sakura的BMI指数是:16.3265306122449
面向对象三大特性之多态
多态即是一种事物的多种形态
# 多态性
class Animal(object):
def speak(self):
pass
class Cat(Animal):
def speak(self):
print('喵喵喵')
class Dog(Animal):
def speak(self):
print('汪汪汪')
class Sheep(Animal):
def speak(self):
print('咩咩咩')
c1 = Cat()
d1 = Dog()
s1 = Sheep()
c1.speak()
d1.speak()
s1.speak()
import abc
# 强制实现多态性
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def talk(self): # 抽象方法中无需实现具体的功能
pass
class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
def talk(self):
print('正在说话')
p1 = Person() # 如果Person子类中没有一个talk的属性则会报错异常TypeError
p1.talk()
反射
什么是反射
程序可以访问、检测和修改本身状态或者行为的一种能力
反射常见的四个方法
hasattr(): 判断对象是否含有字符串对应的数据或者功能
getattr(): 根据字符串获取对应的变量名或者函数名
setattr(): 根据字符串给对象设置键值对(名称空间中的名字)
delattr(): 根据字符串删除对象对应的键值对(名称空间中的名字)
# 反射实际应用
class Student(object):
school = '衡水中学'
def get(self):
pass
# 编写一个小程序,判断Student名称空间中是否含有用户输入的名字,有则展示出来
guess_name = input('请输入你想要查找的名字>>>:').strip()
if hasattr(Student, guess_name):
target_name = getattr(Student, guess_name)
if callable(target_name):
print('类中有一个功能名字是%s' % guess_name, target_name)
else:
print('类中有一个数据名字是%s' % guess_name, target_name)
else:
print('类中没有该名字')
setattr(Student, 'character', '应试教育')
print(Student.__dict__)
def practice():
pass
obj = Student()
setattr(obj, '理论', '英语')
setattr(obj, '实践', practice)
print(obj.__dict__) # {'理论': '英语', '实践': <function practice at 0x000001B608EA1EA0>}
delattr(obj, '理论')
print(obj.__dict__) # {'实践': <function practice at 0x000001B608EA1EA0>}
"""
# 利用反射获取配置文件中的配置信息
import conf_settings
print(dir(conf_settings))
print(getattr(conf_settings, 'name'))
class FtpServer:
def serve_forever(self):
while True:
inp = input('input your cmd>>: ').strip()
if inp.count(' ') != 1:
print('需要一个空格隔开命令和名字')
return
cmd, file = inp.split()
if hasattr(self, cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
func = getattr(self, cmd) # 根据字符串cmd,获取对象self对应的方法属性
func(file)
def down(self, file):
print('Downloading %s...' % file)
def up(self, file):
print('Uploading %s...' % file)
obj = FtpServer() # 定义一个对象
obj.serve_forever() # 通过对象调用函数
# 利用面向对象编写系统终端功能
class WinCmd(object):
def ls(self):
print('windows系统正在执行ls命令')
def dir(self):
print('windows系统正在执行dir命令')
def cd(self):
print('windows系统正在执行cd命令')
class LinuxCmd(object):
def ls(self):
print('Linux系统正在执行ls命令')
def dir(self):
print('Linux系统正在执行dir命令')
def cd(self):
print('Linux系统正在执行cd命令')
obj = WinCmd()
obj1 = LinuxCmd()
"""反射提供了一种不需要考虑代码的前提下 操作数据和功能"""
def run(obj):
while True:
cmd = input('请输入您的指令>>>:')
if hasattr(obj, cmd):
func_name = getattr(obj, cmd)
func_name()
else:
print('cmd command not found')
run(obj) # 执行WinCmd()
run(obj1) # 执行LinuxCmd()
重要的双下方法
- str
对象被执行展示操作的时候自动触发
该方法必须返回字符串类型的数据
class Book:
title = '西游记'
price = 20
def __str__(self):
print('对象被执行展示操作的时候自动触发')
return self.title
book_obj = Book()
print(book_obj)
print(book_obj.price)
- del
对象被执行(被动、主动)删除操作之后自动执行
class Book(object):
title = '西游记'
price = 20
def __del__(self):
print('对象被执行删除操作之后自动执行')
return
book_obj = Book()
Book.__del__(book_obj)
- getattr
对象查找不存在名字的时候自动触发
class Book(object):
title = '西游记'
price = 20
def __getattr__(self, item):
print('对象查找不存在名字的时候自动触发')
return "%s对象中没有属性'%s'" % (self.title, item)
book_obj = Book()
# print(book_obj.price)
print(book_obj.press)
- setattr
对象在执行添加属性操作的时候自动触发
class Book(object):
title = '西游记'
price = 20
def __setattr__(self, key, value):
print('对象在执行添加属性操作的时候自动触发')
return
book_obj = Book()
book_obj.press = '北京出版社'
book_obj.author = '六小龄童'
- call
对象被加括号调用的时候自动触发
class Book(object):
title = '西游记'
price = 20
def __call__(self, *args, **kwargs):
print('对象被加括号调用的时候自动触发')
print('一些小功能')
return 'jason nb'
book_obj = Book()
print(book_obj())
- enter
对象被执行with上下文管理语法开始自动触发
该方法返回什么as后面的变量名就会得到什么
class Book(object):
title = '西游记'
price = 20
def __enter__(self):
"""
对象被执行with上下文管理语法开始自动触发
with后面的as后面的变量名会接收__enter__方法的return返回值
"""
print('执行__enter__方法')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""对象被执行with上下文管理语法结束自动触发"""
print('执行__exit__方法')
return
book_obj = Book()
with book_obj as f:
print(f)
print('执行with上下文管理')
print('with上下文管理结束')
- exit
对象被执行with上下文管理语法结束之后自动触发
class Book(object):
title = '西游记'
price = 20
def __enter__(self):
"""
对象被执行with上下文管理语法开始自动触发
with后面的as后面的变量名会接收__enter__方法的return返回值
"""
print('执行__enter__方法')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""对象被执行with上下文管理语法结束自动触发"""
print(exc_type, exc_val, exc_tb)
print('执行__exit__方法')
return
book_obj = Book()
with book_obj as f:
print(f)
print('执行with上下文管理')
print('with上下文管理结束')
- getattribute
只要对象查找名字无论名字是否存在都会执行该方法
类中有__getattribute__方法,就不会去执行__getattr__方法
class Book(object):
title = '西游记'
price = 20
def __getattribute__(self, item):
print('对象查找属性的时候自动触发')
return "无论存在与否"
# return "%s对象中没有属性'%s'" % (self.title, item)
book_obj = Book()
print(book_obj.price)
# print(book_obj.press)
- new
class Book(object):
title = '西游记'
price = 20
def __new__(cls, *args, **kwargs):
print('类实例的创建对象的时候执行')
return 'jason nb'
print(Book())
元类简介
元类即产生类的类
# type查看的是当前对象所属的类名称
print(type(111)) # <class 'int'>
print(type(111.0)) # <class 'float'>
print(type([111, 222, 333])) # <class 'list'>
print(type({'name': 'david', 'age': 30})) # <class 'dict'>
class MyClass(object):
pass
obj = MyClass()
print(type(obj)) # <class '__main__.MyClass'>
print(type(MyClass)) # <class 'type'>
class Student(MyClass):
pass
print(type(Student)) # <class 'type'>
class Teacher(MyClass):
pass
print(type(Teacher)) # <class 'type'>
产生类的两种表现形式
class关键字
class CLS1(object):
pass
print(CLS1) # <class '__main__.CLS1'>
type元类
# 语法结构type(cls_name, cls_bases, cls_dict)
res = type('CLS1', (), {})
print(res) # <class '__main__.CLS1'>
元类的基本使用
元类不能通过继承的方式直接指定,需通过关键字参数metaclass
class MyTypeClass(type):
pass
class C1(metaclass=MyTypeClass):
pass
class MyTypeClass(type):
def __init__(cls, cls_name, cls_bases, cls_dict):
print(cls, cls_name, cls_bases, cls_dict)
if not cls_name.istitle():
raise Exception("类名的首字母必须大写,首字母以外小写")
super().__init__(cls_name, cls_bases, cls_dict)
class Cls1(metaclass=MyTypeClass):
name = 'tom hahaha'
class cls2(metaclass=MyTypeClass):
name = 'tom hahaha'
元类进阶操作
# 定制对象的产生过程
class MyTypeClass(type):
def __call__(cls, *args, **kwargs):
print('__call__ run')
print(args, kwargs) # () {'name': 'david'}
if args:
raise Exception('必须全部采用关键字参数')
super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
print('__init__ run')
self.name = name
# obj1 = MyClass('david')
obj2 = MyClass(name='david')
__new__方法
# 在元类的__new__里面,可以直接调用
class Meta(type):
def __new__(cls, *args, **kwargs):
cls = type.__new__(cls, *args, **kwargs)
return cls
Cls1 = Meta('Cls1', (), {})
print(Cls1) # <class '__main__.Cls1'>
obj = Cls1()
obj.name = 'sam'
obj.age = 20
print(obj.__dict__) # {'name': 'sam', 'age': 20}
# 在元类的__call__里面,需要间接调用
class Mate(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self) # 创建一个空对象
self.__init__(obj, *args, **kwargs) # 让对象去初始化
return obj
Cls2 = Mate('Cls2', (), {})
obj1 = Cls2()
obj1.name = 'sam'
obj1.age = 20
print(obj1.__dict__) # {'name': 'sam', 'age': 20}