1. 程式人生 > 實用技巧 >上傳python筆記,看看部落格園的編輯器的效果

上傳python筆記,看看部落格園的編輯器的效果

一、Python 中的檔案操作

1.1 檔案操作需要了解的前置知識

1.1.1 為什麼需要用到檔案操作
  • 如果單純的將程式需要用到的內容直接的儲存在記憶體中,那麼程式每一次執行之後,所儲存的資料就會消失,這個時候就需要使用某種方式長期的儲存資料,例如儲存在檔案中,或者儲存在資料庫中。
1.1.2 對路徑的劃分
  • 相對路徑:相對於當前檔案所在目錄的一個路徑。通常使用 . 表示當前目錄,.. 表示上級目錄,通過 ../../ abc.txt 的指令我們可以找到上上級目錄下的 abc.txt 檔案
  • 絕對路徑:從檔案的根目錄開始計算的路徑。在 windows 下,絕對路徑通常是以碟符開頭的,在 linux/unix 下絕對路徑通常是以 / 開頭的,例如 C:\Users\min\Desktop\abc.txt
    就是一個絕對路徑。
  • 如果說一個檔案它的位置和當前的專案有關,就可以寫作相對路徑,如果這個檔案和系統有關,就可以寫成絕對路徑,例如網頁設計中的資源我們通常會寫作相對路徑,用於防止目錄的洩露。
1.1.3 二進位制檔案和文字檔案
  • 二進位制檔案: 指的是擁有特定格式,需要使用對應的演算法進行解析的檔案,例如可執行檔案(.exe)、音訊檔案(.mp3 .aac)、視訊檔案(.mp4)、圖片檔案(.jpg)。
  • 文字檔案:其中儲存的直接就是字串,只需要通過基本的文字檢視工具就可以開啟,不需要專門解析。

1. 2 檔案的操作函式

1.2.1 檔案的基本操作函式

看看https://zhuanlan.zhihu.com/p/112630994

  • open: 用於開啟檔案,將檔案和檔案物件建立關聯。其中第一個引數是檔案的路徑,第二個引數是檔案的開啟方式,還有一個引數 encoding 用於說明檔案的編碼型別。

    # 通過 open 函式可以將檔案物件和一個檔案建立關聯
    # 檔案的開啟方式通常有 r(讀) w(寫) a(追加) b(在操作二進位制檔案的時候使用)
    # 函式的返回值是一個檔案物件,通過檔案物件可以執行相應的檔案操作
    file = open(r'data.txt', 'w+')
    
    # 通過 open 函式可以將檔案物件和一個檔案建立關聯
    # 檔案的開啟方式通常有 r(讀) w(寫) a(追加) b(在操作二進位制檔案的時候使用)
    # 函式的返回值是一個檔案物件,通過檔案物件可以執行相應的檔案操作
    try:
        # 使用這個寫法會自動的關閉檔案,不需要編寫 file.close()
        with open(r'data.txt', 'w+') as file:
            file.write('hello world')
    except Exception as e:
        print(e)
    
  • file.close(): 用於關閉一個檔案,否則可能產生問題

    # 通常在檔案操作完畢之後,需要關閉檔案,沒有正確的關閉檔案可能會導致兩個問
    # 題,(1) 檔案被佔用,在當前專案中無法再次開啟檔案。(2) 檔案的修改無法被應用
    file.close()
    
  • file.write() \ file.writelines(): 向檔案內寫入資料

    # 通過 write 一次只能寫入一個字串
    file.write('hello world')
    # 通過 writelines 一次可以寫入多個字串
    file.writelines(['hello', ' world'])
    
  • file.read() \ file.readlline() \ file.readlines(): 從檔案內讀取資料

    # 讀取所有內容,可以傳入一個引數,表示想要讀取的字元數
    print(file.read())
    # 讀取一行內容,可以傳入一個引數,表示想要讀取的字元數
    print(file.readline())
    # 讀取文字內的所有內容,將每一行作為一個元素儲存到列表中
    print(file.readlines())
    
1.2.2 檔案指標操作函式
  • 檔案指標是什麼? 檔案指標用於標識當前檔案的讀寫位置,通過移動檔案指標可以改變讀寫的起始位置

  • seek: 設定檔案的讀寫位置。

    # 通過 seek 將檔案指標移動到倒數第 4 個位置
    # 0: 檔案開頭開始算起,1:當前位置,2: 檔案末尾。
    file.seek(-4, 2)
    print(file.read())
    
  • tell: 獲取檔案指標當前所在的位置。

    # tell 函式用於獲取當前檔案指標的位置,可以計算檔案大小
    file.seek(0, 2)
    print(file.tell())
    
1.2.3 通過 os 模組操作檔案
  • 需要使用 import os 匯入 os 模組,使用其中提供的檔案操作函式來操作檔案
  • python 的內建檔案操作使用的是面向物件的程式設計方式file.read(),而 os 模組使用面向過程的方式 read(file)
file = os.open('data.txt', os.O_RDONLY)
print(os.read(file, 2))
os.lseek(file, 5, os.SEEK_SET)
print(os.read(file, 2))
os.close(file)

二、面向物件程式設計

2.1 面向物件和麵向過程

2.1.1 面向過程
  • 思想:程式設計的著眼點在於處理問題的一系列過程(函式)。
  • 特點:資料和處理資料的函式 分離的。
2.1.2 面向物件
  • 思想:程式設計的著眼點在於解決這個問題所需要的物件有哪些,需要完成什麼功能。

  • 特點:封裝特性,將資料和處理資料的函式封裝到了一起。

  • 三大特性:封裝 繼承 多型

2.2 類的編寫

2.2.1 簡單的類
  • 通過 class 定義出一個類,一個類其實就是一個自定義的型別,其中描述了某個類別的物件可以實現的功能(方法)和一些描述資訊(屬性),通過 物件 = 類名() 的方式可以創建出一個物件。
# 簡單類的定義方式,使用關鍵字 class
class ClassName(object):
    # 類成員函式,在 python 中被稱為方法
    def class_func1(self):
        print('def class_func(self);')
    # 類成員函式,第一個引數必須是 self,後續可以含有其它的引數
    def class_func2(self, value = 100):
        print('def class_func(self, %d);' % value)
# 通過物件名 = 類名(引數) 的方式可以建立一個物件
object1 = ClassName()
object1.class_func1()
object1.class_func2()
2.2.2 建構函式和解構函式
  • 建構函式:python 中的每一個類中都擁有一個建構函式叫做 __init__,這個函式會被用於執行初始化操作,在一個物件被建立時,自動的呼叫一次。

  • 解構函式: python 中的每一個類中都擁有一個解構函式叫做 __del__,這個函式會被用於執行清理操作,在物件被刪除的時候,自動的呼叫一次

    # 一個包含建構函式和解構函式的類
    class ClassName2(object):
    
        # 當前類的建構函式,函式可以擁有引數,在建立物件是傳入
        def __init__(self, name, age):
            # 在建構函式內執行基本的初始化操作
            print("def __init__(self, %s, %d)" % (name, age))
    
        # 解構函式用於釋放資源,但是由於 python 存在垃圾回收機制
        # 所以解構函式使用的比較少,我們可以在其中關閉檔案等資源
        def __del__(self):
            # 輸出表示解構函式被呼叫了
            print("def __del__(self)")
    
    # 建立物件時需要傳入引數,和建構函式的引數對應,因為建立物件時,會自動呼叫__init__()函式,當然也會執行裡面的語句,在這裡是一個print()函式列印相應的內容
    object2 = ClassName2('xiaoming', 18)
    >>>def __init__(self, xiaoming, 18)
    def __del__(self)
    object3 = ClassName2('xiaohong', 80)
    >>>def __init__(self, xiaohong, 80)
    def __del__(self)                                  
    

關於解構函式何時被呼叫:

析構方法__del__是物件在被垃圾回收的時候起作用的一個方法,它的執行一般也就意味著物件不能夠繼續引用, 回收記憶體.
記憶體回收的方式有兩種:

  • 1、當物件在某個作用域中呼叫完畢,在跳出其作用域的同時解構函式會被呼叫一次,這樣可以用來釋放記憶體空間:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
class Foo:
    #初始化方法
    #建立完物件後會自動被呼叫
    def __init__(self):
        print('構造方法被呼叫')
    #析構方法
    #當物件被刪除時,會自動被呼叫,然後釋放記憶體
    def __del__(self):
        print('指令碼執行結束, 釋放記憶體')
#建立物件
f = Foo()
print('這應該是指令碼最後一句.')
# 這個地方整個檔案的作用域就結束了,所以物件f結束其生命週期(因為程式執行停止而結束),系統自動執行解構函式來做清理善後的工作,所以列印"指令碼執行結束, 釋放記憶體"成了最後執行的語句.
執行結果:
    構造方法被呼叫
	這應該是指令碼最後一句.
	指令碼執行結束, 釋放記憶體

Process finished with exit code 0
  • 2、使用del 刪除物件時,會呼叫他本身的解構函式, 相當於手動釋放記憶體
class Foo:
    #初始化方法
    #建立完物件後會自動被呼叫
    def __init__(self):
        print('構造方法被呼叫')

    #析構方法
    #當物件被刪除時,會自動被呼叫,然後釋放記憶體
    def __del__(self):
        print('指令碼執行結束, 釋放記憶體')

#建立物件
f = Foo()
#刪除物件
del f # 刪除就立馬呼叫解構函式,(因為del刪除物件而結束,物件結束,系統就會呼叫解構函式)
print('這應該是指令碼最後一句.')
執行結果:
	構造方法被呼叫
	指令碼執行結束, 釋放記憶體
	這應該是指令碼最後一句.

Process finished with exit code 0
2.2.3 例項屬性和類屬性
  • 例項屬性: 具體的某一個物件擁有的屬性

  • 通過 self 和 例項名稱都可以新增例項屬性,新增的屬性是歸某一個具體的例項所有的。建構函式中的一開始初始化的例項屬性會被所有的例項擁有(那是因為所有的例項都會呼叫建構函式)

    # 一個含有例項屬性的類
    class ClassName3(object):
    
        # 建構函式,用於初始化例項屬性
        def __init__(self, name, age):
            # 1. 為當前的例項(物件)建立兩個個例項屬性並進行初始化
            self.age = age
            self.name = name
    
        # 一個方法,呼叫之後可以新增例項屬性
        def add_value(self, v):
            # 2. 通過 self 可以在方法內為呼叫當前方法的例項新增例項屬性,在類外面新增屬性:例項名稱.屬性 = value 進行賦值新增
            self.value = v
    
        # 用於輸出當前類內的所有屬性
        def print_member(self):
            # __dict__可以輸出當前例項內的屬性組成的鍵值對
            print(self.__dict__)
    
    object4 = ClassName3('xiaoming', 80)
    object4.print_member()
    >>>{'age': 80, 'name': 'xiaoming'}
    object5 = ClassName3('xiaohong', 18)
    object5.add_value(30)
    object5.print_member()
    >>>{'age': 18, 'name': 'xiaohong', 'value': 30}
    # 3. 通過例項名稱直接的點出屬性進行賦值新增
    object4.value2 = 300
    object4.print_member()
    >>>{'age': 80, 'name': 'xiaoming', 'value2': 300}
    
  • 類屬性:歸整個類所有,被所有的物件共有的屬性

  • 通過類名和在類內直接定義可以新增類屬性,新增的屬性是歸所有的例項擁有的

    # 一個含有類屬性的類
    class ClassName4(object):
    
        # 1. 在類內的一級縮排內直接定義的屬性就是類屬性
        class_value = 10
    
        # 建構函式,用於訪問類屬性
        def __init__(self):
            # 在建構函式中可以使用下面的兩種形式訪問類屬性
            print(self.class_value)
            print(ClassName4.class_value)
    
        # 一個方法,呼叫之後可以新增類屬性
        def add_value(self, v):
            # 2. 通過 類名 可以在方法內為整個類新增一個類屬性 3. 在類外也可以通過類名直接的新增屬性
            ClassName4.value = v
    
        # 用於輸出當前類內的所有屬性
        def print_member(self):
            # 例項.__dict__ 儲存的是例項內的所有屬性
            # 類名.__dict__ 儲存的是類內的所有屬性
            print('例項', self.__dict__)     # 因為沒有例項屬性,所以結果是{}
            print('類', ClassName4.__dict__)
    
    object5 = ClassName4()
    object5.print_member()
    >>>
    10
    10
    例項 {}
    類 {'__module__': '__main__', 'class_value': 10, '__init__': <function ClassName4.__init__ at 0x0000027B3F2414C0>, 'add_value': <function ClassName4.add_value at 0x0000027B3F241550>, 'print_member': <function ClassName4.print_member at 0x0000027B3F2415E0>, '__dict__': <attribute '__dict__' of 'ClassName4' objects>, '__weakref__': <attribute '__weakref__' of 'ClassName4' objects>, '__doc__': None}
    # 3. 在類外可以通過類名直接的新增屬性
    ClassName4.value2 = 1000
    print(object5.value2)  # 在類外沒有這種東西:self.value3 = 2000, self只能在類裡面使用
    >>>1000
    object5.print_member()
    >>>
    例項 {}
    類 {'__module__': '__main__', 'class_value': 10, '__init__': <function ClassName4.__init__ at 0x000001EA731D14C0>, 'add_value': <function ClassName4.add_value at 0x000001EA731D1550>, 'print_member': <function ClassName4.print_member at 0x000001EA731D15E0>, '__dict__': <attribute '__dict__' of 'ClassName4' objects>, '__weakref__': <attribute '__weakref__' of 'ClassName4' objects>, '__doc__': None, 'value2': 1000}
    
  • 類屬性的訪問方式

    # 類屬性的訪問方式(接上面一段程式碼的內容)
    object6 = ClassName4()
    >>>
    10
    10
    object6.print_member()
    >>>
    例項 {}
    類 {'__module__': '__main__', 'class_value': 10, '__init__': <function ClassName4.__init__ at 0x00000259999D14C0>, 'add_value': <function ClassName4.add_value at 0x00000259999D1550>, 'print_member': <function ClassName4.print_member at 0x00000259999D15E0>, '__dict__': <attribute '__dict__' of 'ClassName4' objects>, '__weakref__': <attribute '__weakref__' of 'ClassName4' objects>, '__doc__': None}
    # 可以使用 類名 或 例項名 直接點出屬性進行訪問類
    print(object6.class_value)
    >>>10
    print(ClassName4.class_value)
    >>10
    
    # 不能通過例項.類屬性的方式修改屬性,這樣的操作會創建出一個和類屬性同名的例項屬性,不管是修改還是訪問類屬性都推薦使用類名進行操作
    object6.class_value = 1515
    object6.print_member()
    >>>
    例項 {'class_value': 1515}# 果然創建出一個和類屬性同名的例項屬性
    類 {'__module__': '__main__', 'class_value': 10, '__init__': <function ClassName4.__init__ at 0x00000261AC2314C0>, 'add_value': <function ClassName4.add_value at 0x00000261AC231550>, 'print_member': <function ClassName4.print_member at 0x00000261AC2315E0>, '__dict__': <attribute '__dict__' of 'ClassName4' objects>, '__weakref__': <attribute '__weakref__' of 'ClassName4' objects>, '__doc__': None}
    
    2.3 self 的作用
    • self 用於標識當前函式是被誰呼叫的,self實際上就是物件的地址 id(object) ,可以進行訪問
  # self 的作用
class ClassName5(object):
  
      # 建構函式,用於初始化例項屬性
      def __init__(self, value):
          self.value = value
  
      # 訪問例項屬性的方法
    def visit_value(self):
          print(hex(id(self)), self.value)
  
  # 對於每一個例項(物件)來說,函式使用的都是相同的,但是例項屬性歸屬於每一個例項自己,函式是通過self區分當前需要用到的資料到底是屬於誰的
  
  object7 = ClassName5(100)
    object8 = ClassName5(200)
    object7.visit_value()
    >>>0x1bb49968400 100
    object8.visit_value()
    >>>0x1bb49a52760 200
   
    # 上面的函式呼叫可以看作 ClassName5(id(object8), 引數)
    print(hex(id(object7)), type(object7))
    >>>0x229bead8400 <class '__main__.ClassName5'>
    print(hex(id(object8)), type(object8))
    >>>0x229bebc1760 <class '__main__.ClassName5'>
  

1、self是什麼
在python的類中self代表例項本身,具體來說,是該例項的記憶體地址。
在呼叫例項的方法時,Python直譯器會自己把例項!!變數!!傳給類的函式中的self。
以上述程式碼I為例,程式碼I定義了一個類Test,在這個類中,self為引數變數,在類Test例項化得到例項ins時,python直譯器自動呼叫__init__,執行Test.init(ins, 123),該self可接收例項ins的記憶體地址,從而self代表了例項本身。類似的,如果例項化ins後,執行ins.fun1( ),python直譯器會將ins.fun1( )解釋成Test.fun1(ins)。可見,self這個變數是無需使用者手動傳送值的,直譯器會自動幫我們給其傳遞例項。
需要注意的是,self不是關鍵字,換言之,可以用其它的合法變數名替換self,但是,規範和標準建議我們一致使用self。

2、self的使用場景
在類中,self的使用有下面3個場景:
1)self為類中的函式的第一個引數,例如在類中,def fun1(self, …)。
上文說過,“在呼叫例項的方法時,Python直譯器會自己把例項變數傳給類的函式中的self”,如果類的函式的第一個引數不是代表例項的self,則呼叫例項的方法時,該方法沒有引數接收直譯器自動傳入的例項變數,從而程式會產生異常。
事實上,“和普通的函式相比,在類中定義的函式只有一點不同,就是第一個引數永遠是例項變數self,並且,呼叫時,不用傳遞該引數。除此之外,類的方法和普通函式沒有什麼區別,所以,你仍然可以用預設引數、可變引數、關鍵字引數和命名關鍵字引數”(廖雪峰老師說的)。

​ 2)在類中,引用例項的屬性,示例:self.變數名(如self.val0)。
引用例項的屬性的目的是為例項繫結屬性、寫入或讀取例項的屬性。
例如,在程式碼I中,在類的函式__ init __中,“self.val1 = val1”將屬性val0繫結到了例項self(類例項化成ins後,self就代表例項ins了)上,並且將變數val1的值賦給了例項的屬性val0。在函式fun1中,print(self.val0),讀取了例項self的值val0,並打印出來,當然,在函式中修改屬性val0的值也是可以的。

​ 3)在類中,呼叫例項的方法,例如,self.fun1();獲取例項的方法的地址,例如self.fun1。
類是抽象的模板,而例項是根據類創建出來的一個個具體的“物件”,每個物件都擁有相同的方法,但各自的資料可能不同。既然,self代表例項,則可以“self.函式名”的方式表示例項的方法地址,以“self.函式名()”的方式,呼叫例項的方法。在類的定義中,以及例項化後對例項方法的呼叫,都可以這樣做。

3、python的幾種變數——按作用域分
a、全域性變數:在模組內、在所有函式外面、在class外面,這就是全域性變數。
b、區域性變數:在函式內、在class的方法內(未加self修飾的) ,這就是區域性變數
c、靜態變數(也可以說,類屬性):在class內的,但不在class的方法內的,這就是靜態變數
d、例項變數(也可以說,例項屬性):在class的方法內的,用self修飾的變數,這就是例項變數

4、self和變數的關係
綜合上述的1、2和3點,可以得到在類中,self和變數的關係了,一言以蔽之,被self修飾的變數是例項變數,不被self修飾的變數不是例項變數。
例項變數有什麼作用,或者說,什麼時候應該使用self修飾變數比較好?我的總結如下:
當我們想將某個變數繫結給例項時,就在類中,使用self修飾該變數。一般來說,類例項化為不同例項後,為了不同例項的某一變數互不干擾,就將該變數繫結給例項。

2.4 訪問屬性控制
2.4.1 單下劃線:檔案保護變數
# 當一個模組內的變數以單下劃線開頭,則表示這個變數不希望被其它檔案訪問,以 from m import * 的方式就訪問不到這個變數,其它的變數可以照常訪問
from module import *
# print(_protected_value)
print(normal_value)

# 通過 import 和 from m import v 的方式都可以照常訪問
import module
print(module._protected_value)

from module import _protected_value
print(_protected_value)
2.4.2 雙下劃線:私有成員
  # 通過程式碼來了解python 中的保護屬性
  class ClassName6(object):
      # 以雙下劃線開頭的是私有屬性,不能被外界直接訪問
      __value = 12341515
  
  # 私有屬性實際就是被直譯器改頭換面換了名字,具體的格式如下: _ + 類名 + 雙下劃線開頭的屬性名,寫成這樣任然可以訪問
  # 改變類的私有變數的值有2種方法:
  # 	間接:為這個私有變數提供一個操作的方法,如:def get_score(self, score)
  # 	直接:例項名._類名__私有變數名 = 值, 如:f._Student__score = 10

  print(ClassName6._ClassName6__value)
  >>>12341515
  # 在 python 中,單下劃線開頭的屬性約定俗稱通常是不需要
  # 被外界訪問的,在寫程式碼或使用第三方庫的時候,不要修改
  # 和而訪問其它模組中的屬性

2.3魔術方法

__complex__(self)	定義當被 complex() 呼叫時的行為(需要返回恰當的值)
__int__(self)	定義當被 int() 呼叫時的行為(需要返回恰當的值)
__float__(self)	定義當被 float() 呼叫時的行為(需要返回恰當的值)
__round__(self[, n])	定義當被 round() 呼叫時的行為(需要返回恰當的值)
__index__(self)	1. 當物件是被應用在切片表示式中時,實現整形強制轉換
	2. 如果你定義了一個可能在切片時用到的定製的數值型,你應該定義 __index__
  3. 如果 __index__ 被定義,則 __int__ 也需要被定義,且返回相同的值
	上下文管理(with 語句)
__enter__(self)	1. 定義當使用 with 語句時的初始化行為
	2. __enter__ 的返回值被 with 語句的目標或者 as 後的名字繫結
__exit__(self, exc_type, exc_value, traceback)	1. 定義當一個程式碼塊被執行或者終止後上下文管理器應該做什麼
	2. 一般被用來處理異常,清除工作或者做一些程式碼塊執行完畢之後的日常工作
 容器型別	
__len__(self)	定義當被 len() 呼叫時的行為(返回容器中元素的個數)
__getitem__(self, key)	定義獲取容器中指定元素的行為,相當於 self[key]
__setitem__(self, key, value)	定義設定容器中指定元素的行為,相當於 self[key] = value
__delitem__(self, key)	定義刪除容器中指定元素的行為,相當於 del self[key]
__iter__(self)	定義當迭代容器中的元素的行為
__reversed__(self)	定義當被 reversed() 呼叫時的行為
__contains__(self, item)	定義當使用成員測試運算子(in 或 not in)時的行為