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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

Python面向对象、魔法方法

發(fā)布時間:2024/1/23 python 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python面向对象、魔法方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 寫在篇前
  • 封裝
  • 繼承
      • 單繼承
      • Mixin
  • 抽象
  • 多態(tài)
  • 特殊方法&屬性
      • 特殊屬性
      • 魔法方法
  • 輔助知識
      • OOP實用函數(shù)
      • 迭代器生成器

寫在篇前

??OOP(Object Oriented Programming),即面向?qū)ο蟮某绦蛟O(shè)計,不同于傳統(tǒng)的面向過程的程序設(shè)計,它大大地降低了軟件開發(fā)的難度,使編程就像搭積木一樣簡單,是當(dāng)今編程以及模式設(shè)計一股勢不可擋的潮流。OOP達(dá)到了軟件工程的三個主要目標(biāo):重用性、靈活性和擴(kuò)展性。面向?qū)ο缶幊痰幕A(chǔ)就是類,所謂“類生一,一生二,二生三,三生萬物”,類是對現(xiàn)實世界事物的抽象,一個類包括了現(xiàn)實世界中一組對象的方法和屬性。

封裝

??封裝就是把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來,通過已定義的接口實現(xiàn)對數(shù)據(jù)的訪問以及修改,屏蔽繁雜的技術(shù)細(xì)節(jié)。編寫一個類就是對數(shù)據(jù)和數(shù)據(jù)操作的封裝,可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口。如下示例代碼,即是封裝了一個Student類,包含類屬性Student_number,對象屬性__id,name,score,以及一個打印學(xué)生成績的方法print_info(),這樣實例化對象之后沒就可以直接調(diào)用print_info()方法獲取學(xué)生信息,而無需關(guān)注其實現(xiàn)細(xì)節(jié)。

#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery'class Student(object):"""Student class"""# student_number是一個類屬性, 可通過類訪問,也可通過對象訪問,所有對象共享該表量student_number = 0# 方法可有默認(rèn)參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù)def __init__(self, sid, name, score):"""Student class init method"""Student.student_number += 1self.__id = sidself.name = nameself.score = scoredef print_info(self):"""get Student info"""print('%s: %s' % (self.name, self.score), end=' ')bart = Student('001', 'Bart Simpson', 59) bart.print_score() print(bart.student_number) # 1 print(Student.student_number) # 1lisa = Student('002', 'Lisa Simpson', 87) lisa.print_score() print(bart.student_number) # 2 print(Student.student_number) # 2

繼承

??繼承是從已有類得到繼承信息創(chuàng)建新類的過程,一方面可以繼承父類所有的屬性和方法,另一方面可以增加或則重寫父類方法,以適應(yīng)具體業(yè)務(wù)流程。

單繼承

?這里緊接上面的例子,創(chuàng)建一個MasterStudent類,使其繼承Student類,這樣子類并擁有了父類的所有方法和屬性(實際上父類__init__()方法不會被繼承,這一點放到后面再討論);另外再增加新的屬性major和新的方法change_major()。

class MasterStudent(Student):"""MasterStudent class"""def __init__(self, sid, name, score, major):"""Student class init method"""super().__init__(sid, name, score)self.major = majordef print_info(self):"""get Student score"""super().print_info() # 調(diào)用父類方法print('and majoring in %s' % self.major)def change_major(self, major):"""change major"""self.major = majorif __name__ == '__main__':ms = MasterStudent('001', 'jeffery', '90', 'bio')ms.print_info()

??關(guān)于繼承,需要注意的一個問題是構(gòu)造方法(__new__)和初始化方法(__init__)的執(zhí)行順序:

class A(object):def __new__(cls, *args, **kwargs):print('A __new__')return super().__new__(cls, *args, **kwargs)def __init__(self):print('A __init__')class B(A):def __new__(cls, *args, **kwargs):print('B __new__')return super().__new__(cls, *args, **kwargs)def __init__(self):print('B __init__')super().__init__() # 輸出結(jié)果 B __new__ A __new__ B __init__ A __init__

Mixin

?Mixin是python中多繼承的一種方案,但是事實上它和一般意義上的多繼承(其他編程語言如C++)是有區(qū)別的,它更像是Java中的接口,但是是提供默認(rèn)實現(xiàn)的接口(Java接口默認(rèn)不提供實現(xiàn))。舉個例子,民航飛機(jī)是一種交通工具,對于土豪們來說直升機(jī)也是一種交通工具。對于這兩種交通工具,它們都有一個功能是飛行,但是轎車沒有。所以,我們不可能將飛行功能寫在交通工具這個父類中。但是如果民航飛機(jī)和直升機(jī)都各自寫自己的飛行方法,又違背了代碼盡可能重用的原則(如果以后飛行工具越來越多,那會出現(xiàn)許多重復(fù)代碼)。怎么辦,那就只好讓這兩種飛機(jī)同時繼承交通工具以及飛行器兩個父類,這樣就出現(xiàn)了多重繼承。這時又違背了繼承必須是”is-a”關(guān)系。這個難題該怎么破?

?下面,我們用python實現(xiàn)一下:

class Transportation(object):"""交通工具的基類"""passclass FlyMixin(object):"""Mixin 類,告訴其他人,這是一個"接口",能夠擴(kuò)充類的某一個功能"""def fly_able(self):passclass Airliner(Transportation, FlyMixin):passclass Helicopter(Transportation, FlyMixin):pass

?Mixin其實應(yīng)用非常廣泛,在django中,如某一個頁面需要登陸才允許訪問,則可以讓相應(yīng)View繼承LoginRequiredMixin

class LogoutView(LoginRequiredMixin, View):"""比如退出登陸,當(dāng)然禁止沒有登陸的用戶執(zhí)行該操作"""def get(self, request):logout(request)return HttpResponseRedirect(reverse("index"))

?看完代碼,你會很明顯的發(fā)現(xiàn)FlyMixin不就是一個普通類嗎?所謂Mixin不就是多繼承嗎?對,但是我們一般約定以Mixin結(jié)尾的類作為接口類,用來靈活擴(kuò)充類的功能。

抽象

?抽象類是一個特殊的類,它從一堆類中抽取相同的內(nèi)容,組建成一個新的類。它的特殊之處在于只能被繼承,不能被實例化。比如三角形類、正方形類、菱形類都是屬于圖形類,都應(yīng)該有邊長屬性,求面積、求周長的方法。下面舉一個實例,說明python中抽象類的使用。

class A(object):"""抽象類不能被實例化"""__metaclass__ = abc.ABCMeta@abc.abstractmethoddef load(self, _input):pass@abc.abstractmethoddef save(self, output, data):passclass B(A):def load(self, _input):return _input.read()def save(self, output, data):return output.write(data)if __name__ == '__main__':print(issubclass(B, A))print(isinstance(B(), A))print(A.__subclasses__())

?還有一種通過__subclasshook__魔法方法的用法我在這也提一下:

class C(object, metaclass=abc.ABCMeta):@abc.abstractmethoddef say(self):pass@classmethoddef __subclasshook__(cls, _cls):"""該方法意味著只要一個類實現(xiàn)了他的抽象方法,就會被認(rèn)為是該類的子類"""print('class invoke ********')if cls is C:if any("say" in B.__dict__ for B in _cls.__mro__):return Truereturn NotImplementedclass D(object):def say(self):print('function say implemented in subclass')print(issubclass(D, C)) print(isinstance(D(), C)) print(D.__dict__) print(C.__subclasshook__(D))

多態(tài)

?多態(tài)按字面的意思就是多種形態(tài)。當(dāng)類之間存在層次結(jié)構(gòu),并且類之間是通過繼承關(guān)聯(lián)時,就會用到多態(tài),多態(tài)意味著調(diào)用成員函數(shù)時,會根據(jù)調(diào)用函數(shù)的對象的類型來執(zhí)行不同的函數(shù)。

class Car:def __init__(self, name):self.name = namedef drive(self):raise NotImplementedError("Subclass must implement abstract method")def stop(self):raise NotImplementedError("Subclass must implement abstract method")class SportsCar(Car):def drive(self):return 'SportsCar driving!'def stop(self):return 'SportsCar breaking!'class Truck(Car):def drive(self):return 'Truck driving slowly because heavily loaded.'def stop(self):return 'Truck breaking!'cars = [Truck('Bananatruck'),Truck('Orangetruck'),SportsCar('Z3')]for car in cars:print(car.name + ': ' + car.drive())

?但是,如果你仔細(xì)看完上面的代碼,似乎你覺得并沒有什么特殊之處。因為,Python 沒有覆寫(override)的概念,也就是說嚴(yán)格來講,Python 并不支持多態(tài)。相反,個人覺得,上述代碼表現(xiàn)的行為,用帶太語言編程里的鴨子類型也許更合適。

?在動態(tài)語言中經(jīng)常提到鴨子類型,所謂鴨子類型就是:If it walks like a duck and quacks like a duck, it must be a duck。鴨子類型是編程語言中動態(tài)類型語言中的一種設(shè)計風(fēng)格,一個對象的特征不是由父類決定,而是通過對象的方法決定的。

特殊方法&屬性

??python類中有很多特殊方法、屬性或則約定,熟悉這些特性,能讓你編寫更加健壯的代碼,主要如下:

  • __XXX

?該類變量是一個私有變量(private),只有內(nèi)部可以訪問,外部不能訪問。

  • _XXX_

?該類變量是特殊變量,特殊變量是可以直接訪問的,不是private。
變量。

  • _XXX

?該類變量外部是可以訪問的,但是,按照約定俗成的規(guī)定,當(dāng)你看到這樣的變量時,意思
就是,“雖然我可以被訪問,但是,請把我視為私有變量,不要隨意訪問”。

  • XXX_

    定義的一個變量和某個保留關(guān)鍵字沖突,這時候可以使用單下劃線作為后綴, 以示區(qū)分。

特殊屬性

# 用類名和對象名效果會不同,請自己嘗試MasterStudent(obj).__doc__ # 類注釋 MasterStudent(obj).__name__ # 類名(可能帶命名空間) MasterStudent(obj).__bases__ # 直接父類 MasterStudent(obj).__dict__ # 類信息,字典類型 MasterStudent(obj).__class__ # 一般實例調(diào)用__class__屬性時會指向該實例對應(yīng)的類,然后可以再去調(diào)用其它類屬性(注意是類屬性,不是實例屬性) MasterStudent(obj).__module__ # 模塊名 MasterStudent(obj).__mro__ # 多重繼承init時的解析順序,(<class '__main__.MasterStudent'>, <class '__main__.Student'>, <class 'object'>) MasterStudent(obj).__qualname__ # qualified refernece name,見PEP3155 MasterStudent(obj).__slots__ # 見下面解釋 MasterStudent(obj).method.__annotations__ # 注解,見下面解釋
  • __slot__

    ?用于限制類中的屬性(只能是這些屬性),使用__slots__要注意,__slots__定義的屬性僅對當(dāng)前類實例起作用,對繼承的子類是不起作用的。如果父類與子類中都定義了__slot__,則結(jié)果為父類與子類__slot__的合集。

import enforceclass Student(object):__slots__ = ('name', 'score')@enforce.runtime_validationdef __init__(self, name: str): # annotationsself.name = name
  • __annotations__

    ?__annotations__是python3引入的類型檢查機(jī)制,是一種推薦性寫法,如果要強(qiáng)制runtime進(jìn)行類型檢查,可以使用enforce包,并用裝飾器@enforce.runtime_validation裝飾相應(yīng)的方法。查看annotations使用MasterStudent.__init__.__annotations__

魔法方法

  • __init__(),__del__(),__new__()

    ?這個方法是一個類的構(gòu)造函數(shù),與之對應(yīng)的__del__()是析構(gòu)函數(shù),通過此方法我們可以定義一個對象的初始操作。但實際上,新式類的__new__()才是真正的初始化函數(shù)。

    ?首先,我們驗證一下這三個方法的執(zhí)行順序:

    class A(object):def __init__(self):print('__init__')def __new__(cls, *args, **kwargs):print('__new__')return super().__new__(cls, *args, **kwargs) # cls表示一個類,一個當(dāng)前要被實例化的類,參數(shù)由py解釋器自動提供def __del__(self):print('__del__')a = A() print('do something') # __new__ # __init__ # do something # __del__# 實際上,__new__()負(fù)責(zé)創(chuàng)建一個對象,__init__負(fù)責(zé)定制化該對象,即是在對象創(chuàng)建好之后初始化變量

    ?既然知道了__new__()方法,我們是不是可以考慮一下,如何應(yīng)用它呢?最常見的就是單例模式了,下面給出實現(xiàn)實例。

    class Singleton(object):_instance = Nonedef __new__(cls, *args, **kwargs):"""注意這實際上是一個類方法, cls 表示當(dāng)前類:param args::param kwargs::return:"""if cls._instance is None:cls._instance = super().__new__(cls, *args, **kwargs)return cls._instances1 = Singleton() s2 = Singleton() if s1 is s2:print('yeah')
  • __repr__(),__str__()

    ?分別為str()、repr()函數(shù)提供接口,打印的更好看。

    class Pair:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return 'Pair({0.x!r}, {0.y!r})'.format(self)def __str__(self):return '({0.x!s}, {0.y!s})'.format(self)def __eq__(self, other):if self.x == other.x and self.y == other.y:return Trueelse:return Falsep = Pair(3, 4) pp = eval(repr(p)) if pp == p:print('true')
  • __getitem__(),__setitem__(),__delitem__()

    ?__getitem__()將對象當(dāng)作list使用,如obj = ACLASS(), obj_first=obj[0]

    class A(object):def __init__(self):self['B'] = "BB"self['D'] = "DD"self.jj = 'jj'del self['D']def __setitem__(self, name, value):"""每當(dāng)屬性被賦值的時候都會調(diào)用該方法"""print("__setitem__:Set %s Value %s" % (name, value))self.__dict__[name] = valuedef __getitem__(self, name):"""當(dāng)訪問屬性時會調(diào)用該方法"""print("__getitem__:Try to get attribute named '%s'" % name)if hasattr(self, name):return getattr(self, name)return Nonedef __delitem__(self, name):"""當(dāng)刪除屬性時調(diào)用該方法"""print("__delitem__:Delect attribute '%s'" % name)del self.__dict__[name]print(self.__dict__)if __name__ == "__main__":X = A()b = X['jj']print(b)
  • __getattr__(),__setattr__(),__delattr__()

    ?為getattr(),del obj.attr,setattr(),hasattr()提供接口,這是魔法方法中的一個難點,并且發(fā)現(xiàn)不少其他博客居然講錯了,但也許是py3和py2的差別,請參考官方文檔-py3屬性設(shè)置。需要銘記實例對象屬性尋找的順序如下:

  • 首先訪問 __getattribute__() 魔法方法(隱含默認(rèn)調(diào)用,無論何種情況,均會調(diào)用此方法
  • 去實例對象t中查找是否具備該屬性: t.__dict__ 中查找,每個類和實例對象都有一個 __dict__ 的屬性
  • 若在 t.__dict__ 中找不到對應(yīng)的屬性, 則去該實例的類中尋找,即 t.__class__.__dict__
  • 若在實例的類中也招不到該屬性,則去父類中尋找,即 t.__class__.__bases__.__dict__中尋找
  • 若以上均無法找到,則會調(diào)用 __getattr__ 方法,執(zhí)行內(nèi)部的命令(若未重載 __getattr__ 方法,則直接報錯:AttributeError)
  • #! /usr/bin/python # _*_ coding: utf-8 _*_class Test(object):def __init__(self, count):self.count = countdef __getattr__(self, name):print('__getattr__')raise AttributeError('no such field')def __getattribute__(self, item):"""一旦重載了 __getattribute__() 方法, 如果找不到屬性,則必須要手動加入第④步, 否則無法進(jìn)入到 第⑤步 (__getattr__)的:param item::return:"""print('__getattribute__')return super().__getattribute__(item)def __setattr__(self, name, value):print('__setattr__')super().__setattr__(name, value)def __delattr__(self, name):print('__delattr__')super().__delattr__(name)# 希望讀者好好體會下面測試代碼的輸出,并思考為什么 t = Test(3) print(t.count) print('*'*40)t.x = 10 # __setattr__ a = t.x # __getattribute__ print(a) # 10print('**', t.__dict__) # __getattribute__ # ** {'x': 10}if 'x' in t.__class__.__bases__[0].__dict__:print('** x in base class dict') else:print('** x not in base class dict') # __getattribute__ # ** x not in base class dictdel t.x # __delattr__a = t.x # __getattribute__ # __getattr__

    summary:

    __getattr__(self, name): 訪問不存在的屬性時調(diào)用

    __getattribute__(self, name):訪問存在的屬性時調(diào)用(先調(diào)用該方法,查看是否存在該屬性,若不存在,接著去調(diào)用①)

    __setattr__(self, name, value):設(shè)置實例對象的一個新的屬性時調(diào)用

    __delattr__(self, name):刪除一個實例對象的屬性時調(diào)用

  • __gt__(),__lt__(),__eq__(),__ne__(),__ge__()

    ?定義對象比較方法,為關(guān)系運算符>,>=,<,==等提供接口,這就類似于C++里面的運算符重載。

    class SavingsAccount(object):def __init__(self, name, pin, balance=0.0):self._name = nameself._pin = pinself._balance = balancedef __lt__(self, other):return self._balance < other._balances1 = SavingsAccount("Ken", "1000", 0) s2 = SavingsAccount("Bill", "1001", 30) print(s1 < s2)

    ?其實,類似的數(shù)值運算的魔法方法非常非常之多,好吧,我真的用了兩個,現(xiàn)在是三個非常來形容,以下列出部分,希望讀者根據(jù)上面的例子舉一反三:

    class Point(object):def __init__(self):self.x = -1self.y = 5# 正負(fù),取反、絕對值def __pos__(self):passdef __neg__(self):passdef __invert__(self):passdef __abs__(self):pass# 加減乘除、取余,指數(shù)def __add__(self, other):passdef __sub__(self, other):passdef __divmod__(self, other):passdef __mul__(self, other):passdef __mod__(self, other):passdef __pow__(self, power, modulo=None):pass# 邏輯運算符def __and__(self, other):passdef __or__(self, other):passdef __xor__(self, other):pass# 位移def __lshift__(self, other):passdef __rshift__(self, other):pass# 賦值語句def __iadd__(self, other):passdef __imul__(self, other):passdef __isub__(self, other):passdef __idiv__(self, other):passdef __imod__(self, other):passdef __ipow__(self, other):passdef __ilshift__(self, other):passdef __irshift__(self, other):pass
  • __get__(),__set__(),__delete__()

    ?實現(xiàn)了這些方法的類,稱之為描述器類,這里不展開講,僅給出一個實例

    class Integer:"""資料描述器和非資料描述器會產(chǎn)生不一樣的優(yōu)先級,"""def __init__(self, name):self.name = namedef __get__(self, instance, cls):if instance is None:return selfelse:return instance.__dict__[self.name]def __set__(self, instance, value):if not isinstance(value, int):raise TypeError('Expected an int')instance.__dict__[self.name] = valuedef __delete__(self, instance):del instance.__dict__[self.name]class Point:x = Integer('x')y = Integer('y')def __init__(self, x, y):"""特別注意因為Interger是資料描述器,所以self.x 其實指的就是x = Integer('x')"""self.x = xself.y = yp = Point(10, 11)
  • __iter__()

    ? 為for … in提供接口,返回一個迭代對象,并調(diào)用對象next()方法,直到StopIteration。以下這個例子來源廖雪峰python教程

    class Fib(object):def __init__(self):self.a, self.b = 0, 1 # 初始化兩個計數(shù)器a,bdef __iter__(self):return self # 實例本身就是迭代對象,故返回自己def __next__(self):self.a, self.b = self.b, self.a + self.b # 計算下一個值if self.a > 10: # 退出循環(huán)的條件raise StopIteration()return self.a # 返回下一個值for i in Fib():print(i)
  • __dir__()

    ?為dir()函數(shù)提供接口,查看一個對象中有哪些屬性和方法, 返回值應(yīng)該是iterable。【關(guān)于Iterable放在后面討論】,如返回一個list,一般而言我們不去重寫這個方法。

    首先我們看看dir函數(shù):

    >>> res = dir(str(123)) >>> print(type(res)) <class 'list'> >>> print(res) ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

    我們自定義一個__dir__()方法試試:

    class A(object):def __dir__(self):print('不給你看這個函數(shù)有什么屬性和方法,哼、、哼哼')return []if __name__ == "__main__":a = A()result = dir(a)print(result)# 不給你看這個函數(shù)有什么屬性和方法,哼、、哼哼 # <class 'list'>
  • __call__()

    ?假設(shè)有對象obj, 則obj()可以調(diào)用__call__()方法

    class A(object):def _pre_process(self):print('preoprocess data')def __call__(self, *args, **kwargs):self._pre_process()print('object called over')A()() # 調(diào)用了類中__call__()中的邏輯
  • 數(shù)據(jù)類型轉(zhuǎn)換

    # 類似數(shù)值計算的魔法方法,實現(xiàn)以下方法就可以實現(xiàn)自定義的數(shù)據(jù)類型轉(zhuǎn)換 class A(object):def __init__(self, num):self.x = numdef __int__(self):passdef __float__(self):passdef __long__(self):passdef __complex__(self):passdef __bytes__(self):passdef __oct__(self):passdef __hex__(self):passdef __str__(self):passdef __nonzero__(self):"""這里僅僅實現(xiàn)bool轉(zhuǎn)換,其他的讀者可舉一反三"""if self.x != 0:return Trueelse:return Falseif __name__ == '__main__':print(bool(A(5)))
  • __enter__(),__exit__()

    ?這兩個魔法方法使對象是用于With會話管理,一般用于需要打開關(guān)閉的場景,如文件讀寫、數(shù)據(jù)庫連接。

    #! /usr/bin/python # _*_ coding: utf-8 _*_class OpenTextFile(object):"""實現(xiàn)打開一個文件使用with,這里僅僅是個例子因為 open()本身就可以實現(xiàn) with context"""def __init__(self, file_path):self.file = file_pathdef __enter__(self):self.f = open(self.file, 'r', encoding='utf-8')return self.fdef __exit__(self, exc_type, exc_val, exc_tb):self.f.close()with OpenTextFile('./with_context.py') as f:print(f.readlines())
  • 其他魔法方法

    # 獲取對象大小 __sizeof__()# 獲取對象哈希值 __hash__()# 用于對象序列化和反序列化 __reduce__() __reduce_ex__()__instancecheck__(self, instance) # 檢查一個實例是不是你定義的類的實例 __subclasscheck__(self, subclass) # 檢查一個類是不是你定義的類的子類__contains__(self,value) # 使用in操作測試關(guān)系時 __concat__(self,value) # 連接兩個對象時 __index__(self) # 對象被當(dāng)作list索引時

輔助知識

OOP實用函數(shù)

  • type() 查看對象類型
  • issubclass() 查看一個對象是否屬于某個類的子類
  • is vs == vs isinstance 前者查看兩個對象是否嚴(yán)格相同,后者查看某對象是否屬于某類
  • id用于獲取對象的內(nèi)存地址

迭代器生成器

  • 列表生成式

??List Comprehensions, 是python內(nèi)置的用來生成list的一種快捷高效的方式。

# 舉例 [x * x for x in range(1, 11)] [x * x for x in range(1, 11) if x % 2 == 0]
  • 生成器

??Generator,是列表生成式的一種優(yōu)化方案,列表生成式的list會直接放在內(nèi)存中,因此其大小必然會受到內(nèi)存的限制;而生成器就是為了解決這種資源耗費的情況,能夠做到先定義,邊循環(huán)邊計算。

# 注意區(qū)分生成器和列表生成式的定義方式 # 生成器是用()、列表生成式是用[]>>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x0000020A6184D0A0># 如果要一個一個打印出來,可以通過next()或則__next__()獲得generator的下一個返回值 >>> next(g) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) 9 >>> g.__next__() 16# 在實際編程中,我們一般這樣使用 for n in g:print(n)

??在實際應(yīng)用中,我們經(jīng)常會借助yield關(guān)鍵字構(gòu)造生成器函數(shù),如斐波那契函數(shù):

def fib(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1>>> g = fib(6) >>> g <generator object fib at 0x0000020A619C6BF8> >>> next(g) 1 >>> next(g) 1 >>> next(g) 2 >>> next(g) 3 >>> next(g) 5 >>> next(g) 8 >>> next(g) Traceback (most recent call last):File "<stdin>", line 1, in <module> StopIteration
  • 迭代器

??可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象(Iterable),包括集合數(shù)據(jù)類型(如list、tuple、dict、set、str)和 generator(生成器、帶yield的generator function)。但是集合數(shù)據(jù)類型和generator有一個很大的區(qū)別:generator可以使用next()不斷調(diào)用,直至StopIteration。在python中,可以被next()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器:Iterator。

?

Tips: 如果一個對象是 Iterator(迭代器), 那么它必然是一個Iterable(可迭代對象);而Iterable不一定是一個Iterator,但是Iterable可以通過iter()函數(shù)變成Iterator;特殊的是generator既是Iterable又是Iterator。

>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True>>> isinstance([], Iterator) False >>> isinstance('abc', Iterator) False>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True

總結(jié)

以上是生活随笔為你收集整理的Python面向对象、魔法方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。