欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

python函數(shù)抽象原則 抽象函數(shù)入門

為什么使用抽象基類在Python

抽象方法是基類中定義的方法,但卻沒有任何實現(xiàn)。在java中,可以把方法申明成一個接口。而在python中實現(xiàn)一個抽象方法的簡單的方法是:

龍灣網(wǎng)站建設公司創(chuàng)新互聯(lián),龍灣網(wǎng)站設計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為龍灣近千家提供企業(yè)網(wǎng)站建設服務。企業(yè)網(wǎng)站搭建\成都外貿網(wǎng)站建設要多少錢,請找那個售后服務好的龍灣做網(wǎng)站的公司定做!

class Sheep(object):

def get_size(self):

raise NotImplementedError

任何從Sheep繼承下來的子類必須實現(xiàn)get_size方法。否則就會產生一個錯誤。但這種實現(xiàn)方法有個缺點。定義的子類只有調用那個方法時才會拋錯。這里有個簡單方法可以在類被實例化后觸發(fā)它。使用python提供的abc模塊。

python中定義函數(shù)的關鍵字是什么?

python中定義函數(shù)的關鍵字是def。

Python使用def關鍵字開始函數(shù)定義,緊接著是函數(shù)名,括號內部為函數(shù)的參數(shù),內部為函數(shù)的具體功能實現(xiàn)代碼,如果想要函數(shù)有返回值, 在expressions中的邏輯代碼中用return返回。

上面我們定義了一個名字為 function 的函數(shù),函數(shù)沒有不接受參數(shù),所以括號內部為空,緊接著就是 函數(shù)的功能代碼。

如果執(zhí)行該腳本,發(fā)現(xiàn)并沒有輸出任何輸出,因為我們只定義了函數(shù),而并沒有執(zhí)行函數(shù)。 這時我們在Python命令提示符中輸入函數(shù)調用 function(), 注意這里調用函數(shù)的括號不能省略。

python的學習

如果我們用代碼實現(xiàn)了一個小功能,但想要在程序代碼中重復使用,不能在代碼中到處粘貼這些代碼,因為這樣做違反了軟件工程中DRY原則。 Python提供了函數(shù)功能,可以將我們這部分功能抽象成一個函數(shù)以方便程序調用,或者提供給其他模塊使用。

函數(shù)是組織好的,可重復使用的,用來實現(xiàn)單一,或相關聯(lián)功能的代碼段。(推薦學習:Python視頻教程)函數(shù)必須先定義,才能調用,否則會報錯,無參數(shù)時函數(shù)的調用函數(shù)名()。

有參數(shù)時函數(shù)的調,不要在定義函數(shù)的時候在函數(shù)體里面調用本身,否則會出不來,陷入循環(huán)調用,函數(shù)需要調用函數(shù)體才會被執(zhí)行,單純的只是定義函數(shù)是不會被執(zhí)行的。

Python中的抽象類和抽象方法

抽象類是一個特殊的類,它只能被繼承,不能被實例化。python中如果要使用抽象類則需要導入模塊 abc ,

在定義抽象類的時候,需要添加參數(shù) metaclass=abc.ABCMeta ,在定義抽象方法時需要在方法前添加聲明

注意,我們只需寫出方法的名稱,不用寫出具體的方法內容。

例如:

或者我們也可以寫成

python下的抽象類的用途和意義?

抽象類是不完整的,并且它只能用作基類。它與非抽象類的不同: 1、抽象類不能直接實例化,并且對抽象類使用 new 運算符是編譯時錯誤。雖然一些變量和值在編譯時的類型可以是抽象的,但是這樣的變量和值必須或者為 null,或者含有對非抽象類的實例的引用(此非抽象類是從抽象類派生的)。 2、允許(但不要求)抽象類包含抽象成員。 3、抽象類不能被密封。 當從抽象類派生非抽象類時,這些非抽象類必須具體實現(xiàn)所繼承的所有抽象成員,從而重寫那些抽象成員。在下邊的示例中: abstract class A{ public abstract void F();} abstract class B: A{ public void G() {}} class C: B{ public override void F() { // actual implementation of F }}  抽象類 A 引入抽象方法 F。類 B 引入另一個方法 G,但由于它不提供 F 的實現(xiàn),B 也必須聲明為抽象類。類 C 重寫 F,并提供一個具體實現(xiàn)。由于 C 中沒有了抽象成員,因此可以(但并非必須)將 C 聲明為非抽象類。 抽象類與接口緊密相關。然接口又比抽象類更抽象,這主要體現(xiàn)在它們的差別上:1)類可以實現(xiàn)無限個接口,但僅能從一個抽象(或任何其他類型)類繼承,從抽象類派生的類仍可實現(xiàn)接口,從而得出接口是用來解決多重繼承問題的。2)抽象類當中可以存在非抽象的方法,可接口不能且它里面的方法只是一個聲明必須用public來修飾沒有具體實現(xiàn)的方法。3)抽象類中的成員變量可以被不同的修飾符來修飾,可接口中的成員變量默認的都是靜態(tài)常量(static final)。4)這一點也是最重要的一點本質的一點"抽象類是對象的抽象,然而接口是一種行為規(guī)范"。

如何在Python中使用static,class,abstract方法

方法在Python中是如何工作的

方法就是一個函數(shù),它作為一個類屬性而存在,你可以用如下方式來聲明、訪問一個函數(shù):

Python

1

2

3

4

5

6

7

8

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在告訴你,屬性_get_size是類Pizza的一個未綁定方法。這是什么意思呢?很快我們就會知道答案:

Python

1

2

3

4

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)

我們不能這么調用,因為它還沒有綁定到Pizza類的任何實例上,它需要一個實例作為第一個參數(shù)傳遞進去(Python2必須是該類的實例,Python3中可以是任何東西),嘗試一下:

Python

1

2

Pizza.get_size(Pizza(42))

42

太棒了,現(xiàn)在用一個實例作為它的的第一個參數(shù)來調用,整個世界都清靜了,如果我說這種調用方式還不是最方便的,你也會這么認為的;沒錯,現(xiàn)在每次調用這個方法的時候我們都不得不引用這個類,如果不知道哪個類是我們的對象,長期看來這種方式是行不通的。

那么Python為我們做了什么呢,它綁定了所有來自類_Pizza的方法以及該類的任何一個實例的方法。也就意味著現(xiàn)在屬性get_size是Pizza的一個實例對象的綁定方法,這個方法的第一個參數(shù)就是該實例本身。

Python

1

2

3

4

Pizza(42).get_size

bound method Pizza.get_size of __main__.Pizza object at 0x7f3138827910

Pizza(42).get_size()

42

和我們預期的一樣,現(xiàn)在不再需要提供任何參數(shù)給_get_size,因為它已經(jīng)是綁定的,它的self參數(shù)會自動地設置給Pizza實例,下面代碼是最好的證明:

Python

1

2

3

m = Pizza(42).get_size

m()

42

更有甚者,你都沒必要使用持有Pizza對象的引用了,因為該方法已經(jīng)綁定到了這個對象,所以這個方法對它自己來說是已經(jīng)足夠了。

也許,如果你想知道這個綁定的方法是綁定在哪個對象上,下面這種手段就能得知:

Python

1

2

3

4

5

6

7

m = Pizza(42).get_size

m.__self__

__main__.Pizza object at 0x7f3138827910

# You could guess, look at this:

...

m == m.__self__.get_size

True

顯然,該對象仍然有一個引用存在,只要你愿意你還是可以把它找回來。

在Python3中,依附在類上的函數(shù)不再當作是未綁定的方法,而是把它當作一個簡單地函數(shù),如果有必要它會綁定到一個對象身上去,原則依然和Python2保持一致,但是模塊更簡潔:

Python

1

2

3

4

5

6

7

8

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)方法是一類特殊的方法,有時你可能需要寫一個屬于這個類的方法,但是這些代碼完全不會使用到實例對象本身,例如:

Python

1

2

3

4

5

6

7

class Pizza(object):

@staticmethod

def mix_ingredients(x, y):

return x + y

def cook(self):

return self.mix_ingredients(self.cheese, self.vegetables)

這個例子中,如果把_mix_ingredients作為非靜態(tài)方法同樣可以運行,但是它要提供self參數(shù),而這個參數(shù)在方法中根本不會被使用到。這里的@staticmethod裝飾器可以給我們帶來一些好處:

Python不再需要為Pizza對象實例初始化一個綁定方法,綁定方法同樣是對象,但是創(chuàng)建他們需要成本,而靜態(tài)方法就可以避免這些。

Python

1

2

3

4

5

6

Pizza().cook is Pizza().cook

False

Pizza().mix_ingredients is Pizza.mix_ingredients

True

Pizza().mix_ingredients is Pizza().mix_ingredients

True

可讀性更好的代碼,看到@staticmethod我們就知道這個方法并不需要依賴對象本身的狀態(tài)。

可以在子類中被覆蓋,如果是把mix_ingredients作為模塊的頂層函數(shù),那么繼承自Pizza的子類就沒法改變pizza的mix_ingredients了如果不覆蓋cook的話。

類方法

話雖如此,什么是類方法呢?類方法不是綁定到對象上,而是綁定在類上的方法。

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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 is Pizza().get_radius

True

Pizza.get_radius()

42

無論你用哪種方式訪問這個方法,它總是綁定到了這個類身上,它的第一個參數(shù)是這個類本身(記?。侯愐彩菍ο螅?。

什么時候使用這種方法呢?類方法通常在以下兩種場景是非常有用的:

工廠方法:它用于創(chuàng)建類的實例,例如一些預處理。如果使用@staticmethod代替,那我們不得不硬編碼Pizza類名在函數(shù)中,這使得任何繼承Pizza的類都不能使用我們這個工廠方法給它自己用。

Python

1

2

3

4

5

6

7

class Pizza(object):

def __init__(self, ingredients):

self.ingredients = ingredients

@classmethod

def from_fridge(cls, fridge):

return cls(fridge.get_cheese() + fridge.get_vegetables())

調用靜態(tài)類:如果你把一個靜態(tài)方法拆分成多個靜態(tài)方法,除非你使用類方法,否則你還是得硬編碼類名。使用這種方式聲明方法,Pizza類名明永遠都不會在被直接引用,繼承和方法覆蓋都可以完美的工作。

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

class Pizza(object):

def __init__(self, radius, height):

self.radius = radius

self.height = height

@staticmethod

def compute_area(radius):

return math.pi * (radius ** 2)

@classmethod

def compute_volume(cls, height, radius):

return height * cls.compute_area(radius)

def get_volume(self):

return self.compute_volume(self.height, self.radius)

抽象方法

抽象方法是定義在基類中的一種方法,它沒有提供任何實現(xiàn),類似于Java中接口(Interface)里面的方法。

在Python中實現(xiàn)抽象方法最簡單地方式是:

Python

1

2

3

class Pizza(object):

def get_radius(self):

raise NotImplementedError

任何繼承自_Pizza的類必須覆蓋實現(xiàn)方法get_radius,否則會拋出異常。

這種抽象方法的實現(xiàn)有它的弊端,如果你寫一個類繼承Pizza,但是忘記實現(xiàn)get_radius,異常只有在你真正使用的時候才會拋出來。

Python

1

2

3

4

5

6

7

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_radius

NotImplementedError

還有一種方式可以讓錯誤更早的觸發(fā),使用Python提供的abc模塊,對象被初始化之后就可以拋出異常:

Python

1

2

3

4

5

6

7

8

import abc

class BasePizza(object):

__metaclass__??= abc.ABCMeta

@abc.abstractmethod

def get_radius(self):

"""Method that should do something."""

使用abc后,當你嘗試初始化BasePizza或者任何子類的時候立馬就會得到一個TypeError,而無需等到真正調用get_radius的時候才發(fā)現(xiàn)異常。

Python

1

2

3

4

BasePizza()

Traceback (most recent call last):

File "stdin", line 1, in module

TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

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

當你開始構建類和繼承結構時,混合使用這些裝飾器的時候到了,所以這里列出了一些技巧。

記住,聲明一個抽象的方法,不會固定方法的原型,這就意味著雖然你必須實現(xiàn)它,但是我可以用任何參數(shù)列表來實現(xiàn):

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

import abc

class BasePizza(object):

__metaclass__??= abc.ABCMeta

@abc.abstractmethod

def get_ingredients(self):

"""Returns the ingredient list."""

class Calzone(BasePizza):

def get_ingredients(self, with_egg=False):

egg = Egg() if with_egg else None

return self.ingredients + egg

這樣是允許的,因為Calzone滿足BasePizza對象所定義的接口需求。同樣我們也可以用一個類方法或靜態(tài)方法來實現(xiàn):

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

import abc

class BasePizza(object):

__metaclass__??= abc.ABCMeta

@abc.abstractmethod

def get_ingredients(self):

"""Returns the ingredient list."""

class DietPizza(BasePizza):

@staticmethod

def get_ingredients():

return None

這同樣是正確的,因為它遵循抽象類BasePizza設定的契約。事實上get_ingredients方法并不需要知道返回結果是什么,結果是實現(xiàn)細節(jié),不是契約條件。

因此,你不能強制抽象方法的實現(xiàn)是一個常規(guī)方法、或者是類方法還是靜態(tài)方法,也沒什么可爭論的。從Python3開始(在Python2中不能如你期待的運行,見issue5867),在abstractmethod方法上面使用@staticmethod和@classmethod裝飾器成為可能。

Python

1

2

3

4

5

6

7

8

9

10

11

12

import abc

class BasePizza(object):

__metaclass__??= abc.ABCMeta

ingredient = ['cheese']

@classmethod

@abc.abstractmethod

def get_ingredients(cls):

"""Returns the ingredient list."""

return cls.ingredients

別誤會了,如果你認為它會強制子類作為一個類方法來實現(xiàn)get_ingredients那你就錯了,它僅僅表示你實現(xiàn)的get_ingredients在BasePizza中是一個類方法。

可以在抽象方法中做代碼的實現(xiàn)?沒錯,Python與Java接口中的方法相反,你可以在抽象方法編寫實現(xiàn)代碼通過super()來調用它。(譯注:在Java8中,接口也提供的默認方法,允許在接口中寫方法的實現(xiàn))

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

import abc

class BasePizza(object):

__metaclass__??= abc.ABCMeta

default_ingredients = ['cheese']

@classmethod

@abc.abstractmethod

def get_ingredients(cls):

"""Returns the ingredient list."""

return cls.default_ingredients

class DietPizza(BasePizza):

def get_ingredients(self):

return ['egg'] + super(DietPizza, self).get_ingredients()

這個例子中,你構建的每個pizza都通過繼承BasePizza的方式,你不得不覆蓋get_ingredients方法,但是能夠使用默認機制通過super()來獲取ingredient列表。

打賞支持我翻譯更多好文章,謝謝!

網(wǎng)站題目:python函數(shù)抽象原則 抽象函數(shù)入門
文章轉載:http://chinadenli.net/article10/dodeigo.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃網(wǎng)站排名、網(wǎng)頁設計公司、面包屑導航、品牌網(wǎng)站制作網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設