1. 程式人生 > >Python學習筆記:檔案操作、類基礎、派生與繼承入門

Python學習筆記:檔案操作、類基礎、派生與繼承入門

#檔案操作open、close
    開啟一個檔案供讀寫
    file = open(file, mode=xx)
    
    用完之後一定要記得關閉
    file.close()

#檔案的方法:
    file.readline():通常只對文字檔案進行讀取,讀到檔案為返回空字串,會返回回車符等轉義字元
    file.readlines(lines):讀取 lines 行的資料,返回每一行資料字串組成的列表
    file.read(size):讀取指定位元組數的資料,返回每個位元組字元組成的列表
    file.read():讀取檔案中所有剩餘的位元組數,返回一個大的字串
    file.writelines([a,b,c]):將字串列表寫入檔案,不自動加回車
    file.flush():將緩衝區的檔案緩衝寫入磁碟
    

#檔案的開啟方式
    't':文字檔案方式開啟
    'r':只讀,預設值
    'w':只寫,刪除原始檔內容;若不存在則建立
    'x':建立一個新檔案,並以寫模式開啟這個檔案
    'a':以只寫模式開啟一個檔案,在原檔案後面追加

#二進位制檔案
    檔案中以位元組為儲存的單位,不以字元為單位進行儲存的檔案
    以bytes進行儲存    

#二進位制檔案操作方法
    開啟時用模式'b'開啟
    file.read(size=-1):讀取二進位制檔案size位元組,而不是size個字元
    
#位元組串,也叫位元組序列bytes
    作用:儲存以位元組為單位的資料
    位元組串是不可變的位元組序列
    位元組串中每個元素是0-255之間的整數

#位元組串操作
    建立新的位元組串:b''
    建立非空位元組串:b'ABCD' b"ABCD" b"""ABCD""" b'''ABCD''' b'\x41\x11'

#位元組串的生成函式
    bytes():生成一個空位元組串等同於b''
    bytes(整型list):用可迭代物件初始化一個字串
    bytes(整數n):生成值為0,長為n的位元組串
    bytes(str,encoding='utf-8')
    
#位元組串的運算
    + += * *=    和字串完全相同
    < <= > >= == !=
    in / not in
    索引/切片

#bytes與str的區別
    bytes儲存位元組(0-255)
    str儲存Unicode字元(0-65536)    
    可以相互轉換
    b = s.encode(encoding='utf-8')
    s = b.decode(encoding='utf-8')

#位元組陣列bytearray
    可變的位元組序列
#bytearray建立函式
    bytearray():建立空的位元組陣列
    bytearray(整數n):建立長度為n的、值為0的位元組陣列
    bytearray(整數可迭代物件)
    bytearrar(字串,encoding="utf-8)

#bytearray操作方式與list完全相同
    + += * *=
    < <= > >= == != 
    in / not in
    索引/切片

#檔案讀寫其他方法
    file.tell():返回當前檔案流的絕對位置
    file.seek(offset, whence = 0):
        改變檔案指標的位置,相對於whence位置改變offset
        whence:0:檔案頭    1:當前檔案指標位置    2:檔案末尾

#sys.stdin stdout stderr
    這三個檔案一開始就已經加入緩衝區
    sys.stdout是一個物件,綁定了一個檔案流物件,可以用檔案流檔案的所有方法
        print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
        向file的檔案流物件中寫入資料,flush代表立即寫入檔案還是寫入緩衝區
    sys.stderr是一個物件,綁定了一個錯誤流檔案,向該檔案寫錯誤資訊,包括raise觸發的錯誤


#重定向
    python test.py 2> a.txt

      檔案        檔案描述符 
    輸入檔案    0
    輸出檔案    1
    錯誤輸出檔案    2

#練習:實現檔案拷貝
def file_copy(src, dst, new_name):
    src_file = open(src, 'rb')
    if not dst.endswith('/'):
        dst += '/'+ new_name
    else:
        dst += new_name

    dst_file = open(dst,'wb')

    while True:
        read_data = src_file.read(1000)
        if read_data == b'':
            break
        print("write %d bytes", dst_file.write(read_data))

    src_file.close()
    dst_file.close()

import os,sys

if len(sys.argv) != 4:
    raise ValueError("This function need 3 param, %d is given" % (len(sys.argv)-1))

file_copy(sys.argv[1], sys.argv[2], sys.argv[3])

#呼叫方式:python test.py ./file.txt ./copy_test/ new_copy_file.txt
#註釋:python  test.py  原始檔目錄+檔名  目標檔案路徑  目標檔案檔名
    

#類class
    類是同來描述物件屬性和行為的工具,用類可以建立物件

#類的建立
    class class_name(繼承列表):
        """文件字串
        """
        例項方法
        類變數
        類方法@aclassmethod
        靜態方法@staticmethod
    說明:
    類名必須是識別符號
    類名實質上就是變數,它綁定了一個類
    (潛規則)類的定義後要加兩個空行,告訴直譯器類定義完成;否則在極少數情況下無法解析
    
    例項物件建立:類名(傳參列表)
    
    例項有自己的名字空間,可以為一個例項新增變數(例項變數/方法)

#新增例項物件(直接新增即可)
    class Cat():
        pass
    cat1 = Cat()
    cat1.kinds = "erha"
    #首次賦值建立例項變數,再次賦值改變引用關係
    
#刪除例項變數
    del 例項.變數
#刪除例項
    del 例項

#del作用總結
    1、刪除變數
    2、刪除列表中元素    
    3、刪除字典中鍵值對
    4、刪除例項屬性

#例項方法
    class class_name(繼承列表):
        def 例項方法名(self, argv1, argv2, ...):
            """文件字串
            """
            語句塊
    說明:
    例項方法第一個引數代表自己,一般用self命名

#呼叫例項方法
    例項.方法(引數列表)
    或
    類名.方法(例項,引數列表)

#初始化方法
    作用:建立物件時進行初始化
    語法:
    class class_name(繼承列表):
        def __init__(self[,引數列表]):
            語句塊
    說明:
    1、初始化方法名必須為__init__
    2、一個類中只能有一個__init__方法
    3、在例項建立後自動呼叫    
    4、如果需要return,必須return None

#階段示例:

class Animal():
    def __init__(self, str_name):
        self.name = str_name

    def eat(self, food_name):
        print("%s is eating %s" % (self.name, food_name))
    def drink(self, drink_name):
        print("%s is drinking %s" % (self.name, drink_name))

cat = Animal("cat")
dog = Animal("dog")

cat.eat("cookie")
dog.drink("orange")

#類變數
    在class中建立的變數,屬於這個類,不屬於此類的例項
    類變數可以通過該類直接訪問
    類變數可以通過類的例項間接訪問
    類變數可以通過例項的__class__屬性間接訪問

    示例:
    class Animal():
        type_num = 0
    cat = Animal()
    print(Animal.type_num)
    print(cat.type_num)    #這種方法得到的name只是其引用,只能對其操作,但是不能用=,=會更改繫結關係,相當為cat建立例項變數type_num
    print(cat.__class__.type_num)


#預製的例項屬性
    __dict__屬性:繫結一個儲存此例項變數(屬性)的字典
    示例:cat = Cat()
    cat.name = 'cat'
    則cat.__dict__ 為 {'name':'dog'}
    
    __class__屬性:繫結建立此例項的類物件
    例項:cat = Cat()
    cat.name = 'cat'
    則cat.__class__ 為 <class '__main__.Animal'>
    作用:藉助此屬性建立同類物件(基本沒用)    
        藉助此屬性訪問類變數
    
    __doc__屬性:繫結文件字串
    
    __slots__列表:
    作用:
    1、限定一個類建立的例項只能由固定的例項變數
    2、不允許物件新增此列表以外的例項屬性
    3、防止使用者因寫錯屬性名,引發錯誤
    說明:
    含有__slots__列表的類所建立的例項物件沒有__dict__字典,即此例項不用字典來儲存例項變數
    class Student():
        __slots__ = ["name", "age"]
    s.name = 'asd' #對的
    s.Name = 'asd' #報錯

#關於類的系統內建函式
    isinstance(obj, class_or_tuple)    返回該物件的obj是否是某個或者某些類其中的一個類建立的,如果是,返回True;否則返回Flase
    
    type(obj):返回例項的型別

#類的類方法:僅屬於類的方法,要用@classmethod來修飾;類方法只能訪問類變數
    第一個方法預設是類,約定為cls
    
    說明:類和例項物件都能夠呼叫類內的方法
        類方法不能訪問物件的例項變數
    class A:
        v = 0
        @classmethod
        def set_v(cls,value)
            cls.v = value
    A.set_v(100)    
    
    例項變數也可以建立同名的類變數,但是會為例項建立一個新變數

#靜態方法:
    用@staticmethod修飾器來修飾
    不能傳入self / cls, 只能定義在函式內部
    類和例項都可以呼叫,不能訪問類變數和例項變數    
    示例:
    class A():
    @staticmethod
        def mymax(a,b):
            return max(a,b)
    A.max(10,11)
    a = A()
    a.max(999,1000)

    相當於普通函式,但是隻能通過類或者例項呼叫
    也可以防止重名

#物件屬性管理函式
    getaddr(obj, name[, default]):getaddr(x, y, default)相當於獲取x.y,如果不存在返回default,為給定default時,報錯
    
    hasaddr(obj, name):判斷給定例項有沒有該屬性
    
    setaddr(obj, name, value):設定obj.name = value

    deladdr(obj, name):刪除物件obj中的name屬性,相當於del obj.name

#函式重寫 overwrite
    讓自定義的類生成的物件(例項)能夠像內建物件一樣進行內建函式的操作

#重寫str方法
    使得str(obj)能夠返回一個代表例項資訊的字串
    示例:
    class Student():
        def __init__(self, n, a):
            self.name = n
            self.age = a
        def __str__(self):
            s = "%s is %d years old this year" % (self.name, self.age)
            return s
    a = Student("xiaozhang", 32)
    print(a)
    #或者str(a)
    >>>xiaozhang is 32 years old this year

#repr & str
    str(obj)將物件轉換為字串給人看
    repr(obj)返回建立物件的表示式,可以用於遠端傳輸物件
    如果str物件沒有重寫,呼叫repr返回的結果
    
    示例:
    class Student():
        def __init__(self, n, a):
            self.name = n
            self.age =a
        def __str__(self):
            s = "%s is %d years old this year" % (self.name ,self.age)
            return s
        def __repr__(self):
            return "Student(%r, %d)" % (self.name, self.age)
        #在repr重寫時,用%r輸出字串

    a = Student("xiaozhang", 32)
    print(a)
    print(str(a))
    print(repr(a))

    結果為:
    xiaozhang is 32 years old this year    
    xiaozhang is 32 years old this year
    Student(xiaozhang, 32)

#內建函式重寫
    __abs__ -> abs(obj)
    __len__ -> len(obj)
    __reversed__ -> reversed()
    __round__ round(obj)
    #不重寫用不了
    
    數值轉換重寫
    __complex__
    __int__
    __float__
    __bool__
    


#__bool__方法重寫:
    如果沒有重寫,將呼叫__len__方法;如果沒有__len__方法,返回true
    
#高階迭代器

    什麼是迭代器:通過next(it)函式取值的物件就是迭代器

    迭代器協議:指物件能夠使用next函式取下一項資料,在沒有下一項資料是出啊發StopIterable異常來終止迭代的約定
    
    迭代器協議的實現方法:
    在類中需要__next__(self)函式重寫


程式碼:
class IntIterator():
    def __init__(self, start_, stop_, step_ = 1):
        self.start = start_
        self.stop = stop_
        if step_ == 0:
            raise ValueError("step_ cannot be 0")
        self.step = step_

    def __next__(self):
        if self.step < 0:
            if self.start + self.step >= self.stop:
                self.start += self.step
                return self.start - self.step
            raise StopIteration
        if self.step > 0:
            if self.start + self.step <= self.stop:
                self.start += self.step 
                return self.start - self.step
            raise StopIteration

it = IntIterator(1,13,1)
while True:
    try:
        print(next(it))
    except:
        break
        

#什麼是可迭代物件:
    用iter(obj)函式返回的物件
    可迭代物件內部需要定義__iter__(obj)方法來返回迭代器物件
    可迭代物件能用於for迴圈,而迭代器不能
    可迭代物件的存在就是為了在for迴圈中方便的使用,for迴圈自動呼叫可迭代物件類中的__iter__()方法,然後用next函式獲取迭代器下一個值,且產生StopIteration時不會觸發異常

#示例程式碼:
class IntIterator():
    def __init__(self, start_, stop_, step_ = 1):
        self.start = start_
        self.stop = stop_
        if step_ == 0:
            raise ValueError("step_ cannot be 0")
        self.step = step_

    def __next__(self):
        if self.step < 0:
            if self.start + self.step >= self.stop:
                self.start += self.step
                return self.start - self.step
            raise StopIteration
        if self.step > 0:
            if self.start + self.step <= self.stop:
                self.start += self.step 
                return self.start - self.step
            raise StopIteration

class MyInteger():
    def __init__(self, start_num, stop_num):
        self.start = start_num
        self.end = stop_num
    def __iter__(self):
        return IntIterator(self.start, self.end)

for x in MyInteger(10,20):
    print(x)

前面的簡單的yeild迭代器函式,會被轉化為一個可迭代物件類


#異常(高階)
#with語句
    with 表示式1 [as 變數1], 表示式2 [as 變數2] ...:
        語句塊
    作用:用於對資源訪問的場合,確保過程中是否發生錯誤都能夠執行必要的資源釋放工作
    
    用處:常用於檔案的開啟和關閉,執行緒中鎖的自動獲取與釋放

例子:with語句實現拷貝檔案

def file_copy(src, dst):
    with open(src, 'rb') as src_file, open(dst, 'wb') as dst_file:
        data = src_file.read(1000)
        if data == '':
            return 
        dst_file.write(data)

import sys
if len(sys.argv) != 3:
    raise ValueError("Script only takes and only takes 4 arguments")
file_copy(sys.argv[1], sys.argv[2])


#技巧:文字檔案流檔案也是一個可迭代物件,可以用
    for x in file:
    x代表一行

#環境管理器
    1、有__enter__和__exit__方法的類所生成的物件叫做環境管理器
    2、能夠用with語句進行管理的物件必須是環境管理器
    3、進入with語句時,自動呼叫__enter__()並將返回的物件給as的變數,所以__enter__()必須返回一個該類物件self;退出with語句時,自動呼叫__exit__()方法;
    4、__exit__(self, exc_type, exc_value, exc_tb):當退出時自動呼叫
      如果發生了異常,exc_type繫結異常型別,exc_value繫結物件
      沒有發生異常時,exc_type繫結None,exc_value繫結None
      exc_tb繫結traceback 一般不用
示例:
class Cooker():
    def doworks(self):
        print("Doing work")

    def open_gas(self):
        print("Opening gas")

    def close_gas(self):
        print("Closing gas")
    
    def __enter__(self):
        self.open_gas()
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        self.close_gas()

with Cooker() as cook:
    raise ValueError

#繼承、派生
    作用:
    1、將類的公有功能實現在基類中,實現程式碼共享
    2、不改變超類的程式碼的基礎上,改變原有類的功能

#名詞
    基類(base class)= 超類(super class)= 父類(father class)
    派生類(derived class) = 子類(child class)

#單繼承語法
    class class_name(父類):
        ...

#示例程式碼:
class Human():
    def eat(self):
        print("Eating")
    def walk(self):
        print("Walking")

class Student(Human):
    def study(self ):
        print("Studying")
    def eat(self):
        print("Student is eating")

s = Student()
s.eat()
s.study()
s.walk()

#將類的公有功能實現在基類中,實現程式碼共享:Student可以使用Human的方法
#不改變超類的程式碼的基礎上,改變原有類的功能:Student重寫了自己的eat方法,改變了父類的功能


#繼承說明
    一切類都繼承自object類,object類是一切類的超類

#類的__base__屬性:
    記錄該類的直系父類

#覆蓋override
    子類中重新定義父類中的方法,呼叫時呼叫重寫後的方法,這種操作叫做覆蓋,override