Python面經【8】- Python設計模式專題-上卷

Python面經【8】- Python設計模式專題-上卷

  • 一、接口
  • 二、單例模式
    • (1) 方法一:使用模塊
    • (2) 方法二: 裝飾器實現【手撕 + 理解】(單下劃線 + 閉包 + 裝飾器 + 類方法)
    • (3) 方法三:基于__new__方法【new和init 】

設計模式是一套 被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。

一、接口

定義:一種特殊的類,聲明了若干方法,要求繼承該接口的類必須實現這些方法,可以通過抽象基類(Abstract Base Class)來實現。
作用:限制繼承接口的類的方法的名稱調用方式,隱藏了類的內部實現。

 1. from abc import ABCMeta, abstractmethod2. class Payment(metaclass = ABCMeta):3. 	@abstractmethod4. 	def pay(self, money):5. 		pass6. 	7. class Payment_first(Payment):8. 	def pay(self, money):9. 		print("給%s塊錢"%money)
10. 		
11. pay = Payment_first()
12. pay_first = Payment_first()
13. pay_first.pay(3)
14. 結果:給3塊錢

二、單例模式

單例模式是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。在系統中,某個類只能出現一個實例對象時,單例對象就能排上用場
定義:保證一個類只能有一個實例,而客戶可以從一個眾所周知的訪問點訪問它時。
優點: 1、在內存里只有一個實例,減少了內存的開銷,尤其是頻繁的創建和銷毀實例。
2、避免對資源的多重占用(比如寫文件操作)。
比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個AppConfig的類來讀取配置文件的信息。如果在程序運行期間,有很多地方都需要配置文件的內容,也就是說,很多地方都需要創建AppConfig對象的實例,這就導致系統中存在多個AppConfig的實例對象,而這樣會嚴重浪費內存,類似于AppConfig這樣的類,我們希望在程序運行期間只存在一個實例對象。

(1) 方法一:使用模塊

實現方法:將需要實現的單例功能放到一個.py文件中
實現原理:Python的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成.pyc文件,當第二次導入時,就會直接加載.pyc文件,而不會再次執行模塊代碼。因此,我們只需把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了。

1. # singleton_module.py
2. class SingletonClass:
3. 	def __init__(self):
4. 		pass
5.  
6. singleton_instance = SingletonClass()

將上面的代碼保存在文件singleton_module.py中,要使用時,直接在其他文件中導入此文件中的對象,這個對象既是單例模式的對象。

1. # main.py
2. from singleton_module import singleton_instance
3.  
4. # 使用singleton_instance

(2) 方法二: 裝飾器實現【手撕 + 理解】(單下劃線 + 閉包 + 裝飾器 + 類方法)

定義一個裝飾器函數,將被裝飾的類實例保存在閉包中,每次獲取實例時返回同一個實例對象。

 1.  1. def Singleton(cls):2.  2.     _instance = {}3.  3.     def _singleton(*args, **kargs):4.  4.         if cls not in _instance:#判斷該實例是否存在,存在就直接返回,不存在就創建        5.  5.             _instance[cls] = cls(*args, **kargs)6.  6.         return _instance[cls]7.  7.     return _singleton8.  8.  9.  9. @Singleton
10. 10. class A(object):
11. 11.     a = 1
12. 12.     def __init__(self, x=0):
13. 13.         self.x = x
14. 14.  
15. 15. a1 = A(2)
16. 16. a2 = A(3)
17. 17. # 輸出:{<class '__main__.A'>: <__main__.A object at 0x7fb9af751af0>}
18. ===輸出結果===
19. <__main__.A object at 0x000001E9D1F099B0>
20. <__main__.A object at 0x000001E9D1F099B0>
  • 輸出結果分析:
    • 輸出顯示兩個實例的內存地址是相同的(0x000001E9D1F099B0),這證明 a1 和 a2 實際上是同一個實例的引用
    • 這證實了單例模式的實現,確保了類 A 無論被實例化多少次,始終只有一個實例存在

(3) 方法三:基于__new__方法【new和init 】

我們都知道,當我們實例化一個對象時,是先執行了類的__new__方法(我們沒寫時,默認調用object.new),實例化對象;然后再執行類的__init__方法,對這個對象進行初始化,所以我們可以基于這個,實現單例模式。
個人最初常用的是重寫__new__方法的方式,但是用重寫類中的__new__方法,在多次創建時,盡管返回的都是同一個對象,但是每次執行創建對象語句時,內部的__init__方法都會被自動調用,而在某些應用場景,可能存在初始化方法只能運行只能允許運行一次的需求,這是這種單例的方式并不可取。

 1. class Download(object):2. 	instance = None3. 	def __init__(self):4. 		print("__init__")5. 	def __new__(cls, *args, **kargs):6. 		if cls.instance is None:7. 			cls.instance = super().__new__(cls)8. 		return cls.instance9. object1 = Download()
10. object2 = Download()
11. print(object1)
12. print(object2)

運行結果,可以看到初始化方法多次執行了。

1. __init__
2. __init__
3. <__main__.Download object at 0x7f56beb4ea90>
4. <__main__.Download object at 0x7f56beb4ea90>  

init方法通常用在初始化一個類實例的時候,但其實它不是實例化一個類的時候第一個被調用的方法。當使用Student(id, name)這樣的表達式來實例化一個類時,最先被調用的方法其實是new方法。
new方法接受的參數雖然也是和init一樣,但init是在類實例創建之后調用,而new方法正式創建這個類實例的方法。
New為對象分配空間,是內置的靜態方法,new在內存中為對象分配了空間也返回了對象的引用,init獲得了這個引用才初始化這個實例。

Eg:示例
一個非常簡單的單例

1. class A:
2. 	instance = None
3.  	def __new__(cls, *args, **kwargs):
4.            	if cls.instance is None:
5.                	       cls.instance = super().__new__(cls)
6.   		return cls.instance

因為new方法是一個靜態方法(也就是在定義的時候就沒有cls參數),所以在這里要傳入一個cls參數,而且這里的new你改造過了,所以要返回爸爸的new方法。
按造這個方法改造的單例怎么new都是同一個實例,但init仍然會被執行多次,也就是創建了幾個對象就調用幾次初始化方法。所以還要對init再進行一些判斷

 1.  1. class A:2.  2.  	instance = None3.  3.  	init_flag = False # 初始化標記4.  4.  5.  5.  	def __new__(cls, *args, **kwargs):6.  6.   		if cls.instance is None:7.  7.    	cls.instance = super().__new__(cls)8.  8.   		return cls.instance9.  9.  
10. 10.  	def __init__(self):
11. 11.   		if A.init_flag:
12. 12.    	return
13. 13.   		print('執行了初始化方法')
14. 14.   		A.init_flag = True
15. 15.  
16. 16. if __name__ == '__main__':
17. 17.  a = A()
18. 18.  b = A()
19. 19.  print(a)
20. 20.  print(b)
21. ===結果如下===
22. 執行了初始化方法
23. <__main__.A object at 0x000001E9D1F096D8>
24. <__main__.A object at 0x000001E9D1F096D8>

結果分析:

  • 執行了初始化
    這一行表明 init 方法被執行了一次。由于在 init 方法中有一個條件檢查 (if A.init_flag:),它確保初始化代碼塊只執行一次。在第一次創建實例 a 時,init_flag 是 False,所以 init 方法的內部代碼被執行,并且 init_flag 被設置為 True。當創建第二個實例 b 時,由于 init_flag 已經是 True,init 方法內的代碼不會再次執行。
  • <main.A object at 0x000001E9D1F096D8>
    這兩行輸出分別是打印的 a 和 b 實例。它們具有相同的內存地址 (0x000001E9D1F096D8),這證明了 a 和 b 是同一個對象的兩個引用。這符合單例模式的預期效果,即不管創建多少次該類的實例,始終只有一個實例存在。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/214424.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/214424.shtml
英文地址,請注明出處:http://en.pswp.cn/news/214424.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

簡單的 u-popup 彈出框

uniapp中的popup組件可以用于彈出簡單的提示框、操作框、菜單等。它可以通過position屬性控制彈出框的位置&#xff0c;不同的position值會使得彈出框呈現不同的彈出形式 目錄 一、實現思路 二、實現步驟 ①view部分展示 ②JavaScript 內容 ③css中樣式展示 三、效果展示 …

Linux系統---基于Pipe實現一個簡單Client-Server system

顧得泉&#xff1a;個人主頁 個人專欄&#xff1a;《Linux操作系統》 《C/C》 《LeedCode刷題》 鍵盤敲爛&#xff0c;年薪百萬&#xff01; 一、題目要求 Server是一個服務器進程&#xff0c;只能進行整數平方運算。Client要計算一個整數的平方的平方的平方&#xff0c;即…

聊聊 Jetpack Compose 原理 -- 穿透刺客 CompositionLocal

Compose 官方說明一直很簡潔&#xff1a;CompositionLocal 是通過組合隱式向下傳遞數據的工具。 我們先來看一段代碼&#xff1a; class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setCo…

datav-輪播排名-對數據進行處理

前言 對于大屏需求我們排名數據輪播也是經常需要用到的需求&#xff0c;datav也是給我們提供了 不是說我們自己不能寫&#xff0c;而是提供好的輪子比我們自己 寫的&#xff0c;更全面&#xff0c;更周到&#xff0c; 沒有特殊需求的話&#xff0c;使用datav配置一下完成這個…

mysqlsh導入json,最終還得靠navicat導入json

工作需要將一個巨大的10G的json導入mysql數據庫。 看到mysql官方有對json導入的支持。 如下&#xff1a; MySQL :: Import JSON to MySQL made easy with the MySQL Shell $ mysqlsh rootlocalhost:33300/test --import /path_to_file/zips.json Creating a session to root…

產品經理進階:以客戶為中心的8個維度

目錄 簡介 以客戶為中心 流程和組織維度 產品維度 CSDN學院《硬件產品進階課》

python:六種算法(DBO、RFO、WOA、GWO、PSO、GA)求解23個測試函數(python代碼)

一、六種算法簡介 1、蜣螂優化算法DBO 2、紅狐優化算法RFO 3、鯨魚優化算法WOA 4、灰狼優化算法GWO 5、粒子群優化算法PSO 6、遺傳算法GA 二、6種算法求解23個函數 &#xff08;1&#xff09;23個函數簡介 參考文獻&#xff1a; [1] Yao X, Liu Y, Lin G M. Evolution…

讀書筆記 | 自我管理的關鍵是提高執行力

哈嘍啊&#xff0c;你好&#xff0c;我是雷工&#xff01; 有句話說&#xff0c;能管好自己才是真的本事。 自我管理&#xff0c;管好自己很重要。 我們之所以懂得這么多的道理&#xff0c;卻依然過不好這一生&#xff1f; 很大部分原因是因為管不住自己&#xff0c;做不到。 …

性能測試基礎

性能測試分類 客戶端性能&#xff1a;測試APP自身的性能&#xff0c;例如CPU、內存消耗&#xff1b;web頁面元素渲染速度 服務端性能&#xff1a;測試服務端項目程序的支持的并發、處理能力、響應時間等&#xff0c;主要通過接口來做性能測試 性能測試指標 并發 同時向服務…

大一作業習題

第一題&#xff1a;答案&#xff1a; #include <stdio.h> void sort(int a[], int m) //將數組a的前m個元素(從小到大)排序 {int i 0;for (i 0; i < m - 1; i){int j 0;int flag 1;for (j 0; j < m - 1 - i; j){if (a[j] > a[j 1]){int t 0;t a[j];…

Java八股文面試全套真題【含答案】- Servlet篇

以下是一些關于Servlet的經典面試題以及它們的答案&#xff1a; 什么是 Servlet&#xff1f; 答案&#xff1a;Servlet 是運行在服務器上&#xff0c;用于處理客戶端請求并生成響應的 Java 類。 Servlet 和 JSP 之間的區別是什么&#xff1f; 答案&#xff1a;Servlet 是基于…

1.鴻蒙應用程序開發app_hap開發環境搭建

1.下載Node.js, Javascipts的運行環境 node.js版本下載v12.18.3/https://www.cnblogs.com/txwtech/p/17865780.html 2.下載并安裝DevEco Studio DevEco Studio 3.1 DevEco Studio 3.1配套支持HarmonyOS 3.1版本及以上的應用及服務開發&#xff0c;提供了代碼智能編輯、低代…

Docker筆記:Docker中簡單配置Mysql/Redis/Mongodb容器

Docker 配置 Mysql 容器 1 &#xff09;方案1&#xff1a;基于centos等linux操作系統 啟動centos鏡像&#xff0c;在里面安裝 mysql這樣比較麻煩&#xff0c;配置的東西很多 … 2 &#xff09;方案2&#xff1a;直接用 mysql 鏡像 (推薦) $ docker pull mysql 下載鏡像$ do…

589. N 叉樹的前序遍歷

589. N 叉樹的前序遍歷 java1&#xff1a;stack棧&#xff1a;沒看懂 class Solution {public List<Integer> preorder(Node root) {List<Integer> res new ArrayList<Integer>();if (root null) {return res;}Map<Node, Integer> map new HashMa…

C盤瘦身,C盤清理

以下只是我的C盤清理經驗~ 一.【用軟件簡單清理C盤】 使用一些垃圾清理軟件&#xff0c;簡單的初步把C盤先清理一遍。&#xff08;這種軟件太多我就不推薦了……&#xff09; 二.【WPS清理大師】 因為我電腦裝了WPS&#xff0c;發現右鍵單擊C盤有個選項【釋放C盤空間】&#xf…

接口自動化框架(Pytest+request+Allure)

前言&#xff1a; 接口自動化是指模擬程序接口層面的自動化&#xff0c;由于接口不易變更&#xff0c;維護成本更小&#xff0c;所以深受各大公司的喜愛。 接口自動化包含2個部分&#xff0c;功能性的接口自動化測試和并發接口自動化測試。 本次文章著重介紹第一種&#xff0c…

Vue3.3.4中watch無法監測props的更改

背景 網上說了很多解決方案&#xff0c;都是通過watch(() > props.value, (newValue, oldValue) > {})解決&#xff0c;或者是加上{deep: true}附加屬性。但是我在Vue3.3.4中&#xff0c;還是無法解決。 下面說一下我的解決方案。 解決方案 通過父組件調用子組件defineE…

點云/Mesh 常見處理庫和軟件匯總

注&#xff1a;參考 網址1、網址2 文章目錄 軟件通用點云/Mesh處理庫通用幾何處理庫專用功能庫 軟件 Processing MeshLabCloudCompareTrimeshPyVistaVedo Visualization Simple-3dvizPlotOptiX (Requires CUDA-enabled GPU)PolyscopePyrender 通用點云/Mesh處理庫 PCL &am…

【開發問題】vue的前端和java的后臺,用sm4,實現前臺加密,后臺解密

sm4加密 vue引入的包代碼加密解密 javamaven代碼運行結果 vue 引入的包 npm install sm-crypto代碼加密解密 加密&#xff1a; key &#xff1a;代表著密鑰&#xff0c;必須是16 字節的十六進制密鑰 password &#xff1a;加密前的密碼 sm4Password &#xff1a;代表sm4加密…

Python之格式化保存數據點

功能&#xff1a;將平面點集存儲為格式化txt文檔&#xff0c;每個坐標值為5位整數&#xff0c;前三位為整數&#xff0c;后2位為小數 輸入&#xff1a;平面點坐標&#xff0c;用列表存儲&#xff0c;列表的元素為點坐標元組 輸出&#xff1a;txt文件&#xff0c;每行一個點坐…