当前位置: 首页 > news >正文

Python Day29

元类:

元类是什么:在python中一切皆对象。类也是对象,可以把一个类当成普通对象来使用,比如

存储到列表中,或者作为参数传给函数等等。。。

对象是通过类实例化产生的

类对象 是由type实例化产生的 (记住)

class AClass:

  pass

print(type(AClass))

我们可以手动调用type来实例化产生一个类

一个类由三个部分组成:类的名称(我是谁)  |  类的父类们(我从哪里来)  | 类的名称空间(我有什么)

type(类名,父类元祖,名称空间字典) #返回一个新的类

type(对象)会返回这个对象的类型

总结:当你定义一个类时,解释器会自动调用type来完成类的实例化。

模拟解释器创建类对象

def test1(a):
print(a)

def test2(self,b):
print(self,b)

class_name = "C"
bases = (object,)
name_dict = {"name":"jack","test1":test1,"test2":test2}

C = type(class_name,bases,name_dict)
# print(C)
c1 = C()
# print(c1)
c1.test2(100)

补充:exec,eval

exec用于执行字符串形式的python代码,只要符合python都能执行,并且可以指定将执行产生的名字放入某个名称空间。

eval 用于执行简单的表达式,不能有任何的语法,而且只能一行。

class_text = """
class A:
def test(self):
print(self)
"""
loca2 = {}
exec(class_text,None,loca2)
print(loca2)
#eval(class_text) #报错

所以说元类就是用于产生类的类。

元类翻译成metaclass,只要看见它将应该想起来这是元类。

我们在定义元类时,尽量在类名后添加MetaClass 方便阅读

用来干啥:

当我们需要高度定制类时,如限制类名必须大写开头等等,就需要使用元类,但是元类type中的代码,无法被修改,只能创建新的元类(继承自object)通过覆盖__init__来完成对类的限制。

使用元类

如何自定义元类:

class MyMetaClass(type):
pass

# 使用自定义元类
class Person(metaclass=MyMetaClass):
pass

__init__方法(重点):

实例化对象时会自动执行类中的__inti__方法,类也是对象,在实例化类对象时会自动执行元类中的__init__方法。并且传入类的三个必要参数,类的名字,父类们,名称空间

当然会自动传入类对象本身作为第一个参数

 

案例:限制类名必须首字母大写,控制类中方法名必须全部小写

class MyMetaClass(type):
def __init__(self,class_name,bases,name_dict):

super().__init__(class_name,bases,name_dict)
# 类名必须首字母大写 否则直接抛出异常
if not class_name.istitle():
print("类名必须大写 傻x!")
raise Exception

# 控制类中方法名必须全部小写
for k in name_dict:
if str(type(name_dict[k])) == "<class 'function'>":
if not k.islower():
raise Exception
pass

# 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们 名称空间
class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{})
NAME = 10
def say(self):
print("SAY")

__new__方法:

元类中的new方法会在创建类对象时执行,并且先于init方法

作用是创建一个类对象

class A(metaclass=MyMetaClass):

pass

1.执行MyMetaClass的__new__方法 拿到一个类对象

2.执行MyMetaClass的__init__ 方法 传入类对象以及其他的属性 ,进行初始化

 注意:如果覆盖了__new__一定也要调用type中的__new__并返回执行结果

使用__new__方法也可以完成定制类的工作和__init__有什么区别吗?

在调用__init__方法前类对象已经创建完成了。所以如果对性能要求高的话,可以选择在new中完成定制,如果发现有问题,就不用创建类对象了。

需求:要求每个类必须包含__doc__属性

class DocMeatClass(type):

def __init__(self,class_name,bases,name_dict):
super().__init__(class_name,bases,name_dict)
# if not("__doc__" in name_dict and name_dict["__doc__"]):
# raise Exception

# 或者如下
if not self.__doc__:
raise Exception

class Person(metaclass=DocMeatClass):
""""""
pass

 

 

# 需求: 要求每个类必须包含__doc__属性 __doc__ 用于访问一个对象的注释信息


# 你要控制类的创建 那就自定义元类 覆盖__init__
class DocMeatClass(type):

def __init__(self,class_name,bases,name_dict):
super().__init__(class_name,bases,name_dict)
# if not("__doc__" in name_dict and name_dict["__doc__"]):
# raise Exception
if not self.__doc__:
raise Exception

class Person(metaclass=DocMeatClass):
pass

__call__方法(重点)

元类中的call方法会在调用类时执行。

可以用于控制对象的创建过程

class MyMeta(type):

# 获得某个类的实例
def __call__(self, *args, **kwargs):
print("call")
# return super().__call__(*args,**kwargs)
new_args = []
for i in args:
if isinstance(i,str):
new_args.append(i.upper())
else:
new_args.append(i)
return super().__call__(*new_args,**kwargs)

 

# 注意注意注意: __new__ __init__ 是创建类对象时还会执行
# __call__ 类对象要产生实例时执行

class Student(metaclass=MyMeta):
def __init__(self,name,gender,age):
self.name = name
self.gender = gender
self.age = age

s = Student("jack","woman",18)
print(s.age)
print(s.gender)


class Person(metaclass=MyMeta):
def __init__(self,name,gender):
self.name = name
self.gender = gender

p = Person("rose","man")
print(p.name)

总结:当你要定制类时,就自定义元类并覆盖init方法

元类实现单例模式

什么是单例:某个类如果只有一个实例对象,那么该类称为单例类

单例的好处:当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源

案例:

class SingletonMetaClass(type):
#创建类时会执init 在这为每个类设置一个obj属性 默认为None
def __init__(self,a,b,c):
super().__init__(a,b,c)
self.obj = None

# 当类要创建对象时会执行 该方法
def __call__(self, *args, **kwargs):
# 判断这个类 如果已经有实例了就直接返回 从而实现单例
if self.obj:
return self.obj

# 没有则创建新的实例并保存到类中
obj = type.__call__(self,*args,**kwargs)
self.obj = obj
return obj

异常:

什么是异常:异常是程序运行过程中发生的非正常情况,是一个错误发生时的信号,异常如果没有被正确处理的话,将导致程序被终止,这对于用户体验是非常差的,可能导致严重的后果。处理异常的目的就是提高程序的健壮性

异常的分类:

python解释器在执行代码前会先检查其语法,语法通过才会开始执行代码。

1.语法检测异常,作为一个合格的程序员,是不应该出现这种低级错误

2.运行时异常:已经通过语法检测时,才会执行代码,执行过程中发生异常,称之为运行时异常

看见的异常:

 TypeError: 'int' object is not subscriptable 对象不能被切片 

TypeError: 'list' object is not callable 对象不能被调用
IndexError: list index out of range 索引超出范围
TypeError: 'builtin_function_or_method' object is not iterable 对象不能被迭代
KeyError: 'xxx' 不存在这个key
FileNotFoundError: [Errno 2] No such file or directory: 'xxxxx' 文件找不到

 

异常的组成:

Traceback (most recent call last):
File "F:/python8期/课堂内容/day29/11.常见异常.py", line 22, in <module>
with open("xxxxx") as f:
FileNotFoundError: [Errno 2] No such file or directory: 'xxxxx'




Traceback 是异常追踪信息 用于展示错误发生的具体位置 以及调用的过程
其中 包括了 错误发生的模块 文件路径 行号 函数名称 具体的代码

最后一行 前面是错误的类型
后面 错误的详细信息 在查找错误时 主要参考的就是详细信息

异常处理:

异常发生后,如果不正确处理将导致程序终止,我们必须应该尽量的避免这种情况发生

重点:

必须掌握的语法

语法:

try:

  可能会出现异常的代码 放到try里面

except 具体异常类型 as e:

  如果真的发生异常就执行except

如何正确处理异常:

  1. 当发生异常 不是立马加try 要先找出错误原因并解决它

  2. try 仅在 即使你知道为什么发生错误 ,但是你却无法避免 例如 你明确告诉用户 需要一个正确文件路径 然而用户依然传入了错误的路径

    如 socket 双方都要使用管道 ,但是如果一方有由于某些原因强行关闭了 ,即使你知道原因也无法避免出错 那就只能try 保证程序正常结束

    总结一句话:能不加try 就不加try

 

自定义异常类:

当系统提供异常类不能准确描述错误原因时,就可以自定义异常类继承自Execption即可

class MyException(Exception):
pass

主动抛出异常:

什么时候需要主动抛出异常

当我们做功能的提供者,给外界提供一个功能接口

但是使用者不按照相应的方式来使用,或者参数类型不正确等原因,导致功能无法正常执行时,就应该主动抛出异常

主动抛出异常使用raise 关键字

后面可以跟任何Exception的子类 或是 对象

raise MyException
raise MyException("错误具体原因!")

断言assert

断言 其实可以理解为断定的意思

即非常肯定某个条件是成立的

条件是否成立其实可以使用if来判断

其存在的目的就是 为了简化if 判断而生的

 

 

转载于:https://www.cnblogs.com/xinfan1/p/10920014.html

相关文章:

  • java socket之多人聊天室Demo
  • NCRE考试感想 四级嵌入式(下)
  • ps调整图层
  • 使用zabbix系统批量监控Url返回码
  • 1 weekend110的hdfs源码跟踪之打开输入流 + hdfs源码跟踪之打开输入流总结
  • 支持手机版微信分享显示帖子标题+缩略图+简介】的分享奖励积分插件
  • springMvc源码学习之:spirngMvc的参数注入的问题
  • Rocket - util - LanePositionedQueue
  • URL中带加号的处理
  • XML操作
  • 制作支持UEFI PC的Server2008 R2系统安装U盘
  • c++ 中 毫秒级时间获取
  • golang使用oracle碰到go/lib/time/zoneinfo.zip: no such file or directory
  • Introduction to Machine Learning
  • Windows Server 2012 R2上安装.Net4.6.1出错
  • #Java异常处理
  • 《深入 React 技术栈》
  • CEF与代理
  • Docker 笔记(2):Dockerfile
  • Druid 在有赞的实践
  • ES2017异步函数现已正式可用
  • Gradle 5.0 正式版发布
  • interface和setter,getter
  • React16时代,该用什么姿势写 React ?
  • Redis字符串类型内部编码剖析
  • ------- 计算机网络基础
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 手写双向链表LinkedList的几个常用功能
  • 算法-图和图算法
  • #define
  • #Ubuntu(修改root信息)
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • (33)STM32——485实验笔记
  • (Forward) Music Player: From UI Proposal to Code
  • (k8s中)docker netty OOM问题记录
  • (层次遍历)104. 二叉树的最大深度
  • (超详细)语音信号处理之特征提取
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (五)网络优化与超参数选择--九五小庞
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)可以带来幸福的一本书
  • (转载)从 Java 代码到 Java 堆
  • .NET CLR基本术语
  • .NET企业级应用架构设计系列之结尾篇
  • .NET序列化 serializable,反序列化
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示
  • /bin/rm: 参数列表过长"的解决办法
  • /etc/skel 目录作用
  • :O)修改linux硬件时间
  • [.net]官方水晶报表的使用以演示下载
  • []Telit UC864E 拨号上网
  • [AutoSar]工程中的cpuload陷阱(三)测试