面向对象编程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()

重要的双下方法

  1. str
    对象被执行展示操作的时候自动触发
    该方法必须返回字符串类型的数据
class Book:
    title = '西游记'
    price = 20

    def __str__(self):
        print('对象被执行展示操作的时候自动触发')
        return self.title


book_obj = Book()
print(book_obj)
print(book_obj.price)

  1. del
    对象被执行(被动、主动)删除操作之后自动执行
class Book(object):
    title = '西游记'
    price = 20

    def __del__(self):
        print('对象被执行删除操作之后自动执行')
        return


book_obj = Book()
Book.__del__(book_obj)

  1. 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)

  1. setattr
    对象在执行添加属性操作的时候自动触发
class Book(object):
   title = '西游记'
   price = 20

   def __setattr__(self, key, value):
       print('对象在执行添加属性操作的时候自动触发')
       return


book_obj = Book()
book_obj.press = '北京出版社'
book_obj.author = '六小龄童'

  1. call
    对象被加括号调用的时候自动触发
class Book(object):
    title = '西游记'
    price = 20

    def __call__(self, *args, **kwargs):
        print('对象被加括号调用的时候自动触发')
        print('一些小功能')
        return 'jason nb'


book_obj = Book()
print(book_obj())

  1. 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上下文管理结束')

  1. 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上下文管理结束')

  1. 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)

  1. 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}
posted @ 2022-04-11 19:56  一梦便是数千载  阅读(25)  评论(0编辑  收藏  举报