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

歡迎訪問 生活随笔!

生活随笔

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

python

关于如何在Python中使用静态、类或抽象方法的权威指南

發(fā)布時間:2023/11/30 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于如何在Python中使用静态、类或抽象方法的权威指南 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Python中方法的工作方式

方法是存儲在類屬性中的函數(shù),你可以用下面這種方式聲明和訪問一個函數(shù)

>>> class Pizza(object):... def __init__(self, size):... self.size = size... def get_size(self):... return self.size...>>> Pizza.get_size<unbound method Pizza.get_size>

?Python在這里說明了什么?Pizza類的屬性get_size是unbound(未綁定的),這代表什么含義?我們調(diào)用一下就明白了:

>>> Pizza.get_size()Traceback (most recent call last):File "<stdin>", line 1, in <module>TypeError: unbound method get_size() must be called with Pizza instance as first argument (got nothing instead)

我們無法調(diào)用它(get_size),因?yàn)樗鼪]有綁定到Pizza的任何實(shí)例上,而且一個方法需要一個實(shí)例作為它的第一個參數(shù)(Python2中必須是類的實(shí)例,Python3沒有這個強(qiáng)制要求),讓我們試一下:

>>> Pizza.get_size(Pizza(42))42

我們使用一個實(shí)例作為這個方法的第一個參數(shù)來調(diào)用它,沒有出現(xiàn)任何問題。但是如果我說這不是一個方便的調(diào)用方法的方式,你將會同意我的觀點(diǎn)。我們每次調(diào)用方法都要涉及(這里我理解是引用)類

來看Python打算為我們做些什么,就是它從Pizza類中綁定所有的方法到這個類的任何實(shí)例上。意思就是Pizza實(shí)例化后get_size這個屬性是一個綁定方法,方法的第一個參數(shù)會是實(shí)例對象自己

>>> Pizza(42).get_size<bound method Pizza.get_size of <__main__.Pizza object at 0x7f3138827910>>>>> Pizza(42).get_size()42

意料之中,我們不需要為get_size傳任何參數(shù),自從被綁定后,它的self參數(shù)會自動設(shè)置為Pizza實(shí)例,下面是一個更明顯的例子:

>>> m = Pizza(42).get_size>>> m()42

事實(shí)上是,你甚至不需要對Pizza引用,因?yàn)檫@個方法已經(jīng)綁定到了這個對象

如果你想知道這個綁定方法綁定到了哪一個對象,這里有個快捷的方法:

>>> m = Pizza(42).get_size>>> m.__self__<__main__.Pizza object at 0x7f3138827910>>>> # You could guess, look at this:...>>> m == m.__self__.get_sizeTrue

明顯可以看出,我們?nèi)匀槐3謱ξ覀儗ο蟮囊?#xff0c;而且如果需要我們可以找到它

在Python3中,類中的函數(shù)不再被認(rèn)為是未綁定的方法(應(yīng)該是作為函數(shù)存在),如果需要,會作為一個函數(shù)綁定到對象上,所以原理是一樣的(和Python2),只是模型被簡化了

>>> class Pizza(object):... def __init__(self, size):... self.size = size... def get_size(self):... return self.size...>>> Pizza.get_size<function Pizza.get_size at 0x7f307f984dd0>

靜態(tài)方法

靜態(tài)方法一種特殊方法,有時你想把代碼歸屬到一個類中,但又不想和這個對象發(fā)生任何交互:

class Pizza(object):@staticmethoddef mix_ingredients(x, y):return x + ydef cook(self):return self.mix_ingredients(self.cheese, self.vegetables)

上面這個例子,mix_ingredients完全可以寫成一個非靜態(tài)方法,但是這樣會將self作為第一個參數(shù)傳入。在這個例子里,裝飾器@staticmethod 會實(shí)現(xiàn)幾個功能:

Python不會為Pizza的實(shí)例對象實(shí)例化一個綁定方法,綁定方法也是對象,會產(chǎn)生開銷,靜態(tài)方法可以避免這類情況

>>> Pizza().cook is Pizza().cookFalse>>> Pizza().mix_ingredients is Pizza.mix_ingredientsTrue>>> Pizza().mix_ingredients is Pizza().mix_ingredientsTrue

簡化了代碼的可讀性,看到@staticmethod我們就會知道這個方法不會依賴這個對象的狀態(tài)(一國兩制,高度自治)
允許在子類中重寫mix_ingredients方法。如果我們在頂級模型中定義了mix_ingredients函數(shù),繼承自Pizza的類除了重寫,否則無法改變mix_ingredients的功能

類方法

什么是類方法,類方法是方法不會被綁定到一個對象,而是被綁定到一個類中

>>> class Pizza(object):... radius = 42... @classmethod... def get_radius(cls):... return cls.radius... >>> >>> Pizza.get_radius<bound method type.get_radius of <class '__main__.Pizza'>>>>> Pizza().get_radius<bound method type.get_radius of <class '__main__.Pizza'>>>>> Pizza.get_radius == Pizza().get_radiusTrue>>> Pizza.get_radius()42

無論以何種方式訪問這個方法,它都會被綁定到類中,它的第一個參數(shù)必須是類本身(記住類也是對象)


什么時候使用類方法,類方法在以下兩種場合會有很好的效果:
??? 1、工廠方法,為類創(chuàng)建實(shí)例,例如某種程度的預(yù)處理。如果我們使用@staticmethod代替,我們必須要在代碼中硬編碼Pizza(寫死Pizza),這樣從Pizza繼承的類就不能使用了

class Pizza(object):def __init__(self, ingredients):self.ingredients = ingredients@classmethoddef from_fridge(cls, fridge):return cls(fridge.get_cheese() + fridge.get_vegetables())

? 2、使用靜態(tài)方法調(diào)用靜態(tài)方法,如果你需要將一個靜態(tài)方法拆分為多個,可以使用類方法來避免硬編碼類名。使用這種方法來聲明我們的方法Pizza的名字永遠(yuǎn)不會被直接引用,而且繼承和重寫方法都很方便

class Pizza(object):def __init__(self, radius, height):self.radius = radiusself.height = height@staticmethoddef compute_area(radius):return math.pi * (radius ** 2)@classmethoddef compute_volume(cls, height, radius):return height * cls.compute_area(radius)def get_volume(self):return self.compute_volume(self.height, self.radius)

抽象方法

抽象方法是定義在基類中的,可以是不提供任何功能代碼的方法
在Python中簡單的寫抽象方法的方式是:

class Pizza(object):def get_radius(self):raise NotImplementedError

繼承自Pizza的類都必須要實(shí)現(xiàn)并重寫get_redius,否則就會報(bào)錯

這種方式的抽象方法有一個問題,如果你忘記實(shí)現(xiàn)了get_radius,只有在你調(diào)用這個方法的時候才會報(bào)錯

>>> Pizza()<__main__.Pizza object at 0x7fb747353d90>>>> Pizza().get_radius()Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 3, in get_radiusNotImplementedError

使用python的abc模塊可以是這個異常被更早的觸發(fā)

import abcclass BasePizza(object):__metaclass__ = abc.ABCMeta@abc.abstractmethoddef get_radius(self):"""Method that should do something."""

使用abc和它的特殊類,如果你嘗試實(shí)例化BasePizza或者繼承它,都會得到TypeError錯誤

??? >>> BasePizza()
??? Traceback (most recent call last):
????? File "<stdin>", line 1, in <module>
??? TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

備注:我使用Python3.6實(shí)現(xiàn)的代碼  

In [8]: import abc...:...: class BasePizza(abc.ABC):...:...: @abc.abstractmethod...: def get_radius(self):...: """:return"""...:In [9]: BasePizza()---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-9-70b53ea21e68> in <module>()----> 1 BasePizza()TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

混合靜態(tài),類和抽象方法

當(dāng)需要創(chuàng)建類和繼承時,如果你需要混合這些方法裝飾器,這里有一些小竅門建議給你
記住要將方法聲明為抽象,不要凍結(jié)這個方法的原型。意思是它(聲明的方法)必須要執(zhí)行,但是它在執(zhí)行的時候,參數(shù)不會有任何限制

import abcclass BasePizza(object):__metaclass__ = abc.ABCMeta@abc.abstractmethoddef get_ingredients(self):"""Returns the ingredient list."""class Calzone(BasePizza):def get_ingredients(self, with_egg=False):egg = Egg() if with_egg else Nonereturn self.ingredients + egg

這樣是有效的,因?yàn)镃alzone實(shí)現(xiàn)了我們?yōu)锽asePizza定義的接口要求,這意味著我們也可以將它實(shí)現(xiàn)為一個類或者靜態(tài)方法,例如:

import abcclass BasePizza(object):__metaclass__ = abc.ABCMeta@abc.abstractmethoddef get_ingredients(self):"""Returns the ingredient list."""class DietPizza(BasePizza):@staticmethoddef get_ingredients():return None

這也是正確的,它實(shí)現(xiàn)了抽要BasePizza的要求,事實(shí)上是get_ingredioents方法不需要知道對象返回的結(jié)果,
因此,你不需要強(qiáng)制抽象方法實(shí)現(xiàn)成為常規(guī)方法、類或者靜態(tài)方法。在python3中,可以將@staticmethod和@classmethod裝飾器放在@abstractmethod上面

import abcclass BasePizza(object):__metaclass__ = abc.ABCMetaingredient = ['cheese']@classmethod@abc.abstractmethoddef get_ingredients(cls):"""Returns the ingredient list."""return cls.ingredients

和Java的接口相反,你可以在抽象方法中實(shí)現(xiàn)代碼并通過super()調(diào)用它

import abcclass BasePizza(object):__metaclass__ = abc.ABCMetadefault_ingredients = ['cheese']@classmethod@abc.abstractmethoddef get_ingredients(cls):"""Returns the ingredient list."""return cls.default_ingredientsclass DietPizza(BasePizza):def get_ingredients(self):return ['egg'] + super(DietPizza, self).get_ingredients()

在上面的例子中,繼承BasePizza來創(chuàng)建的每個Pizza都必須重寫get_ingredients 方法,但是可以使用super()來獲取default_ingredients

?

本文翻譯自:https://julien.danjou.info/guide-python-static-class-abstract-methods/

轉(zhuǎn)載于:https://www.cnblogs.com/flashBoxer/p/9814012.html

總結(jié)

以上是生活随笔為你收集整理的关于如何在Python中使用静态、类或抽象方法的权威指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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