[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瀏覽器模擬