1. 程式人生 > >eval、exec及元類、單例實現的5種方法

eval、exec及元類、單例實現的5種方法

管理 wrap `` assm 當前 name 出發點 tac 全局

eval內置函數

# eval內置函數的使用場景:
# 1.執行字符串會得到相應的執行結果
# 2.一般用於類型轉化,該函數執行完有返回值,得到dict、list、tuple等
?
dic_str = "{‘a‘: 1, ‘b‘: 2, ‘c‘: 3}"
print(eval(dic_str))
?
list_str = "[1, 2, 3, 4, 5]"
print(eval(list_str))
?
tuple_str = "(1, 2, 3, 4, 5)"
print(eval(tuple_str))

exec內置函數

# exec應用場景
# 1.執行字符串沒有執行結果(沒有返回值)
# 2.將執行的字符串中產生的名字形成對應的局部名稱空間
# 3.可以操作全局與局部兩個名稱空間,一般不用關心全局名稱空間
?
source = ‘‘‘
name = ‘Bob‘
age = 20
‘‘‘
class A:
pass
a = A()
?
dic = {}
exec(source, {}, dic)
a.__dict__ = dic # dic = {‘name‘: ‘Bob‘, ‘age‘: 20}
print(a.__dict__)
print(a.name)
print(a.age)

元類

# 元類:類的類
# 通過class產生的類,也是對象,而元類就是用來產生該對象的類
local_str = """
def __init__(self, name, age):
self.name = name
self.age = age
def study(self):
print(self.name + ‘在學習‘)
"""
local_dic = {}
exec(local_str, {}, local_dic)
Student = type(‘Student‘, (), l_d)
print(Student)
?
?

type產生類

# 類是type的對象,可以通過type(參數)來創建類
?
# type(name, bases, namespace)
?
s = ‘‘‘
my_a = 10
my_b = 20
def __init__(self):
pass
@classmethod
def print_msg(cls, msg):
print(msg)
‘‘‘
namespace = {}
exec(s, {}, namespace)
?
Student = type(‘Student‘, (object, ), namespace)
?
stu = Student()

自定義元類

# 元類:所有自定義的類本身也是對象,是元類的對象,所有自定義的類本質上是由元類實例化出來了
Student = type(‘Student‘, (object, ), namespace)
?
class MyMeta(type):
# 在class Student時調用:Student類的創建 => 來控制類的創建

# 自定義元類,重用init方法的目的:
# 1.該方法是從type中繼承來的,所以參數同type的init
# 2.最終的工作(如果開辟空間,如果操作內存)還是要借助type
# 3.在交給type最終完成工作之前,可以對類的創建加以限制 *****
def __init__(cls, class_name, bases, namespace):
# 目的:對class_name | bases | namespace加以限制 **********************
super().__init__(class_name, bases, namespace)

# 在Student()時調用:Student類的對象的創建 => 來控制對象的創建

# 自定義元類,重寫call方法的目的:
# 1.被該元類控制的類生成對象,會調用元類的call方法
# 2.在call中的返回值就是創建的對象
# 3.在call中
# -- 通過object開辟空間產生對象
# -- 用被控制的類回調到自己的init方法完成名稱空間的賦值
# -- 將修飾好的對象反饋給外界
def __call__(cls, *args, **kwargs):
# 目的:創建對象,就可以對對象加以限制 **********************
obj = object.__new__(cls) # 通過object為那個類開辟空間
cls.__init__(obj, *args, **kwargs) # 調回當前被控制的類自身的init方法,完成名稱空間的賦值
return obj
?
# 問題:
# 1.繼承是想獲得父級的屬性和方法,元類是要將類的創建與對象的創建加以控制
# 2.類的創建由元類的__init__方法控制
# -- 元類(class_name, bases, namespase) => 元類.__init__來完成實例化
# 3.類的對象的創建由元類的__call__方法控制
# -- 對象產生是需要開辟空間,在__call__中用object.__new__()來完成的
class Student(object, metaclass=MyMeta):
pass
?
# class Student: <=> type(class_name, bases, namespace)
?
?

單例

# 單例:一個類只能產生一個實例
# 為什麽要有單例:
# 1.該類需要對象的產生
# 2.對象一旦產生,在任何位置再實例化對象,只能得到第一次實例化出來的對象
# 3.在對象唯一創建後,可以通過屬性修改或方法間接修改屬性,來完成數據的更新,不能通過實例化方式更新數據
?
## 單例
?
```python
#實現單例方法1--類方法及類封裝屬性
class Song:
__instance = None
def __init__(self):
pass
@classmethod
def getInstance(cls):
if cls.__instance == None:
cls.__instance = cls()
return cls.__instance
s1 = Song.getInstance()
s2 = Song.getInstance()
print(s1, s2)
?
#實現單例方法2--裝飾器
```
?
```python
def singleton(cls):
_instance = None
def getInstance(*args, **kwargs):
nonlocal _instance
if _instance == None:
_instance = cls(*args, **kwargs)
return _instance
return getInstance
?
@singleton
class A:
def __init__(self, num):
self.num = num
print(A(1), A(2), A(3))
?
#實現單例方法3--重用__new__方法
```
?
```python
class A:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance == None:
cls.__instance = super().__new__(cls)
return cls.__instance
print(A(), A())
?
#實現單例方法4--模塊導入(原理:一個模塊只有在第一次導入時才會編譯執行,之後都是從內存中尋找)
```
?
```python
# single_module.py
class Single:
pass
singleton = Single()
?
# 測試文件
from single_module import singleton
print(singleton)
print(singleton)
?
?
#實現單例方法5--自定義元類,並將__call__方法重用
class SingleMeta(type):
__instance = None
def __call__(cls, *args, **kwargs):
if SingleMeta.__instance == None:
SingleMeta.__instance = object.__new__(cls)
cls.__init__(SingleMeta.__instance, *args, **kwargs)
return SingleMeta.__instance
?
?
class Songs(metaclass=SingleMeta):
def __init__(self):
pass
pass
?
?
s1 = Songs()
s2 = Songs()
print(s1, s2)
?
```
?
?
?
### 就選課系統分析面向對象思想
?
```python
‘‘‘
1.做項目,優先考慮要用到哪些對象:老師、學生、管理員、課程、學校等等,那就優先為這些對象創建出對應的類,而不是優先考慮項目要去實現哪些功能,功能的出發點永遠從創建類開始,優先想到了該項目有哪些功能,也是重點向這些功能應該封裝成什麽類
?
2.類一旦有了,再思考,該類應該有哪些屬性,這就是設計__init__方法的過程,然後思考該類有哪些方法,不需要對象的參與,就是類方法,需要就是對象方法
?
3.對於數據的存儲,我們最終要持久化到文件或是硬盤,但是數據要在程序中使用,那就必須在內存中使用,那麽數據在內存中采用哪種方式存儲,列表可以,但是索引標識數據方式很不方便,字典可以,具有信息標識,對象也可以,具有信息標識,而且訪問數據修改數據采用.語法,相當簡單,所以優選對象存儲,這也是面向對象的優點
?
4.那麽隨著項目的發展,很多類就僅僅用來存放數據的,那這樣的類就可以稱之為Model類,那這些類的數據也具備很多業務邏輯,那我們在面向對象思想中,不是將功能寫在Model類中,而是定義處理業務的工具類,必然專門操作與數據庫打交道的操作,丟在DB_Handle類中,那這樣專門處理業務邏輯的類,我們稱之為Ctrl類
?
5.而大型項目中有大量與用戶交互的頁面,我們也用專門的類來控制,這就是View類,就選課系統而言,可以封裝打印各自信息的各種方法,也是在Ctrl的合適位置調用即可,這就是面向對象的 MVC 設計模式
‘‘‘
```
?
?
?

eval、exec及元類、單例實現的5種方法