元类

元类的用途:自定义元类控制类的创建行为及类的实例化行为

Python 中一切皆为对象。

一切接对象,对象可以怎么用呢?

1、都可以被引用,x=obj

2、都可以当作函数的参数传入

3、都可以当作函数的返回值

4、都可以当作容器类的元素,l=[func,time,obj,1]

让我们先定义一个类,然后逐步分析

class People:
def __init__(self, name, age):
self.name = name
self.age = age def say(self):
print('%s say welcome to here' % self.name) p = People('ysg', 21)
p.say()
print(type(p)) # <class '__main__.People'>
print(type(People)) # <class 'type'>

所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用类OldboyTeacher得到的

如果一切皆为对象,那么类 Peope 本质也是一个对象,既然所有的对象都是调用类得到的,那么 Peope 必然也是调用了一个类得到的,这个类称为元类

总结:产生类的类称之为元类,默认使用 class 定义的类,他们的元类是 type。

exec的用法

参数1:字符串形式的命令

参数2:全局作用域(字典形式),如果不指定默认就是用 globals()

参数3:局部作用局(字典形式),如果不指定默认就是用 locals()

例子

g = {
'x': 'ysg',
'y': ''
} l = {} exec("""
global x,m
x = 'ysging'
m = 'pei'
z = '21'
""", g, l)
print(g) # {'x': 'ysging', 'y': '123'..., 'm': 'pei'}
print(l) # {'z': '21'}

元类定义的两种方式

方法一:class

class People:
country = "China" def __init__(self, name, age):
self.name = name
self.age = age def func(self):
print('%s say good' % self.name) p = People('ysg', '')
print(People) # <class '__main__.People'>
print(p, p.name, p.age) # <__main__.People object at 0x0000020B0FC652E8> ysg 22

方法二:type

定义类的三要素:类名、类的基类、类的名称空间

class_name = 'People'
class_bases = (object,)
class_body = """
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age def func(self):
print('%s say good' % self.name)
"""
class_dic = {}
exec(class_body, globals(), class_dic)
People1 = type(class_name, class_bases, class_dic)
print(People1) # <class '__main__.People'>
p1 = People1('ysg', '')
print(p1, p1.name, p1.age) # <__main__.People object at 0x0000020B0FC65470> ysg 22

自定义元类控制类的创建行为

实现检索类名称是否为大写,类中是否写入注释

class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
if not class_name.istitle():
raise TypeError('类名称首字母要求大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('新建的类必须标有注释') class People(object, metaclass=Mymeta): # People = Mymeta(class_name,class_bases,class_dic)
'''
使用自定义元类控制类的创建行为
'''
country = "China" def __init__(self, name, age):
self.name = name
self.age = age def func(self):
print('%s say good' % self.name)

自定义元类控制类的实例化行为

预备知识 __call__

class Foo:
pass f = Foo()
f() # TypeError: 'Foo' object is not callable
class Foo:
def __call__(self, *args, **kwargs):
print(self)
print(args)
print(kwargs) f = Foo()
f(1, 2, 3, a=1, b=2, c=3) 结果:
<__main__.Foo object at 0x000001DBE6B7F240>
(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}

由以上两个例子可以看出,在调用方式实际是自动调用了 __call__ 方法

所以可以得出,在使用元类控制类的实例化行为时:

  元类内部也应该有一个 __call__ 方法,会在调用 Foo 时触发执行;Foo(1,2,x=1) 就相当于 Foo.__call__(Foo,1,2,x=1)

例子:自定义元类控制类实现单实例

预备知识:单实例

单实例:对象内部特征如果一样的情况下,就不要产生新的内存空间,实现共用一个空间。

非单实例:

class Mysql:
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306 m = Mysql()
m1 = Mysql()
print(m) # <__main__.Mysql object at 0x000001517C67F278>
print(m1) # <__main__.Mysql object at 0x000001517C67F390>

方法一:绑定方法实现单实例

class Mysql:
__singleins = None def __init__(self):
self.host = '127.0.0.1'
self.port = 3306 @classmethod
def si(cls):
if not cls.__singleins:
obj = cls()
cls.__singleins = obj
return cls.__singleins m = Mysql.si()
m1 = Mysql.si()
print(m) # <__main__.Mysql object at 0x000001F1ECEC5278>
print(m1) # <__main__.Mysql object at 0x000001F1ECEC5278>

方法二:元类实现单实例

class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
self.__singleins = None def __call__(self, *args, **kwargs):
if not self.__singleins:
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
self.__singleins = obj
return self.__singleins class Mysql(object, metaclass=Mymeta):
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306 m = Mysql()
m1 = Mysql()
print(m) # <__main__.Mysql object at 0x00000278E56552B0>
print(m1) # <__main__.Mysql object at 0x00000278E56552B0>

异常处理

什么是异常:异常是错误发生的信号,一旦程序出错,并且程序没有处理这个错误,就会抛出异常,并且程序的运行随之终止

  强调一:异常发生的条件如果是可预知的,此时应该用 if 判断预防异常

  强调二:异常发生的条件如果是不可预知的,此时应该使用异常处理机制,try...except

错误分为两种:语法错误、逻辑错误

例子:指定要预防的报错类型

a = 'qwe'
try:
int(a)
except ImportError:
print('int 类型报错') 结果:ValueError: invalid literal for int() with base 10: 'qwe'

注意:当指定的类型和实际报错的类型不一致时,报错不会被预防,而是报出真实的报错信息

a = 'qwe'
try:
int(a)
except ValueError:
print('int 类型报错') # int 类型报错 print('拦截报错信息后的输出') # 拦截报错信息后的输出

当类型一致时,会拦截报错,并执行下面的语句,不会打断程序的运行

例子:异常的多分支

用途:被检测的代码块存在抛出多种异常的可能性,即为每种异常指定单独的处理逻辑

try:
print('=====>1')
a = 'qwe'
int(a)
print('=====>2')
l = [1,2,3]
l[100]
print('=====>3')
d = {}
d['name']
print('=====>')
except ValueError as e:
print('----->',e) # -----> invalid literal for int() with base 10: 'qwe'
except IndexError as e:
print('----->', e) # -----> list index out of range
except KeyError as e:
print('----->', e) # -----> 'name' print('被检测代码块的代码') # 被检测代码块的代码

例子:万能异常处理——Exception

用途:被检测的代码块存在抛出多种异常的可能性,且我们只为其设置一种处理逻辑

try:
print('=====>1')
a = 'qwe'
int(a)
print('=====>2')
l = [1,2,3]
l[100]
print('=====>3')
d = {}
d['name']
print('=====>')
except Exception as e:
print('统一的处理方法----->', e) # -----> invalid literal for int() with base 10: 'qwe' print('被检测代码块的代码') # 被检测代码块的代码

例子:else、finally

try:
print('=====>1')
a = 'qwe'
# int(a)
print('=====>2')
l = [1,2,3]
# l[100]
print('=====>3')
d = {}
# d['name']
print('=====>')
except Exception as e:
print('----->', e)
else:
print('被检测代码块没有发生异常时执行') # 被检测代码块没有发生异常时执行
finally:
print('不管被检测代码块没有发生异常时执行都执行') # 无论被检测代码块是否发生异常时都执行

finally 在回收资源时的运用

不论是否发生异常都执行回收操作

try:
f = open('../test.txt', 'r', encoding='utf-8')
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
finally:
f.close()

 例子:主动触发异常——raise,异常类型(值)

class Foo:
def __init__(self,name,age):
if not isinstance(name,str):
raise TypeError('名称必须要使用 str 类型')
self.name = name
self.age = age f = Foo(123,12)

例子:自定义异常类型

class MyException(Exception):
def __init__(self, msg):
super(MyException, self).__init__()
self.msg = msg def __str__(self):
return self.msg raise MyException('自定义异常类') # raise 包含 print(obj)
结果:__main__.MyException: 自定义异常类

例子:断言——assert

info = {}
info['name'] = 'ysg'
# info['age'] = 22 # 这一部分的判断 就叫做断言
# if 'name' not in info:
# raise KeyError('name 的 key 不存在')
# if 'age' not in info:
# raise KeyError('age 的 key 不存在') # 使用 assert
assert ('name' in info) and ('age' in info) # AssertionError if info['name'] == 'ysg' and info['age'] > 10:
print('welcome')

day 28-1 元类的更多相关文章

  1. 【python进阶】详解元类及其应用2

    前言 在上一篇文章[python进阶]详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有 ...

  2. Python进阶开发之元类编程

    系列文章 √第一章 元类编程,已完成 ; 本文目录 类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战:ORM . 类是如何产生的 类是如何产生?这个问题肯定很傻.实则不然,很多 ...

  3. 神级程序员通过两句话带你完全掌握Python最难知识点——元类!

    千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为 每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生 ...

  4. Python中的元类

    从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象. class C(object): pass c = C() prin ...

  5. iOS中类、元类、isa详解

    类相信大家都知道是什么,如果看过runtime的源码或者看过相关的文章对isa肯定也不陌生,不过元类(meta class)大家可能就比较陌生了.不过大家也不要担心,我会细细道来,让大家明白它到底是个 ...

  6. 元类应用ORM实现

    首先看下一个简单的例子 # 需求 import numbers class Field: pass class IntField(Field): # 数据描述符 def __init__(self, ...

  7. gj8 元类编程

    8.1 property动态属性 from datetime import date, datetime class User: def __init__(self, name, birthday): ...

  8. python概念-其实只要简单了解一下,但是却讲了将近两个小时的知识点:元类

    说实话,我真心不太想总结这个东西,算了,炒一下egon的吧 1 引子 1 class Foo: 2 pass 3 4 f1=Foo() #f1是通过Foo类实例化的对象 python中一切皆是对象,类 ...

  9. python面向对象(六)之元类

    元类 1. 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: In [13]: class ObjectCreator(object): . ...

  10. Django中的元类-乾颐堂

    看Django(1.6)的Form相关源代码时比较迷惑,于是节选了django.forms.forms.py中的几个代码片段来分析Django中是怎么使用元类的: 1 2 3 4 5 6 7 8 9 ...

随机推荐

  1. SpringBoot时间参数处理完整解决方案

    在JavaWeb程序的开发过程中,接口是前后端对接的主要窗口,而接口参数的接收有时候是一个令人头疼的事情,这其中最困扰程序猿的,应该是时间参数的接收. 比如:设置一个用户的过期时间,前端到底以什么格式 ...

  2. sqlserver2008 R2 安装以后没有 sql server profiler

    一些人在安装好SQL server 2008 r2或者从empress升级到enterprise或者开发版之后没有SQL server profiler功能,如果需要加装则应该找到自己的安装文件(部分 ...

  3. 【10分钟学Spring】:(一)初识Spring框架

    简介 Spring是一个轻量级的企业级的Java开发框架.主要是用来替代原来更加重量级的企业级Java技术,比如EJB(Enterprise JavaBean).Java数据对象(Java Data ...

  4. CSRF(Cross-site request forgery)跨站请求伪造

    CSRF是什么 CSRF(Cross-site request forgery)跨站请求伪造,也被称为"One Click Attack"或者Session Riding,通常缩写 ...

  5. pikachu 暴力破解

    一 暴力破解 1.基于表单的暴力破解 先随意测试root/root登录,用Burp抓包,丢进Intruder 添加username和password两个参数变量,攻击类型选择Clusterbomb 有 ...

  6. SpringBoot 发送邮件功能实现

    背景 有个小伙伴问我你以前发邮件功能怎么弄的.然后我就给他找了个demo,正好在此也写一下,分享给大家. 理清痛点 发送邮件,大家可以想一下,坑的地方在哪? 我觉得是三个吧. 第一:邮件白名单问题. ...

  7. Tomcat下载安装并部署到IDEA(附带idea两种热部署设置方法)

    目录 Tomcat下载教程 Tomcat安装教程 Tomcat热部署到IDEA idea两种热部署设置方法 使用Idea的时候,修改了代码,需要反复的重启Tomcat,查看效果,是不是贼烦?还记得刚上 ...

  8. Mybatis动态查询

    需要导入的jar包: 实体类User: package com.bjsxt.pojo; import java.io.Serializable; public class User implement ...

  9. [TimLinux] JavaScript AJAX如何重定向页面

    1. AJAX 异步JavaScript + XML,用于不通过页面from表单,来发送数据到后端服务器中 2. 如何重定向 服务器后端无法直接将页面重定向,因为服务器后端传回的任何数据,都将被XML ...

  10. HDU 6405 Make ZYB Happy(广义SAM)

    It's known to all that ZYB is godlike, so obviously he has a large number of titles, such as jskingj ...