日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python学习(六)

發布時間:2024/1/18 python 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python学习(六) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

魔法方法

在python中,有一些內置好的特定的方法,這些方法在進行特定的操作時會自動被調用,稱之為魔法方法。

構造和析構

魔法方法總是被雙下橫線包圍,例如__init__;
是面向對象的Python的一切;
他們總是能在適當的時候被調用。

  • __init__(self[, …])
    相當于其他編程語言的構造方法,類在實例化對象的時候首先會調用的一個方法。

  • __new__(cls[, …])
    init并不是實例化對象調用的第一個方法,new方法才是,它的第一個參數是cls,通常情況下是返回cls類的對象,也可以返回其他類的對象。
    new方法是極少去重寫它的,Python會默認執行,但是當需要繼承一個不可變類型又需要修改的時候,那么就需要重寫了。

  • __del__(self)
    當對象將要被銷毀的時候這個方法會自動被調用,但是

del x 并不等于調用了 x.__del__()

del方法是當垃圾回收機制,即當沒有任何變量去引用這個對象的時候,垃圾回收機制會自動銷毀,這時才會調用對象的self方法。

注意:內置的__del__()方法并不是發生del操作的時候就會調用,當對象生成后,所有對它的引用都被del后才會啟動垃圾回收機制,才會調用__del__()方法。

算數運算

在Python2.2之前類和類型是分開的,類是屬性和方法的封裝,類型是如整型、浮點型、字符串這些類型,但是在Python2.2后,試圖對兩者進行統一,做法就是將int、float、string、list、tuple這些內置函數通常轉化為工廠函數。

  • 什么是工廠函數

參考



原因: 當a+b,識別到加法會先調用前者a的add,返回self+other,即返回了a+b,就又運行了加法add,進入了無限遞歸。
所以在實現的時候,一定要注意避免出現無限遞歸的情況。
稍作修改

  • 一些算數運算
方法相應二元算數運算符
__add__(self, other)定義加法的行為:+
__sub__(self, other)定義減法的行為:-
__mul__(self, other)定義乘法的行為:*
__truediv__(self, other)定義真除法的行為:/
__floordiv__(self, other)定義整數除法的行為://
__mod__(self, other)定義取模算法的行為:%
__divmod__(self, other)定義當被divmod()調用時的行為【divmod(a, b)返回值是一個元組(a//b, a%b)】
__pow__(self, other[, modulo])定義當被pow()調用或**運算時的行為
__lshift__(self, other)定義按位左移位的行為:<<
__rshift__(self, other)定義按位右移位的行為:>>
__and__(self, other)定義按位與操作的行為:&
__xor__(self,other)定義按位異或操作的行為:^
__or__(self, other)定義按位或操作的行為:|

通過對指定魔法方法的重寫,可以讓Python根據自己的意圖來實現程序

魔法方法參考

  • 反運算

    這里是3-1,并不是1-3,如果想讓1-3,那么就要互換int.sub()中self, other的位置,舉例說明

定制一個簡單的類

  • 需要的資源
    (1)使用time模塊的localtime方法獲取時間

time模塊詳解


(2)time.localtime返回struct_time的時間格式
(3)表現你的類:重寫__str__和__repr__

  • 程序MyTimer
import time as tclass MyTimer():def __str__(self):return self.prompt__repr__ = __str__# 開始計時def start(self):self.start = t.localtime()print("計時開始...")# 停止計時def stop(self):self.stop = t.localtime()self._calc()print("計時結束...")# 內部方法,計算運行時間def _calc(self):self.lasted = []self.prompt = "總共運行了"for index in range(6):self.lasted.append(self.stop[index] - self.start[index])self.prompt += str(self.lasted[index])


但是這里有一個問題就是,如果定以后直接調用,就會報錯

因為這時,prompt還沒有被定義,這時就需要所有屬于實例對象的變量先在init中定義

import time as tclass MyTimer():# 添加init定義def __init__(self):self.prompt = "未開始計時!"self.lasted = []self.start = 0self.stop = 0def __str__(self):return self.prompt__repr__ = __str__# 開始計時def start(self):self.start = t.localtime()print("計時開始...")# 停止計時def stop(self):self.stop = t.localtime()self._calc()print("計時結束...")# 內部方法,計算運行時間def _calc(self):self.lasted = []self.prompt = "總共運行了"for index in range(6):self.lasted.append(self.stop[index] - self.start[index])self.prompt += str(self.lasted[index])


這時在執行雖然不會直接調用t1出錯了,但是運行起來卻又出現“整型不能被調用”問題,這里是由于在init中將self.start定義為0導致,因為類的方法名和屬性名一樣時,屬性會覆蓋方法,這里就認為start是屬性。
這時只需要將start和stop改一下名字即可
并且在這里改變一下顯示的方式和累加計時

import time as tclass MyTimer():def __init__(self):self.unit = ['年', '月', '天', '小時', '分鐘', '秒']self.prompt = "未開始計時!"self.lasted = []self.begin = 0self.end = 0def __str__(self):return self.prompt__repr__ = __str__def __add__(self, other):prompt = "總共運行了"result = []for index in range(6):result.append(self.lasted[index] + other.lasted[index])if result[index]:prompt += (str(result[index]) + self.unit[index])return prompt# 開始計時def start(self):self.begin = t.localtime()self.prompt = "提示:請先調用 stop() 停止計時!"print("計時開始...")# 停止計時def stop(self):if not self.begin:print("提示:請先調用start()進行計時!")else:self.end = t.localtime()self._calc()print("計時結束...")# 內部方法,計算運行時間def _calc(self):self.lasted = []self.prompt = "總共運行了"for index in range(6):self.lasted.append(self.end[index] - self.begin [index])if self.lasted[index]: # 為0不顯示 self.prompt += str(self.lasted[index]) + self.unit[index]# 為下一輪計時初始化變量self.begin = 0self.end = 0

  • 代碼存在的問題
    (1)生成的時間會存在負數的情況

    (2)精度不夠,只能到秒

屬性訪問

(1)直接訪問屬性
(2)通過getattr()訪問

(3)利用property(),以屬性的方式訪問屬性

  • __getattr__(self, name)
    定義當用戶試圖獲取一個不存在的屬性時的行為
  • __getattribute__(self, name)
    定義當該類的屬性被訪問時的行為
  • __setattr__(self, name, value)
    定義當一個屬性被設置時的行為
  • __delattr__(self, name)
    定義當一個屬性被刪除時的行為
>>> class C:def __getattribute__(self, name):print("getattribute")return super().__getattribute__(name)def __getattr__(self, name):print("getattr")def __setattr__(self, name, value):print("setattr")super().__setattr__(name, value)def __delattr__(self, name):print("delattr")super().__delattr__(name)

  • 練習
class Rectangle:def __init__(self, width=0, height=0):self.width = widthself.height = heightdef __setattr__(self, name, value):if name == 'square':self.width = valueself.height = valueelse:self.name = valuedef getArea(self): # 獲得面積return self.width * self.height # 輸入 r1 = Rectangle(4, 5) # 這樣寫會出現一個無限遞歸,因為執行__init__中的self.width和self.height賦值語句,會觸發__setattr__中的else后的語句self.name = value,再重復調用__setattr__,這樣就會無限遞歸下去 # ===================================================================================================== # 下面進行改進 class Rectangle:def __init__(self, width=0, height=0):self.width = widthself.height = heightdef __setattr__(self, name, value):if name == 'square':self.width = valueself.height = valueelse:super().__setattr__(name, value)def getArea(self): # 獲得面積return self.width * self.height


另一種改進方法就是給一個特殊屬性dict,dict是以字典的形式顯示出當前對象的所有屬性以及對應的值

class Rectangle:def __init__(self, width=0, height=0):self.width = widthself.height = heightdef __setattr__(self, name, value):if name == 'square':self.width = valueself.height = valueelse:self.__dict__[name] = valluedef getArea(self): # 獲得面積return self.width * self.height

描述符

描述符就是將某種特殊類型的類的實例指派給另一個類的屬性。

__get__(self, instance, owner) # 用于訪問屬性,返回屬性的值 __set__(self, instane, value) # 將在屬性分配操作中調用,不返回任何內容 __delete__(self, instance) # 控制刪除操作,不返回任何內容
  • 實例
class MyDescriptordef __get__(self, instance, owner):print("getting...", self, instance, owner)def __set__(self, instance, value):print("setting...", self, instance, value)def __delete__(self, instnce):print("deleting...", self, instance)class Test:x = MyDescriptor()

【ps:這里改用spyder編輯了,輸入處顯示方式改變,實際操作同python idle相同】
這里就是將某種特殊類型的類(MyDescriptor)的實例(MyDescriptor())指派給另一個類(Test)的屬性(x),就說明MyDescriptor就是x的描述符。

實例化對象后,用text.x強制打印
可以看到打印出三個參數,第一個是self的參數描述符類MyDescriptor本身的實例,第二個是instance的參數類的擁有者Test的實例test,第三個就是擁有者類Test本身
驗證一下


對實例化對象進行賦值,出現賦值調用set的特殊方法,打印self、instance和value

del同理,打印self和instance

  • 定義一個MyProperty
    之前提到的property其實就是一個描述符
class MyProperty:def __init__(self, fget=None, fset=None, fdel=None):self.fget = fgetself.fset = fsetself.fdel = fdeldef __get__(self, instance, value):return self.fget(instance)def __set__(self, instance, value):self.fset(instance, value)def __delete__(self, instance):self.fdel(instance)class C:def __init__(self):self._x = Nonedef getX(self):return self._xdef setX(self, value):self._x = valuedef delX(self):del self._xx = MyProperty(getX, setX, delX)


同樣的這里將MyProperty的實例MyProperty()指派給類C的屬性x,對類C的實例對象c的x屬性賦值,調用setX返回c._x再進行操作。

  • 練習
class Celsius:def __init__(self, value = 26.0):self.value = float(value)def __get__(self, instance, owner):return self.valuedef __set__(self, instance, value):self.value = float(value)class Fahrenheit: def __get__(self, instance, owner):return instance.cel * 1.8 +32def __set__(self, instance, value):instance.cel = (float(value) - 32) / 1.8class Temperature:cel = Celsius()fah = Fahrenheit()

定制容器

  • 協議
    協議Protocols相似于接口,規定了必須要定義的方法。而在Python中協議更像是一種指南。
  • 容器類型的協議
    (1)定制不可變容器
    只需定義__len__()和__getitem__()方法
    (2)定制可變容器
    除__len__()和__getitem__()方法外,還需定義__setitem__()和__delitem__()兩個方法

Python魔法方法詳解

  • 練習
    編寫一個不可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
class CountList:def __init__(self, *args): # 星號代表參數是可變數量的self.values = [x for x in args] # 依次取列表中元素self.count = {}.fromkeys(range(len(self.values)),0)# fromkeys 用于創建一個新字典def __len__(self):return len(self.values)def __getitem__(self, key):self.count[key] += 1return self.values[key]

迭代器

提供迭代方法的容器稱之為迭代器。
通常的迭代器有序列、列表、元組、字符串、字典、文件。

  • for語句迭代
  • 字典迭代
  • 關于迭代操作,Python提供了兩個BIF內置函數inter()和next()
    inter() 即iteration
    對于容器對象調用iter就得到它的迭代器,調用next()就會返回下一個值,當迭代器沒有值可以返回了,Python就會拋出一個“StopIteration”的異常,此時迭代結束。

    這樣就可以知道for語句是如何執行的
    利用while語句來模擬for語句的執行
  • 迭代器的魔法方法
# 兩個魔法方法分別對應兩個BIF容器的實現 iter() --> __iter__() # 返回迭代器本身 next() --> __next__() # 決定迭代器的迭代規則
  • 實現斐波那契數列的打印
class Fibs:def __init__(self, n=10):self.a = 0self.b = 1self.n = ndef __iter__(self):return selfdef __next__(self):self.a, self.b = self.b, self.a + self.bif self.a > self.n:raise StopIterationreturn self.a


生成器

生成器并不涉及魔法方法、類和對對象,只通過普通的函數實現。生成器實際上是迭代器的一種實現。
生成器延續了Python簡潔的特點,并且使協同程序的概念得以實現,協同程序就是可以運行的獨立函數調用,函數可以暫?;驋炱?#xff0c;并在需要的時候從程序離開的地方繼續或者重新開始。

Generator 實例

def myGen():print("生成器被執行!")yield 1yield 2# 一旦一個函數中出現yield語句# 那么就說明這個函數被定義為生成器# yield就相當于普通函數中的return# 和return的區別:# 出現yield,就將yield后的參數返回,并暫停在yield處

  • 實現斐波那契數列
def libs():a = 0b = 1while True:a, b = b, a + byield a # 由于有yield,所以while True不會變成死循環

  • 推導式
    (1)列表推導式

    (2)字典推導式

    有“:”的是字典,沒有的是集合
    (3)集合推導式

    (4)沒有字符串推導式

    (5)元組(tuple)推導式

    打印元組e發現e是一個生成器推導式

    生成器推導式如果作為函數的參數,是可以直接寫推導式,不需要加括號
    【100以內不能被2整除的整數和】

[擴展閱讀] 提高你的 Python:解釋 yield 和 Generators(生成器)

總結

以上是生活随笔為你收集整理的Python学习(六)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。