python学习笔记

昨日内容回顾

  • 对象独有方法
对象本身不需要在自己的名称空间中定义方法 因为类中定义的方法默认就是绑定给对象使用的 对象来调用就会将对象当做第一个参数传入
  • 动静态方法
在类体代码中编写的函数有三种类型  
1.直接写函数
	绑定给对象的方法
2.使用@classmethod
	绑定给类的方法
3.使用@staticmethod
	普普通通的函数
  • 继承理论及基本使用
继承的目的是为了提升开发效率 站在巨人的肩膀上编程
继承仅限于类与类之间 也是面向对象三大特性之一
class B:
    pass
1.单继承
class A(B):
    pass
2.多继承
class C(A,B):
    pass
  • 名字的查找顺序
1.不继承的情况下
2.单继承的情况下
3.多继承的情况下
"""
对象在点一个名字的时候查找顺序都是先从
	对象自身查找
	再去产生对象的类中查找
	最后是类的父类中
"""
针对多个父类问题 名字的查找
	深度优先
 	广度优先
 
mro方法 结果是一个列表 展示了名字的查找顺序
	[A,B,C,D,E]
  • 经典类与新式类
新式类继承了object或者其子类的类
经典类不继承object或其子类的类(什么都不继承)
  • 派生方法
子类继承了父类 并且在子类中定义了与父类一样的方法

子类调用父类的方法 super().父类的方法()
	拦截 添加 原路返回

今日内容概要

  • 派生方法的实战演练(重要)
  • 面向对象三大特性之封装
  • property伪装属性
  • 面向对象三大特性之多态
  • 面向对象之反射(重要)
  • 反射实战演练(重要)

今日内容详细

派生方法的实战演练(重要)

import datetime
import json

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

"""
上述代码会报错 无法正常序列化
    raise TypeError(f'Object of type {o.__class__.__name__} '
    TypeError: Object of type datetime is not JSON serializable
json序列化python数据类型是有限制的 不是所有的类型都可以
    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+
ps:即将要被序列化的数据 里里外外都必须是上述类型才可以
"""
  • 解决方式1:手动将不符合数据类型要求的数据转成符合要求的
d = {
    't1': str(datetime.datetime.today()),
    't2': str(datetime.date.today())
}
res = json.dumps(d)
print(res)
  • 解决方式2:利用派生方法
d = {
    't1': datetime.datetime.today(),
    't2': datetime.date.today()
}
# res = json.dumps(d)
"""
class JSONEncoder:
    pass
dumps(obj,cls=None):
    if cls == None:
        cls = JSONEncoder
    return cls(...)   # JSONEncoder()

查看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)

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

面向对象三大特性之封装

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

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

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

  • 1.在类定义阶段使用双下划线开头的名字 都是隐藏的属性
    后续类和对象都无法直接获取
class Person:
    d_type = '人类'
    __school = '清华大学'  # 隐藏


print(obj.__school)  # 无法访问
print(Person.__school)  # 无妨访问
  • 2.在python中不会真正的限制任何代码
    隐藏的属性如果真的需要访问 也可以 只不过需要做变形处理
    __ 变量名 _ 类名 __变量名

ps:既然隐藏了 就不该使用变形之后的名字去访问 这样就失去了隐藏的意义

class Person:
    d_type = '人类'
    __school = '清华大学'  # 隐藏
    
    def get_info(self):
        return f"""
        ++++++++++++++++++++++++++
        姓名:{self.__name}
        年龄:{self.__age}
        学校:{self.__school}
        ++++++++++++++++++++++++++
        """
    
print(obj._Person__school)  # 清华大学 一般不这样做
print(obj.get_info())  # 利用接口获取
输出结果:
++++++++++++++++++++++++++
        姓名:jason
        年龄:18
        性别:清华大学
++++++++++++++++++++++++++


"""
我们编写python很多时候都是大家墨守成规的东西 不需要真正的限制
class A:
	_school = '清华大学'  # 隐藏数据
	def _choice_course(self):  # 隐藏方法
		pass
"""

property伪装属性

可以简单的理解为 将方法伪装成数据

obj.name   # 数据只需要点名字
obj.func()  # 方法至少还要加括号

伪装之后可以将func方法伪装成数据 obj.func

扩展了解

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

Python专门提供了一个装饰器property,可以将类中的函数“伪装成”对象的数据属性,对象在访问该特殊属性时会触发功能的执行,然后将返回值作为本次访问的结果

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('jason', 78, 1.83)
print(p1.BMI)  # 23.291229956104985

"""BMI虽然需要计算获得 但是更像是人的数据"""

使用property有效地保证了属性访问的一致性。另外property还提供设置和删除属性的功能

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) # 触发name.setter装饰器对应的函数name(f,’jason')
obj.name = 666
print(obj.name) # 触发name.setter对应的的函数name(f,123),抛出异常TypeError
del obj.name # 触发name.deleter对应的函数name(f),抛出异常PermissionError

面向对象三大特性之多态

  • 多态:一种事物的多种形态。比如水:液态 气态 固态,动物:人 狗 猫 猪
class Animal(object):
    def spark(self):
        pass
    
class Cat(Animal):
    def spark(self):
        print('喵喵喵')
        
class Dog(Animal):
    def spark(self):
        print('汪汪汪')

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

c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.miao()
d1.wang()
p1.heng()
"""
一种事物有多种形态 但是相同的功能应该有相同的名字
这样的话 以后我无论拿到哪个具体的动物 都不需要管到底是谁 直接调用相同的功能即可
    无论你是鸡 鸭 猫 狗 猪 只要你想叫 你就调固定的叫的功能
"""
c1.spark()
d1.spark()
p1.spark()
  • Python中一切皆对象,本身就支持多态性
l1 = [11, 22, 33, 44]
d1 = {'name': 'jason', 'pwd': 123, 'hobby': 'raed'}
t1 = (11, 22, 33, 44)

# Python内置了一个统一的接口
print(len(l1))
print(len(d1))
print(len(t1))
  • python也提供了一种强制性的操作(了解即可) 应该是自觉遵守
import abc

# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
    def talk(self): # 抽象方法中无需实现具体的功能
        pass

class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
    def talk(self):
        pass

cat=Cat() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化

其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,这正是Python崇尚的“鸭子类型”(duck typing):“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。

操作系统
    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('不好意思 您想要查找的名字 对象没有')
print(stu.__dict__)
stu.name = 'jason'
stu.age = 18
print(stu.__dict__) # 通过对象点的方法

setattr(stu,'gender','male')
setattr(stu,'hobby','read')
print(stu.__dict__) # 通过setattr方法 引号很重要 可以让用户自定义输入数据

del stu.name
print(stu.__dict__) # 直接删除变量名

delattr(stu, 'age')
print(stu.__dict__) # 通过delattr方法 可以让用户自定义输入数据

"""
以后只要在需求中看到了关键字
	....对象....字符串 
那么肯定需要使用反射
"""

反射实战案例

# 用户输入指令触发相应的功能
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()
posted @   空白o  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示