ICode9

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

py 学习之另外两大特性封装和多态以及反射的内容 day 28

2022-04-08 21:32:36  阅读:137  来源: 互联网

标签:__ .__ name self py 28 多态 print def


今日学习内容

  • 继承下的派生实际应用
  • 面向对象三大特性之封装
  • 面向对象三大特性之多态
  • 反射
  • 双下方法

继承下的派生实际应用

在学习的时候讲到这样的一个例子,还用到了之前学的时间模块内容

import datetime
import json

class MyJsonEncoder(json.JSONEncoder):
    def default(self, o):
        # 这个形参o是即将要被序列化的数据对象 
        '将o处理成json可以序列化的类型'
        if isinstance(o.datetime.datetime):
            return o.strftime('%Y-%m-%d %X')
        elif isinstance(o, datetime.date):
            return o.strftime('%Y-%m-%d')
        return super().default(o)
    # 这里就是调用父类的default
d1 = {'t1': datetime.datetime.today(), 
      't2': datetime.date.today()}
res = json.dumps(d1, cls = MyJsonEncoder)
print(res)
# {"t1": "2022-04-08 21:12:00", "t2": "2022-04-08"}

上述操作重写了default
'''
1.手动将不能序列化的类型先转字符串
{'t1': str(datetime.datetime.today()), 
 't2': str(datetime.date.today())}
2.研究json源码并重写序列化方法
研究源码发现报错的方法叫default
raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)
    我们可以写一个类继承JSONEncoder然后重写default方法
'''

封装

# 通俗理解
	把属性和方法放到类里面的操作可以认为是封装,封装还可以控制属性和方法的访问权限,比如:把方法改成私有的
可以说是将类中的某些名字'隐藏'起来,不让外界直接调用,隐藏的目的是为了提供专门的通道去访问,并且在通道内可以添加额外的功能

# 封装的目的
	封装数据的主要原因是:保护隐私
	封装方法的主要原因是:隔离复杂度(比如:电视机,我们看见的就是一个黑匣子,其实里面有很多电器元件,对于用户来说,我们不需要清楚里面都有些元件,电视机把那些电器元件封装在黑匣子里,提供给用户的只是几个按钮接口,通过按钮就能实现对电视机的操作。)

# 封装的一些操作
在变量名的前面加上两个下划线__
并且封装的功能只在类定义阶段才能生效
__变量名  -->   _类名__变量名
看到上面的这种结构就表示需要通过特定的通道去访问

# 例子
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
        if not isinstance(age,int):
            print('年龄必须是数字')
            return
        self.__name = name
        self.__age = age

stu1 = Student('jason', 18)
stu1.check_info()
stu1.set_info('jasonNB',28)
stu1.check_info()
stu1.set_info('','haha')

特性(property)

property就是将方法伪装成数据
'''
可扩扩展:
	体质指数(BMI)=体重(kg)÷身高^2(m)
'''
有时候很多数据需要经过计算才可以获得 
	但是这些数据给我们的感觉应该属于数据而不是功能
  	BMI指数>>>:应该属于人的数据而不是人的功能
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('jason', 1.83, 77)
# # p1.BMI()  # 22.9
# # print(p1.BMI)
# p2 = Person('eason',1.90,85)
# # p2.BMI()  # 23.5
# # print(p2.BMI)
# p3 = Person('xd',1.85,100)
# # p3.BMI()  # 29.2
# print(p3.BMI)
# p4 = Person('xd',1.5,34)
# # p4.BMI()  # 15.1
# print(p4.BMI)

多态

# 概念
多态:指事物的多种形态
计算机中多态:一个抽象类有多个子类,进行不同的实现,多态依赖于继承
简意:不同的对象调用相同的方法,产生不同的行为 
# 例子
s1 = 'abc'
w1 = [1, 2, 3, 4, 5]
s1.__len__()
w1.__len__()
len(s1)
len(w1)
print(len(s1))  # 3
print(len(w1))  # 5
s1是字符串类型,w1是列表,两个完全不同的对象,他们都可以调用len方法,而得出的结果不同   

如何使用多态

多态在python中,即子类对象调用父类相同的方法时,产生各自的结果
多态依赖于继承,可以用接口继承或者重写父类来实现

# 例子
class H20:
    def __init__(self,name,temerature):
        self.name = name
        self.temerature = temerature
    def turn_ice(self):
        if self.temerature < 0:
            print("[%s]温度太低结冰了"%self.name)
        elif self.temerature > 0 and self.temerature < 100:
            print("[%s]液化成水" % self.name)
        elif self.temerature > 100:
            print("[%s]温度太高变成水蒸气" % self.name)
class Water(H20):
    pass
class Ice(H20):
    pass
class Steam(H20):
    pass
w1 = Water("水",25)
i1 = Ice("冰",-20)
s1 = Steam("水蒸气",3000)
#执行过程中不同的对象调用相同的方法
w1.turn_ice()  # [水]液化成水
i1.turn_ice()  # [冰]温度太低结冰了
s1.turn_ice()  # [水蒸气]温度太高变成水蒸气

#或者定义一个接口来执行上面的调用
def func(obj):
    obj.turn_ice()
func(w1)  # [水]液化成水
func(i1)  # [冰]温度太低结冰了
func(s1)  # [水蒸气]温度太高变成水蒸气


'接口类Animal'
import abc
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
    def talk(self): # 抽象方法中无需实现具体的功能
        pass
class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
    def talk(self):
        pass
p1 = Person() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化

反射

# 什么是反射
	概念:指程序可以访问、检测和修改本身状态或者行为的一种能力
  大白话:其实就是通过字符串来操作对象的数据和功能

# 需掌握的四个方法
  hasattr():判断对象是否含有字符串对应的数据或者功能
  getattr():根据字符串获取对应的变量名或者函数名
  setattr():根据字符串给对象设置键值对(名称空间中的名字)
  delattr():根据字符串删除对象对应的键值对(名称空间中的名字)

    
# 就是以上四种方法在例子中的使用
class Student(object):
    school = '清华大学'
    def get(self):
        print('得到了一个篮球')
# 编写一个小程序 判断Student名称空间中是否含有用户指定的名字 如果有则取出展示
print(Student.__dict__)
guess_name = input('请输入你想要查找的名字>>>:').strip()
# 不使用反射不太容易实现
print(hasattr(Student, 'school'))  # True
print(hasattr(Student, 'get'))  # True
print(hasattr(Student, 'post'))  # False
#
print(getattr(Student, 'school'))  # 清华大学
print(getattr(Student, 'get'))  # <function Student.get at 0x10527a8c8>
while True:
    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,'level','贵族学校')
print(Student.__dict__)
def index():
     pass
obj = Student()
setattr(obj, '血量', 10000)
setattr(obj, '功能', index)
print(obj.__dict__)
delattr(obj, '功能')
print(obj.__dict__)
'就是看到关键词对象和字符串(用户输入、自定义、指定)就是用反射'

反射实例

# 利用反射获取配置文件中的配置信息
"""一切皆对象 文件也是对象"""
import settings
dir(settings)  # 获取对象中所有可以使用的名字
getattr(settings, 'NAME')
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()

今天的学习内容到此结束,接下来去复习前面的知识点了

标签:__,.__,name,self,py,28,多态,print,def
来源: https://www.cnblogs.com/kazz/p/16119848.html

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

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

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

ICode9版权所有