[TOC]
## 知识储备
### 1.exec函数
* exec:三个参数
参数一:字符串形式的命令
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
* **exec的使用**
可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
~~~
g={'x':1,'y':2}
l={}
exec('''
global x,z
x=100
z=200
m=300''',g,l)
print(g) #输出:{'x': 100, 'y': 2,......,'z':200}
print(l) #输出:{'m': 300}
~~~
### 2.一切皆对象
python中一切皆是对象,具体来说对象都有这四个特征,也可以说有这四个特征的都是对象
1. 都可以被引用,x=obj
2. 都可以当作函数的参数传入
3. 都可以当作函数的返回值
4. 都可以当作容器类的元素,如`l=[func,time,obj,1]`
既然一切皆是对象,那类本身也是一个对象,那类又是由哪个类产生的呢?
~~~
class Foo:
pass
obj=Foo()
#type函数可以查看类型,也可以用来查看对象的类,二者是一样的
print(type(obj)) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建
print(type(Foo)) # 输出:<type 'type'> 表示Foo对象有tupe类创建
~~~
### 3.type的语法
语法:`type(name, bases, dict)`,如:`type('Foo',(object,),{})`
type 接收三个参数:
* 第 1 个参数Foo是字符串,表示类名
* 第 2 个参数是元组 (object, ),表示所有的父类
* 第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
## 元类的知识
### 什么是元类?
产生类的类称之为元类,默认所有用class定义的类,他们的元类是type
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
### 创建类方式1:使用class
~~~
class Chinese(object):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
~~~
### 创建类方式2:使用type
使用type模拟class创建类的过程,需要就是把class建类的步骤拆分开,手动去创建
* 准备工作:
定义类的三要素:类名,类的基类,类的名称空间(类体-->exec)
类的名称空间需要通过exec执行类体方法获取
* 定义类名,基类,类体
~~~
class_name='Chinese' #类名
class_bases=(object,) #类的基类
#类体
class_body="""
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
"""
~~~
* 获取类的名称空间
类体定义的名字都会存放于类的名称空间中,我们可以事先定义一个空字典,然后用exec去执行类体的代码,生成类的局部名称空间,即填充字典
~~~
class_dic={}
exec(class_body,globals(),class_dic)
print(class_dic) #输出: {'country': 'China',......}
~~~
* 调用元类type来产生类Chinense
~~~
Chinese1=type(class_name,class_bases,class_dic)
obj1=Chinese1('noah',18)
print(obj1,obj1.name,obj1.age)
~~~
## 自定义元类控制类的行为
通过自定义的元类,可以做到控制类的创建,控制类的实例化,基于元类实现单例模式等,下面分别演示这三个功能
### 1.控制类的创建行为
我们对类的创建做两个行为控制,第一个是类名首字母必须大写,第二个是必须写注释
>关于注释的说明:我们创建类的时候,如果有写备注的话,类的名称空间中就会有`__dic__`熟悉,可以通过判断这一熟悉是否存在并是否为空来判断是否有些注释
~~~
#1.基于type自定义一个元类Mymeta
class Mymeta(type): # 继承默认元类的一堆属性
def __init__(self, class_name, class_bases, class_dic):
if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():
raise TypeError('必须为类指定文档注释')
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
#通过super直接继承type父类的初始化方法
#2. 基于Mymeta创建一个类people
class People(object, metaclass=Mymeta):
'''
类的备注信息,不写就要报错
'''
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
~~~
### 2.控制类的实例化行为
1. 储备知识:`__call__`方法
在类的内置方法那里学过call方法,用途是将让对象可以再次被调用,而类之所以能被调用,就说明:
元类内部也应有有一个`__call__`方法,会在调用类的时触被执行
* 元类中的call方法需要完成三件事:
1:先造一个空对象obj
2:初始化对象obj
3:返回对象obj
2. 创建一个可控制实例化的元类
```
# A.创建包含call方法的元类Mymeta
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs): #obj=Chinese('egon',age=18)
#1:先造一个空对象obj
obj=object.__new__(self)
#2:初始化obj
self.__init__(obj,*args,**kwargs)
#3:返回obj
return obj
#B. 基于Mymeta创建一个类Chinese
class Chinese(object,metaclass=Mymeta):
country='China'
def __init__(self,namem,age):
self.name=namem
self.age=age
def talk(self):
print('%s is talking' %self.name)
#C.实例化对象obj
obj=Chinese('noah',age=18) #等于:Chinese.__call__(Chinese,'egon',18)
print(obj.__dict__) #输出:{'name': 'noah', 'age': 18}
```
## 元类实现单例模式
### 单例模式是什么
单例模式就是指,如果实例化的对象数据是一样的,就没有必要分配两个内存地址去存储它,以便节约内存,例如:
```
>>> a,b=1,1
>>> id(a),id(b)
(1490068576, 1490068576)
```
那如果是自定义的类,类中的数据不变化(如mqsql端口信息),实例化的对象ID一样吗?
~~~
class mysql:
def __init__(self):
self.host='127.0.0.1'
self.port=3306
obj1=mysql()
obj2=mysql()
print(obj1)
print(obj2)
#输出:
<__main__.mysql object at 0x000002519D69A240>
<__main__.mysql object at 0x000002519D69A6D8>
~~~
### 通过绑定类方法实现[常规]
```
class MySQL:
__instance=None
def __init__(self):
self.host='127.0.0.1'
self.port=3306
@classmethod
def singleton(cls):
if not cls.__instance:
obj=cls()
cls.__instance=obj
return cls.__instance
def conn(self):
pass
obj1=MySQL.singleton()
obj2=MySQL.singleton()
print(obj1)
print(obj2)
#输出:
<__main__.Mysql object at 0x0000019F876AA710>
<__main__.Mysql object at 0x0000019F876AA710>
```
### 通过自定义元类的方法实现
```
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
self.__instance=None
def __call__(self, *args, **kwargs):
if not self.__instance:
obj=object.__new__(self)
self.__init__(obj)
self.__instance=obj
return self.__instance
class Mysql(object,metaclass=Mymeta):
def __init__(self):
self.host='127.0.0.1'
self.port=3306
def conn(self):
pass
obj1=Mysql()
obj2=Mysql()
print(obj1 is obj2)
输出:
<__main__.Mysql object at 0x0000019220B4A908>
<__main__.Mysql object at 0x0000019220B4A908>
```
- 基础部分
- 基础知识
- 变量
- 数据类型
- 数字与布尔详解
- 列表详解list
- 字符串详解str
- 元组详解tup
- 字典详解dict
- 集合详解set
- 运算符
- 流程控制与循环
- 字符编码
- 编的小程序
- 三级菜单
- 斐波那契数列
- 汉诺塔
- 文件操作
- 函数相关
- 函数基础知识
- 函数进阶知识
- lambda与map-filter-reduce
- 装饰器知识
- 生成器和迭代器
- 琢磨的小技巧
- 通过operator函数将字符串转换回运算符
- 目录规范
- 异常处理
- 常用模块
- 模块和包相关概念
- 绝对导入&相对导入
- pip使用第三方源
- time&datetime模块
- random随机数模块
- os 系统交互模块
- sys系统模块
- shutil复制&打包模块
- json&pickle&shelve模块
- xml序列化模块
- configparser配置模块
- hashlib哈希模块
- subprocess命令模块
- 日志logging模块基础
- 日志logging模块进阶
- 日志重复输出问题
- re正则表达式模块
- struct字节处理模块
- abc抽象类与多态模块
- requests与urllib网络访问模块
- 参数控制模块1-optparse-过时
- 参数控制模块2-argparse
- pymysql数据库模块
- requests网络请求模块
- 面向对象
- 面向对象相关概念
- 类与对象基础操作
- 继承-派生和组合
- 抽象类与接口
- 多态与鸭子类型
- 封装-隐藏与扩展性
- 绑定方法与非绑定方法
- 反射-字符串映射属性
- 类相关内置方法
- 元类自定义及单例模式
- 面向对象的软件开发
- 网络-并发编程
- 网络编程SOCKET
- socket简介和入门
- socket代码实例
- 粘包及粘包解决办法
- 基于UDP协议的socket
- 文件传输程序实战
- socketserver并发模块
- 多进程multiprocessing模块
- 进程理论知识
- 多进程与守护进程
- 锁-信号量-事件
- 队列与生产消费模型
- 进程池Pool
- 多线程threading模块
- 进程理论和GIL锁
- 死锁与递归锁
- 多线程与守护线程
- 定时器-条件-队列
- 线程池与进程池(新方法)
- 协程与IO模型
- 协程理论知识
- gevent与greenlet模块
- 5种网络IO模型
- 非阻塞与多路复用IO实现
- 带着目标学python
- Pycharm基本使用
- 爬虫
- 案例-爬mzitu美女
- 案例-爬小说
- beautifulsoup解析模块
- etree中的xpath解析模块
- 反爬对抗-普通验证码
- 反爬对抗-session登录
- 反爬对抗-代理池
- 爬虫技巧-线程池
- 爬虫对抗-图片懒加载
- selenium浏览器模拟