元类

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

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. 使用IDEA创建SpringMVC项目

    作为一名从.NET转Java的小渣渣,之前都是听说Java配置复杂,今天算是见识到了.甚是怀念宇宙第一IDE VS和.NET高效的开发. 网上大多教程是基于Eclipse的,即使按照IDEA的教程做, ...

  2. 侠梦说pinpoint--左侧服务地图调用量和WasOn过滤

    前言 这篇文章主要是从pinpoint-web界面入手,我们的目标是弄清楚两个问题: 1. pinpoint左侧服务地图上的调用量数据是怎么查询的? 2.界面查询条件WasOnly是什么意思? 左侧服 ...

  3. Nginx+MySQL+PHP+Redis多机部署(测试发布discuz论坛)

    链接:LNMP+Redis单机部署 1.实战多机部署环境 nginx服务器: 192.168.1.3 php服务器:    192.168.1.4 mysql服务器: 192.168.1.10 red ...

  4. .Net core-邮件发送(同步,异步)底层代码(欢迎留言讨论)

    using MailKit.Net.Smtp;using MimeKit;using System;using System.Collections.Generic;using System.IO;u ...

  5. shell 往文件中添加一列一样的字符串

    例如:往文件file.txt中,添加一列字符串"20161020", 用制表符分割 awk '$0=$0"\t20161020"' file.txt

  6. Java 从入门到进阶之路(十二)

    在之前的文章我们介绍了一下 Java 类的重写及与重载的区别,本章我们来看一下 Java 类的 private,static,final. 我们在之前引入 Java 类概念的时候是通过商场收银台来引入 ...

  7. POJ3111

    Demy has n jewels. Each of her jewels has some value vi and weight wi. Since her husband John got br ...

  8. ZOJ 3195 Design the city (LCA 模板题)

    Cerror is the mayor of city HangZhou. As you may know, the traffic system of this city is so terribl ...

  9. HDU-1027Ignatius and princess II

    Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about ...

  10. ARTS-S golang常用代码段

    通过http下载文件 func DownloadFile(filepath string, url string) error { out, err := os.Create(filepath) if ...