python 面向对象(高级篇) !

为了增加程序的友好性,一般在程序报错的时候不会将错误直接返回用户,而是封装好一个提示页面给用户

最简单的结构
    try:
        # 代码块 逻辑
        pass
    except Exception as e:
        # e是Exception的对象,对象中封装了错误信息
        # 上述代码块出错,执行当前块的内容
        pass
断言
    assert 条件   # 不满足条件直接报错,想使用程序必须报错,强制用户服从,不服从就报错
a = 2
assert a == 1
# try语句格式
try:
    # 执行业务代码
    # a = [1,2,3]
    # a[4]
    pass
except IndexError as e:
    print('我们知道报错的错误类型: IndexError',e)
    print("捕捉报错的错误类型, 可以进行精准的错误处理")
    print("比如这里, 可能是超出了列表的索引, 就可以提示用户重新输入或者处理列表")
except ValueError as e:
    print('我们知道报错的错误类型: ValueError',e)
except Exception as e:
    print('并不知道报错的类型: Exception',e)
else:
    #  try 代码块没报错才会执行这里的业务逻辑
    print('try中的代码没出错执行这里')
finally:
    # 可有可无, 无论 try 代码块是否报错都会执行这里
    print('最后一定会执行这里')
try:
    # 有时候程序没出错, 但是我们捕获到了用户的一些异常操作
    # 自定义报错信息
    raise Exception('心情不好,主动触发异常')
except Exception as e:
    print(e)

# 需求: 打开文件并输出内容

# 示例Python学习群:683380553,有大牛答疑,有资源共享!是一个非常不错的交流基地!欢迎喜欢Python的小伙伴!

try:
   with open('a.txt', "r", encoding="utf8") as f:
      print(f.read())
except FileNotFoundError  as e:
    print("文件不存在, 将自动创建空白文件并输入: hello world")
    with open('a.txt', "w", encoding="utf8") as f:
        f.writelines("hello world")

常用异常

AttributeError 试图访问一个对象没有的属性,
比如foo.x,但是foo没有属性x
IOError 输入/输出异常;常见为无法打开文件
ImportError 无法引入模块或包;常见为路径问
题或名称错误
IndentationError 语法错误(的子类) ;代码
没有正确对齐
IndexError 下标索引超出序列边界,比如当x只
有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译
(个人认为这是语法错误, 写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置
的局部变量,基本上是由于另有一个同名的全局
变量, 导致你以为你正在访问它
ValueError 传入一个调用者不期望的值,即使
值的类型是正确的

反射

什么是反射: 通过字符串映射object对象的方法或属性

  • hasattr(obj, name_str): 判断objec是否有name_str这个方法或者属性
  • getattr(obj, name_str): 获取object对象中与name_str同名的方法或者函数 
  • setattr(obj, name_str, value): 为object对象设置一个以name_str为名的value方法或者属性 
  • delattr(obj, name_str): 删除object对象中的name_str方法或者属性

方法的简介绍

class F006:
    static_foo = '公有静态字段'
    __static_foo = '私有静态字段'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        print(self.name)
    def __show(self):
        print(self.name)
obj = F006('nathaniel',20)
# 检查是否含有某成员
ret = hasattr(obj,'static_foo')
print(ret)
ret = hasattr(obj,'__static_foo')
print(ret)
ret = hasattr(obj,'__init__')
print(ret)
ret = hasattr(obj,'show')
print(ret)
ret = hasattr(obj,'__show')
print(ret)
# 从对象中获取成员
ret = getattr(obj,'static_foo')
print(ret)
# ret = getattr(obj,'__static_foo')
# print(ret)
ret = getattr(obj,'__init__')
print(ret)
ret = getattr(obj,'show')
print(ret)
# ret = getattr(obj,'__show')
# print(ret)
# 设置对象中的成员
setattr(obj,'show',lambda x:print(x))
obj.show('233')
setattr(obj,'static_foo',999)
print(obj.static_foo)
setattr(obj,'new_num',888)
print(obj.new_num)
# 删除对象中的成员
delattr(obj,'name')
print(obj.name) # >> 报错 AttributeError: 'F006' object has no attribute 'name'

python的反射,它的核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,是一种基于字符串的事件驱动!!!

举个栗子 >> 一个web页面,需要根据用户输入的URL不同,调用不同的函数,实现不同的操作,也就是一个简单的路由,这在web框架里是核心部件之一

你可能会这样写

# web框架实例之普通青年版
class Web0:
    def __init__(self,name):
        self.name = name
    def home_page(self):
        print('%s进入了首页'% self.name)
    def login_page(self):
        print('%s进入了登录页'% self.name)
    def logout_page(self):
        print('%s进入了退出页'% self.name)
    def news_page(self):
        print('%s进入了新闻页'% self.name)
obj = Web0('Nathaniel')
inp = ''
while inp != 'q' and inp != 'Q':
    inp = input('请输入需要查看的url>>>')
    if inp == 'home_page':
        obj.home_page()
    elif inp == 'login_page':
        obj.login_page()
    elif inp == 'logout_page':
        obj.logout_page()
    elif inp == 'news_page':
        obj.news_page()
    else:
        if inp != 'q' and inp != 'Q':
            print('404')

有毛病嘛?没毛病.然而,我们考虑一个问题,如果有成百上千个URL呢(这很正常)?难道我们手动去写成百上千条if语句?显然不现实,呐,反射就来了>>我们对上述代码进行如下优化

# web框架实例之装逼青年版
class Web1:
    def __init__(self,name):
        self.name = name
    def home_page(self):
        print('%s进入了首页'% self.name)
    def login_page(self):
        print('%s进入了登录页'% self.name)
    def logout_page(self):
        print('%s进入了退出页'% self.name)
    def news_page(self):
        print('%s进入了新闻页'% self.name)
obj = Web1('Nathaniel')
inp = ''
while inp != 'q' and inp != 'Q':
    inp = input('请输入需要查看的url>>>')
    if hasattr(obj,inp):
        getattr(obj,inp)()
    else:
        if inp != 'q' and inp != 'Q':
            print('404')

单例模式

单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中应用该模式的类一个类只有一个实例,即一个类只有一个对象实例

举个栗子,某服务器程序的配置信息存放在一个文件当中,客户端通过一个AppConfig的类来读取配置文件的信息.如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,严重浪费内存资源,尤其是在配置文件内容很多的情况下.事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象

使用模块实现单例模式

python模块天然就是单例模式,当模块第一次被导入时会生成一个.pyc文件,第二次导入该模块就会直接执行.pyc文件而不会再次执行模块里的代码,因此我们可以把需要的函数和数据都定义在一个模块当中,这样就可以保证每次使用的都是同一个对象了

# 使用模块实现单例模式
class Foo7:
    def __init__(self):
        pass
    def foo0(self):
        pass
obj = Foo7()
# 将上面的代码保存在文件 xxx.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象
from xxx.py import obj
print(id(
obj))

使用装饰器实现单例模式

# 使用装饰器实现单例模式
def make_singleton(cls):
    _instance = {}
    def _singleton(*args, **kwargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)
        return _instance[cls]
    return _singleton
@make_singleton
class Foo8:
    pass
obj0 = Foo8()
obj1 = Foo8()
obj2 = Foo8()
obj3 = Foo8()
print(obj0)
print(obj1)
print(obj2)
print(obj3)
我们发现,无论用Foo8创建多少实例对象,他们所使用的都是同一个内存地址
使用类实现单例模式
# 使用类实现单例模式
class Singleton(object):
    def __init__(self):
        pass
    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            cls._instance = Singleton(*args, **kwargs)
        return cls._instance
obj0 = Singleton.instance()
obj1 = Singleton.instance()
obj2 = Singleton.instance()
obj3 = Singleton.instance()
print(obj0)
print(obj1)
print(obj2)
print(obj3)

这种方式实现的单例模式,使用时会有限制,以后实例化必须通过 obj = Singleton.instance() , 如果用 obj=Singleton() ,这种方式得到的不是单例

 使用__new__方法实现(推荐使用,方便)

我们知道,当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式

# 使用__new__方法实现(推荐使用,方便)
class Singleton(object):
    def __init__(self):
        pass
    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            if not hasattr(Singleton, "_instance"):
                Singleton._instance = object.__new__(cls)
        return Singleton._instance
obj0 = Singleton()
obj1 = Singleton()
obj2 = Singleton()
obj3 = Singleton()
print(obj0)
print(obj1)
print(obj2)
print(obj3)

简单粗暴的说,就是一个类无论你实例化多少次,它的对象始终都是一个内存地址

猜你喜欢

转载自blog.csdn.net/qq_42156420/article/details/88973092
今日推荐