真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

[Python]類與面向?qū)ο缶幊?創(chuàng)新互聯(lián)

1. class語句

類通常是由函數(shù)、變量和屬性組成的集合。使用class語句可以定義類,例如:

創(chuàng)新互聯(lián)IDC提供業(yè)務(wù):眉山服務(wù)器托管,成都服務(wù)器租用,眉山服務(wù)器托管,重慶服務(wù)器租用等四川省內(nèi)主機托管與主機租用業(yè)務(wù);數(shù)據(jù)中心含:雙線機房,BGP機房,電信機房,移動機房,聯(lián)通機房。
class Account(object):
    num_accounts = 0
    def __init__(self, name, balance):
        self.name = name
        self.balance = balance
        Account.num_accounts += 1
    def __del__(self):
        Account.num_accounts -= 1
    def deposit(self, amt):
        self.balance = self.balance + amt
    def withdraw(self, amt):
        self.balance = self.balance - amt
    def inquiry(self):
        return self.balance

在類主體執(zhí)行期間創(chuàng)建的值放在類對象中,這個對象充當著命名空間,例如:

Account.num_accunts
Account.__init__
Account.__del__
Account.deposit
Account.withdraw
Account.inquiry

需要注意的是,class語句本身并不創(chuàng)建該類的任何類型。類僅設(shè)置將在以后創(chuàng)建的所有實例都使用的屬性。類中定義的函數(shù)稱為實例方法。類的實例作為第一個參數(shù)傳遞,根據(jù)約定,這個參數(shù)稱為self,但所有合法的標識符都可以使用。類變量是可在類的所有實例之間共享的值。比如上例的num_accounts變量用于跟蹤存在多少個Account實例。
?

2. 類實例

類的實例是以函數(shù)形式調(diào)用類對象來創(chuàng)建的。這種方法將創(chuàng)建一個新實例,而后將該實例傳遞給類的__init__()方法。__init__()方法的參數(shù)包括新創(chuàng)建的實例self和在調(diào)用類對象時提供的參數(shù)。例如:

a = Account("Guido", 1000.00)
b = Account("Bill", 10.00)

通過將屬性分配給self來將其保存到實例中。例如self.name = name表示將name屬性保存在衫例中。使用"."運算符可以訪問這些屬性以及類屬性,例如:

a.deposit(100.00)
b.withdraw(50.00)
name = a.name

盡管類會定義命名空間,但它們不會為在方法體內(nèi)使用的名稱限定范圍。所以在實現(xiàn)類時,對屬性和方法的引用必須是完全限定的。比如之前的例子中使用的是self.balance而非balance。如果希望從一個方法中調(diào)用另一個方法,也可以采用這種方式,例如:

class Foo(object):
    def bar(self):
        print("bar!")
    def spam(self):
        bar(self) # 錯誤,拋出NameError異常
        self.bar()
        Foo.bar(self)

3. 繼承

繼承是一種創(chuàng)建新類的機制。原始類稱為基類或超類。新類稱為派生類或子類。通過繼承創(chuàng)建類時,所創(chuàng)建的類將“繼承”其基類定義的屬性。派生類可以重新定義屬性并添加自己的屬性。
在class語句中使用以逗號分隔的基類名稱列表來指定繼承。如果沒有有效的基類,將繼承object。繼承通常會重新定義現(xiàn)有方法的行為,例如:

import random
class EvilAccount(Account):
    def inquiry(self):
        if andom.randint(0, 4) == 1:
            return self.balance * 1.10
        else:
            return self.balance
c = EvilAccount("George", 1000.00)
c.deposit(10.0)
available = c.inquiry()

如果搜索一個屬性時未在實例或?qū)嵗念愔姓业狡ヅ漤?,搜索將會在基類上進行。這個過程會一直繼續(xù)下去,直到?jīng)]有更多的基類可供搜索。子類可以定義自己的__init__()方法。因此,要由派生類調(diào)用基類的__init__()方法來對它們進行恰當?shù)某跏蓟?。如果基類未定義__init__(),就可以忽略這一步。如果不知道基類是否定義了__init__(),可在不提供任何參數(shù)的情況下調(diào)用它,因為始終存在一個不執(zhí)行任何操作的默認__init__()實現(xiàn)。例如:

class EvilAccount(Account):
    def __init__(self, name, balance, evilfactor):
        Account.__init__(self, name, balance)
        self.evilfactor = evilfactor
    def inquiry(self):
        if random.randint(0, 4) == 1:
            return self.balance * self.evilfactor
        else:
            return self.balance

有時,派生類重新實現(xiàn)了方法,但是還想調(diào)用原始的實現(xiàn),可以將實例self作為第一個參數(shù)傳遞,例如:

class MoreEvilAccount(EvilAccount):
    def deposit(self, amount):
        self.withdraw(5.00)
        EvilAccount.deposit(self, amount)

但是這種寫法容易引起一些混淆,可以使用另一種方案,用super()函數(shù),例如:

class MoreEvilAccount(EvilAccount):
    def deposit(self, amount):
        self.withdraw(5.00)
        super().deposit(amount)

Python支持多重繼承,通過讓一個類列出多個基類即可指定多重繼承,例如:

class DepositCharge(object):
    fee = 5.00
    def deposit_fee(self):
        print(self.fee)

class WithdrawCharge(object):
    fee = 2.50
    def withdraw_fee(self):
        print(self.fee)

class MostEvilAccount(EvilAccount, DepositCharge, WithdrawCharge):
    def deposit(self, amt):
        self.deposit_fee()
        super().deposit(amt)
    def withdraw(self, amt):
        self.withdraw_fee()
        super().withdraw(amt)

withdraw_fee()實際并未使用在自己的類中初始化的fee值。屬性fee是在兩個不同的基類中定義的類變量,程序使用了其中一個。要找到使用了多重繼承的屬性,可以在列表中對所有基類按從“最特殊”的類到“最不特殊”的類。而后在搜索屬性時,就會按這個順序搜索列表,直至找到該屬性的第一個定義。對于任何給定的類,通過打印它的__mro__屬性即可查看基類的順序。

4. 靜態(tài)方法和類方法

靜態(tài)方法是一種普通函數(shù),就位于類定義的命名空間中。要定義靜態(tài)方法,可使用@staticmethod裝飾器,例如:

class Foo(object):
    @staticmethod
    def add(x, y):
        return x + y

要調(diào)用靜態(tài)方法,只需用類名作為它的前綴,例如:

x = Foo.add(3, 4)

類方法是將類本身作為對象進行操作的方法。類方法使用@classmethod裝飾器定義,根據(jù)約定,類是作為第一個參數(shù)(名為cls)傳遞的,例如:

class Times(object):
    factor = 1
    @classmethod
    def mul(cls, x):
        return cls.factor * x

class TwoTimes(Times):
    factor = 2

x = TwoTimes.mul(4)

5. 特性

特性是一種特殊的屬性,訪問它時會計算它的值,例如:

class Circle(object):
    def __init__(self, radius):
        self.radius = radius
    @property
    def area(self):
        return math.pi * self.radius ** 2
    @property
    def perimeter(self):
        return 2 * math.pi * self.radius

在這個例子中,Circle實例存儲了一個實例變量c.radius。c.area和c.perimeter是根據(jù)該值計算得來的。@property裝飾器支持以簡單屬性的形式訪問后面的方法,無需添加額外的()來調(diào)用該方法。方法本身是作為一類特性被隱式處理的,當創(chuàng)建一個實例然后訪問實例的方法時,不會返回原始函數(shù)對象,會得到綁定方法。綁定方法是一個對象,表示將在對象中調(diào)用()運算符時執(zhí)行的方法調(diào)用。這種綁定方法對象是由在后臺執(zhí)行的特性函數(shù)靜默創(chuàng)建的。使用@staticmethod和@classmethod定義靜態(tài)方法和類方法時,實際上就指定了使用不同的特性函數(shù)。
特性還可以攔截操作,以設(shè)置和刪除屬性。這是通過向特性附加其他setter和deleter方法來實現(xiàn)的,例如:

class Foo(object):
    def __init__(self, name):
        self.__name = name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError("Must be a string!")
        self.__name = value
    @name.deleter
    def name(self):
        raise TypeError("Can't delete name")

f = Foo("Guido")
n = f.name
f.name = "Monty" # 調(diào)用setter
f.name = 45 # 調(diào)用setter(TypeError)
del f.name

6. 描述符

使用特性后,對屬性的訪問將由一系列用戶定義的get、set和delete函數(shù)控制。這種屬性控制方式可以通過描述符對象進一步推廣。描述符就是一個表示屬性值的對象,通過實現(xiàn)一個或多個特殊的__get__()、__set__()和__delete__()方法,可以將描述符與屬性訪問機制掛鉤,例如:

class TypedProperty(object):
    def __init__(self, name, type, default=None):
        self.name = "_" + name
        self.type = type
        self.default = default if default else type()
    def __get__(self, instance, cls):
        return getattr(instance, self.name, self.default)
    def __set__(self, instance, value):
        if not isinstance(value, self.type):
            raise TypeError("Must be a %s" % self.type)
        setattr(instance, self.name, value)
    def __delete__(self, instance):
        raise AttributeError("Can't delete attribute")

class Foo(object):
    name = TypedProperty("name", str)
    num = TypedProperty("num", int, 42)

在這個例子中,類TypedProperty定義了一個描述符,分配屬性時它將進行類型檢查,例如:

f = Foo()
a = f.name # 隱式調(diào)用Foo.name.__get__(f.Foo)
f.name = "Guido" # 調(diào)用Foo.name.__set__(f, "Guido")
del f.name # 調(diào)用Foo.name.__delete__(f)

7. 數(shù)據(jù)封裝和私有屬性

默認情況下,類的所有屬性和方法都是“公共的”。這意味著對它們的訪問沒有任何限制。在基類中的所有內(nèi)容都會被 派生類繼承,并可從派生類內(nèi)進行訪問。這可能導(dǎo)致在派生類中定義的對象與在基類中定義的對象之間發(fā)生命名空間沖突,為了解決該問題,類中所有以雙下劃線開頭的名稱都會變成具有_類名__Foo形式的新名稱。例如:

class A(object):
    def __init__(self):
        self.__X = 3 # 變?yōu)閟elf._A__X
    def __spam(self): # 變成_A__spam()
        pass
    def bar(self):
        self.__spam() # 只調(diào)用A.__spam()

class B(A):
    def __init__(self):
        A.__init__(self)
        self.__X = 37 # 變?yōu)閟elf._B__X
    def __spam(self): # 變?yōu)開B__spam()
        pass

這種方案似乎隱藏了數(shù)據(jù),但并沒有嚴格的機制來實際阻止對類的“私有”屬性進行訪問。盡管這種變形似乎是一個額外的處理步驟,但變形過程實際上只在定義類時發(fā)生一次。而且,名稱變形不會在getattr()、hasattr()、setattr()或delattr()等函數(shù)中發(fā)生,因為在這些函數(shù)中,屬性名稱指定為字符串。對于這些函數(shù),需要顯示使用變形名稱。

8. 對象表示和屬性綁定

在類的內(nèi)部,實例是使用字典來實現(xiàn)的,可以用實例的__dict__屬性的形式訪問該字典。這個字典包含的數(shù)據(jù)對每個實例而言都是唯一的。對實例的修改始終會反映到局部__dict__屬性中。同樣,如果直接對__dict__進行修改,所做的修改也會反映在該屬性中。
實例被特殊屬性__class__鏈接回它們的類。在特殊屬性__base__中將類鏈接到它們的基類。只要使用obj.name = value設(shè)置屬性,就會調(diào)用特殊方法obj.__setattr__("name", value)。如果使用del obj.name刪除了一個屬性,就會調(diào)用特殊方法obj.__delattr__("name")。
來查找屬性時,將調(diào)用特殊方法obj.__getattrribute__("name")。如果搜索過程失敗,最終會嘗試調(diào)用類的__getattr__()方法(如果已定義)來查找該屬性。如果這也失敗,就會拋出AttributeError異常。

9. 運算符重載

用戶可以定義Python的所有內(nèi)置運算符,比如,如果希望向Python添加一種新的數(shù)字類型,可以定義一個類并在該類中定義__add__(),例如:

class complex(object):
    def __init__(self, real, imag=0):
        self.real = float(real)
        self.imag = float(imag)
    def __repr__(self):
        return "Complex(%s, %s)" % (self.real, self.imag)
    def __str__(self):
        return "(%g+%gj)" % (self.real, self.imag)
    def __add__(self, other):
        return Complex(self.real + other.real, self.imag + other.imag)
    def __sub__(self, other):
        return Complex(self.real - other.real, self.imag - other.imag)

在這個例子中,__repr__()方法創(chuàng)建一個字符串,可以計算該字符串來重新創(chuàng)建對象。__str__()方法創(chuàng)建具有良好輸出格式的字符串。__add__()和__sub__()實現(xiàn)數(shù)學運算。
?

10. 抽象基類

要定義抽象基類,需要使用abc模塊。該模塊定義一個元類(ABCMeta)和一組裝飾器,可以按如下方式使用:

from abc import ABCMeta, abstractmethod, abstractproperty
class Foo:
    __metaclass__ = ABCMeta
    @abstractmethod
    def spam(self, a, b):
        pass
    @abstractproperty
    def name(self):
        pass

要定義抽象類,需要將其元類如上所示設(shè)置為ABCMeta。因為抽象類的實現(xiàn)離不開元類。在抽象類中,@abstractmethod和@abstractproperty裝飾器指定Foo的子類必須實現(xiàn)一個方法或特性。抽象類不能直接實例化。這一限制也適用于派生類,如果派生類沒有實現(xiàn)一個或多個抽象方法,那么嘗試創(chuàng)建派生類實例將會失敗。
抽象基類支持對已經(jīng)存在的類進行注冊,使其屬于該基類。這是用register()方法完成的,例如:

class Grok(object):
    def spam(self, a, b):
        print("Grok.spam")

Foo.register(Grok)

10. 元類

在Python中定義類時,類定義本身將成為一個對象。例如:

class Foo(object): pass
isinstance(Foo, object) # True

類對象的這種創(chuàng)建方式是由一種名為元類的特殊對象控制的。即元類就是知道如何創(chuàng)建和管理類的對象。如果查看Foo的類型,將會發(fā)現(xiàn)它的類型為type。
使用class語句定義新類時,類主體將作為其自己的私有字典內(nèi)的一系列語句來執(zhí)行。語句的執(zhí)行與正常代碼執(zhí)行過程相同,只是會在私有成員上發(fā)生名稱變形。最后,類的名稱、基類列表和字典將傳遞給元類的解構(gòu)函數(shù),以創(chuàng)建相應(yīng)的類對象。類創(chuàng)建的最后一步,也就是調(diào)用元類type()的步驟,可以自定義。
類可以顯式地指定其元類,這通過在基類元組中提供metaclass關(guān)鍵字參數(shù)來實現(xiàn),例如:

class Foo(metaclass=type)
    __metaclass__ = type
    ...

如果沒有顯示指定元類, class語句將檢查基類元組中的第一個條目。在這種情況下,元類與第一個基類的類型相同。如果沒有指定基類,class語句將檢查全局變量__metaclass__是否存在。如果找到了該變量,將使用它來創(chuàng)建類。如果沒有找到任何__metaclass__值,Python將使用默認的元類(type())。
?

10. 類裝飾器

類裝飾器是一種函數(shù),它接受類作為輸入并返回類作為輸出,例如:

registry = { }
def register(cls):
    registry[cls.__clsid__] = cls
    return cls

要使用該函數(shù),可以在類定義前將它用作裝飾器,例如:

class Foo(object):
    __clsid__ = "123-456"
    def bar(self):
        pass

等同的方式如下:

class Foo(object):
    __clsid__ = "123-456"
    def bar(self):
        pass
register(Foo)

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。


文章名稱:[Python]類與面向?qū)ο缶幊?創(chuàng)新互聯(lián)
文章位置:http://weahome.cn/article/dpioed.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部