ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

派生方法的实战演练 面向对象三大特性之一:封装 property伪装属性 面向对象三大特性之一:多态 面向对象之反射

2022-07-31 13:02:45  阅读:227  来源: 互联网

标签:name stu self 特性 面向对象 三大 print class def


目录

派生方法的实战演练

一、发现问题:

import datetime
import json

d = {
    't1':datetime.datetime.today(),
    't2':datetime.date.today()
}
res = json.dumps(d)
print(res)

image

上述代码会报错,无法正常序列化

raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)

TypeError: Object of type 'datetime' is not JSON serializable

json序列化python数据是有限制的,不是所有的数据类型都可以

json模块默认:将要序列化的数据必须是以下表格中的类型

Supports the following objects and types by default:
# 默认支持以下对象和类型:
    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+

二、解决问题

解决方法 1:手动将数据类型转成符合要求的

import datetime
import json

d = {
    't1':str(datetime.datetime.today()),
    't2':str(datetime.date.today())
}
res = json.dumps(d)
print(res)

# 输出:{"t1": "2022-07-29 19:25:34.672788", "t2": "2022-07-29"}

解决方法2:利用派生方法

if cls is None:
	cls = JSONEncoder
 return cls(
        skipkeys=skipkeys, ensure_ascii=ensure_ascii,
        check_circular=check_circular, 					    allow_nan=allow_nan, indent=indent,
        separators=separators, default=default, 			    sort_keys=sort_keys,**kw).encode(obj)

查看JSONEncoder源码发现序列化报错是由default方法触发的

raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)

我们如果想要避免报错,那么肯定需要对default方法做修改(也就是派生)

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')
        if isinstance(o, datetime.date):
            return o.strftime('%Y-%m-%d')
        return super().default(o)

res = json.dumps(d,cls = MyJsonEncode)
print(res)
json.dumps(d,cls=MyJsonEncode)

# 输出 {"t1": "2022-07-29 19:42:02", "t2": "2022-07-29"}

面向对象三大特性之一:封装

一、意义

封装其实就是将数据或功能隐藏起来(包起来 装起来)

隐藏的目的不是让用户无法使用,而是给这些隐藏的数据开设特定的接口

让用户使用接口才可以去使用,我们在接口中可以添加一些额外操作

二、特点

1.在定义阶段使用双下划线开头的名字,都是隐藏的属性

后续类和对象都无法直接获取

2.在Python中不会真正的限制任何代码

隐藏的属性如果真的需要访问,可以通过变形处理去访问

__变量名    ------->   _类名__变量名

既然隐藏了,那就不应该使用变形后的名字去访问,因为这样做就失去了隐藏的意义

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
        self.__name = name
        self.__age = age

stu1 = Student('ZHANG',22)
stu1.set_info('','bbb')
# 输出:用户名不能为空

property伪装属性

一、介绍

可以简单理解为,把方法伪装成数据

obj.name  # 数据只需要点名字
obj.func()  # 方法至少还要加括号
'''伪装之后可以将func方法伪装成数据'''
obj.func

二、扩展了解

体质指数(BMI)= 体重(kg)÷ 身高(m)^2

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('JJJ', 200, 180)
res = p1.BMI
print(res)
p2 = Person('SSS',80,200)
res = p2.BMI
print(res)
# 0.006172839506172839
# 0.002


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

面向对象三大特性之一:多态

一、介绍

多态:一种事物的多种形态

eg:水:液态 气态 固态 动物:人 猫 狗 牛

二、代码演示

一种事物有多种形态,但相同的功能应该有相同的名字

这样的话,以后无论拿到那个具体的动物,都不需要管到底是谁,直接调用相同的功能即可

eg:无论是什么动物,猫也好,狗也好,只要想叫,就固定调用speak功能

class Animal(object):
    def speak(self):
        pass


class Cat(Animal):
    def miao(self):
        print('喵喵喵')


class Dog(Animal):
    def wang(self):
        print('汪汪汪')


class Pig(Animal):
    def heng(self):
        print('哼哼哼')


c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.miao()
d1.wang()
p1.heng()
'''在这种情况下,每种动物都有各自叫的方法,就是多态'''
'''像下面代码这样,就可以解除多态'''
class Animal(object):
    def speak(self):
        pass


class Cat(Animal):
    def speak(self):
        print('喵喵喵')


class Dog(Animal):
    def speak(self):
        print('汪汪汪')


class Pig(Animal):
    def speak(self):
        print('哼哼哼')


c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.speak()
d1.speak()
p1.speak()

其实上述多态的概念,我们之前就已经接触过

l1 = [11,22,33,44]
d1 = {'name':'zhang','age':19,'hobby':'learn'}
t1 = (1,2,3,4,5)
print(len(l1))
print(len(d1))
print(len(t1))

三、了解知识 —— 抽象类

1.指定metaclass属性将类设置为抽象类

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()

image

2.鸭子类型

只要长得像鸭子,走路像鸭子,说话像鸭子,那么它就是鸭子

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():根据字符串给对象删除属性

三、代码演示

1.需求:判断用户提供的名字在不在对象可以使用的范围内

class Student:
    school = '清华大学'

    def choice_course(self):
        print('选课')


stu = Student()

方式一:利用异常处理(过于繁琐)

try:
    if stu.school:
        print(f'True{stu.school}')
except Exception:
    print('没有属性')

方式二:获取用户输入的名字,然后判断该名字的对象有没有

'''
变量名school 与字符串school 看起来区别不大
    stu.school
    stu.'school'
两者虽然只差了引号,但是本质完全不同
'''
while True:
    target_name = input('请输入您的姓名>>>:').strip()
    '''上面的异常更难实现,需要反射'''
    print(hasattr(stu,target_name))
    print(getattr(stu,target_name))
    if hasattr(stu,target_name):
        print(getattr(stu,target_name))
        res = getattr(stu,target_name)
        if callable(res):
            print('拿到的是一个函数名',res())
        else:
            print('拿到的是名字是一个数据',res)
    else:
        print('没在对象里找到这个名字')

2.四个方法试用

print(stu.__dict__)		# {}
stu.name = 'zhang'
stu.age = 19
print(stu.__dict__)		# {'name': 'zhang', 'age': 19}
setattr(stu,'gender','male')
setattr(stu,'hobby','read')
print(stu.__dict__)
# {'name': 'zhang', 'age': 19, 'gender': 'male', 'hobby': 'read'}
del stu.name
print(stu.__dict__)
# {'age': 19, 'gender': 'male', 'hobby': 'read'}
delattr(stu,'age')
print(stu.__dict__)
# {'gender': 'male', 'hobby': 'read'}

四、反射实战案例

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)
                func(file)

    def get(self, file):
        print('Downloading %s...' % file)

    def put(self, file):
        print('Uploading %s...' % file)


obj = FtpServer()
obj.serve_forever()

标签:name,stu,self,特性,面向对象,三大,print,class,def
来源: https://www.cnblogs.com/Zhang614/p/16536899.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有