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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

python中的类与继承

發布時間:2023/12/13 综合教程 31 生活家
生活随笔 收集整理的這篇文章主要介紹了 python中的类与继承 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Class

類的定義以及實例的建立

Python中,類通過class關鍵字定義。

例如最簡單的一個類定義可以為:

class Person(object):
    pass

Python的編程習慣,類名以大寫字母開頭,緊接著是(object),表示該類是從哪個類繼承下來的。

例如上面的person類,我們可以創建很多實例:

zhangsan=Person()
lisi=Person()

實例的屬性及方法

Python是動態語言,對每一個實例,都可以直接給他們的屬性賦值,即使類中并無定義,例如,給xiaoming這個實例加上name、gender和birth屬性:

xiaoming = Person()
xiaoming.name = 'Xiao Ming'
xiaoming.gender = 'Male'
xiaoming.birth = '1990-1-1'

__init__()

如上所說,我們可以自由地給一個實例綁定各種屬性,但是,現實世界中,一種類型的實例應該擁

有相同名字的屬性。例如,Person類應該在創建的時候就擁有name、gender和birth屬性。

所以在創建類時,我們可以使用__init__()方法,當創建實例時,__init__()方法被自動調用,我們就

能在此為每個實例都統一加上以下屬性:

class Person(object):
    def __init__(self, name, gender, birth):
        self.name = name
        self.gender = gender
        self.birth = birth

__init__()方法的第一個參數必須是self(也可以用別的名字,但建議使用習慣用法),后續參數則

可以自由指定,和定義函數沒有任何區別。

同時,創建實例時,就必須要提供除self以外的參數:

xiaoming = Person('Xiao Ming', 'Male', '1991-1-1')
xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')

屬性的訪問限制(私有屬性)

我們可以給一個實例綁定很多屬性,如果有些屬性不希望被外部訪問到怎么辦?

Python對屬性權限的控制是通過屬性名來實現的,如果一個屬性由雙下劃線開頭(__),該屬性就無

法被外部訪問。例如:

class Person(object):
    def __init__(self, name):
        self.name = name
        self._title = 'Mr'
        self.__job = 'Student'

p1=Person("zhangsan")

print(p1.name,'
')
print(p1._title,'
')
try:
    print(p1.__job)
except:
    print("Error")

結果:

zhangsan 

Mr 

Error

可以看出只有__job無法被訪問

實例的方法

雖然私有屬性無法從外部訪問,但是,從類的內部是可以訪問的。除了可以定義實例的屬性外,還可以定義實例的方法。

例如我們可以定義一個__name私有屬性,同時創建一個get_name方法去訪問__name:

class Person(object):

    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

p2=Person("Bob")
print(p2.get_name())

結果

Bob

get_name(self)就是一個實例方法,它的第一個參數是self。__init__(self, name)其實也可看做是一個特殊的實例方法。

在實例方法內部,可以訪問所有實例屬性,這樣,如果外部需要訪問私有屬性,可以通過方法調用獲得,這種數據封裝的形式除了能保護內部數據一致性外,還可以簡化外部調用的難度。

python中實例方法也是屬性

我們在class中定義的實例方法其實也是屬性,它實際上是一個函數對象,因為方法也是一個屬性,所以,它也可以動態地添加到實例上,只是需要用types.MethodType()把一個函數變為一個方法:

import types
def Pn_get_name(self):
    return str("This person's name is :"+self.name)

class Person(object):
    def __init__(self, name):
        self.name = name

p1=Person("Alice")
p2=Person("Bob")

p1.get_name=types.MethodType(Pn_get_name,p1)

print(p1.get_name(),'
')
print(p2.get_name())

結果:

This person's name is :Alice 

Traceback (most recent call last):
  File "D:/pythonwork/practise/test.py", line 15, in <module>
    print(p2.get_name())
AttributeError: 'Person' object has no attribute 'get_name'

給一個實例動態添加方法并不常見,直接在class中定義要更直觀

類的屬性及方法

類是模板,而實例則是根據類創建的對象。綁定在一個實例上的屬性不會影響其他實例,但是,類本身也是一個對象,如果在類上綁定一個屬性,則所有實例都可以訪問類的屬性,并且,所有實例訪問的類屬性都是同一個,也就是說,實例屬性每個實例各自擁有,互相獨立,而類屬性有且只有一份。

定義類屬性可以直接在class中定義:

class Person(object):
    address = 'Earth'
    def __init__(self, name):
        self.name = name

因為類屬性是直接綁定在類上的,所以,訪問類屬性可以直接用類名訪問,也可以使用實例訪問,例如:

class Person(object):
    address = 'Earth'
    def __init__(self, name):
        self.name = name

p1=Person("zhangsan")

print(Person.address)
print(p1.address)

結果:

Earth
Earth

由于Python是動態語言,類屬性也是可以動態添加和修改的:

Person.address = 'China'

print(Person.address)
print(p1.address)

結果:

China
China

因為類屬性只有一份,所以,當Person類的address改變時,所有實例訪問到的類屬性都改變了。

注意:如果在實例變量上修改類屬性,則實際上是給實例綁定了一個與類屬性同名的實例屬性,而

訪問時會優先訪問實例屬性:

p1.address="China"

print(Person.address)
print(p1.address)

結果:

Earth
China

類的方法

和屬性類似,方法也分實例方法和類方法。

在class中定義的全部是實例方法,實例方法第一個參數self是實例本身。

要在class中定義類方法,我們通過標記一個@classmethod,該方法將綁定到Person類上,而非

類的實例。類方法的第一個參數將傳入類本身,通常將參數名命名為cls,下面例子中

的cls.count實際上相當于Person.count。

class Person(object):
    count = 0
    @classmethod
    def how_many(cls):
        return cls.count

    def __init__(self, name):
        self.name = name
        Person.count = Person.count + 1

print (Person.how_many())
p1 = Person('Bob')
print (Person.how_many())

結果:

0
1

類的繼承

如果已經定義了Person類,需要定義新的Student和Teacher類時,可以直接從Person類繼承,定義Student類時,只需要把額外的屬性加上,例如score:

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

注意:

一定要用super(Student, self).__init__(name, gender)去初始化父類,否則,繼承自Person的Student將沒有name和gender。

函數super(Student, self)將返回當前類繼承的父類,即Person,然后調用__init__()方法,注意self參數已在super()中傳入,在__init__()中將隱式傳遞,不需要寫出(也不能寫)。

python中的多態

類具有繼承關系,并且子類類型可以向上轉型看做父類類型,如果我們從Person派生出Student和

Teacher,并都寫了一個 同名的whoAmI()方法,當我們調用實例的whoAmI()方法時,總是先查找

它自身的定義,如果沒有定義,則順著繼承鏈向上查找,直到在某個父類中找到為止。

例如:

class Person(object):
    pass
    def Pstr(self):
        print("This is Person class method")

class Student(Person):
    def __init__(self, name):
        self.name = name
    def Pstr(self):
        print("This is Student class method")

class Teacher(Person):
    def __init__(self, name):
        self.name = name

p1=Student("Alice")
p2=Teacher("Tom")

p1.Pstr()
p2.Pstr()

結果:

This is Student class method
This is Person class method

python中的多重繼承

除了從一個父類繼承外,Python允許從多個父類繼承,稱為多重繼承。

例如:

class A(object):
    def __init__(self, a):
        print 'init A...'
        self.a = a

class B(A):
    def __init__(self, a):
        super(B, self).__init__(a)
        print 'init B...'

class C(A):
    def __init__(self, a):
        super(C, self).__init__(a)
        print 'init C...'

class D(B, C):
    def __init__(self, a):
        super(D, self).__init__(a)
        print 'init D...'

像這樣,D同時繼承自B和C,也就是D擁有了A、B、C的全部功能。多重繼承通過super()調用

__init__()方法時,A雖然被繼承了兩次,但__init__()只調用一次:

運行測試代碼:

d=D('d')

結果:

init A...
init C...
init B...
init D...

類的定制

我們可以使用一些特殊的方法來定制我們自己定義的類

python中 __slots__

由于Python是動態語言,任何實例在運行期都可以動態地添加屬性。

如果要限制添加的屬性,例如,Student類只允許添加name、gender和score這3個屬性,就可以利用Python的一個特殊的__slots__來實現。

例如:

class Student(object):
    __slots__ = ('name', 'gender', 'score')
    def __init__(self, name, gender, score):
        self.name = name
        self.gender = gender
        self.score = score

進行操作:

>>> s = Student('Bob', 'male', 59)
>>> s.name = 'Tim' # OK
>>> s.score = 99 # OK
>>> s.grade = 'A'
Traceback (most recent call last):
  ...
AttributeError: 'Student' object has no attribute 'grade'

__slots__的目的是限制當前類所能擁有的屬性,如果不需要添加任意動態的屬性,使用__slots__也能節省內存。

python中 __str__和__repr__對于print的改變

例如原本對于類中的實例直接打印:

class Student(object):
    def __init__(self, name):
        self.name = name

p1=Student("Alice")

print(p1)

結果:

<__main__.Student object at 0x000002672671EF98>

但是我們想讓print實例的時候直接打印類名與實例名我們就可以使用__str__:

class Student(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return 'Student: %s' % self.name

p1=Student("Alice")

print(p1)

結果:

Student: Alice

但是我們在命令交互行中直接輸入變量p1卻不是這樣:

>>>p1
<Student object at 0x0000023C8F331A58>

這是因為Python 定義了__str__()和__repr__()兩種方法,__str__()用于顯示給用戶,而__repr__()

用于顯示給開發人員。

同理我們可以定義類的__repr__()例如直接:

__repr__ = __str__

這樣直接在命令交互中直接輸入變量p1也是同樣效果了

>>>p1
Student: Alice

python3中__cmp__方法已經不再使用

在python2中該方法可實現對于sorted()函數改變,不再贅述

python中 __len__對于len()的改變

如果一個類表現得像一個list,要獲取有多少個元素,就得用len()函數。

要讓len()函數工作正常,類必須提供一個特殊方法__len__(),它返回元素的個數。

例如,我們寫一個 Students 類,把名字傳進去:

class Students(object):
    def __init__(self, *args):
        self.names = args
    def __len__(self):
        return len(self.names)

ss = Students('Bob', 'Alice', 'Tim')
print (len(ss))

結果:

3 

類的實例的數學運算

同以上特殊方法一樣,我們可以利用

__add__對符號 + 進行改變

__sub__對符號 -進行改變

__mul__對符號 * 進行改變

__div__對符號 / 進行改變

例如:

我們創建一個分數的類:

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

我們想實現符號+直接運用在我們創建的實例上我們需要這樣寫代碼:

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q
    def __add__(self, r):
        return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
    def __str__(self):
        return '%s/%s' % (self.p, self.q)
    __repr__ = __str__

r1 = Rational(1, 3)
r2 = Rational(1, 2)
print(r1+r2)

結果:

5/6

類的實例的類型轉換

如上,Rational類實現了有理數(分數)類的數學運算,但是,如果要把結果轉為int或float怎么辦?

我們對于整數和浮點數可以直接使用int()和float()函數直接轉換,但是我們肯定無法直接使用在我們所創建的類的實例上,因此我們需要使用__int__()和__float__()

例如__int__:

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q
    def __int__(self):
        return self.p//self.q   #python3中//是整數結果

結果:

>>> print int(Rational(7, 2))
3

python中 @property

對于Student類:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

當我們想要修改一個Student的scroe屬性時,可以這么寫:

s = Student('Bob', 59)
s.score = 1000

顯然,直接給屬性賦值無法檢查分數的有效性。

如果利用兩個方法:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

這樣一來,s.set_score(1000)就會報錯。

這種使用get/set方法來封裝對一個屬性的訪問在許多面向對象編程的語言中都很常見。但是寫s.get_score()和s.set_score()沒有直接寫s.score來得直接。

而在Python中,python支持高階函數,在函數式編程中我們介紹了裝飾器函數,可以用裝飾器函數@property。

把get/set方法“裝飾”成屬性調用:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

現在再設置score會怎么樣呢:

s = Student('Bob', 59)
s.score = 60
print (s.score)
try:
    s.score = 1000
except:
    print("Error")

結果:

60
Error

注意:第一個score(self)是get方法,用@property裝飾,第二個score(self, score)是set方法,用@score.setter裝飾,@score.setter是前一個@property裝飾后的副產品。說明對score賦值實際調用的是set方法。

如果沒有定義set方法即@score.setter,就不能對“屬性”賦值,這時,就可以創建一個只讀“屬性”。

python中 __call__

在Python中,函數其實是一個對象:

>>> f = abs
>>> f.__name__
'abs'
>>> f(-123)
123

由于f可以被調用,所以,f被稱為可調用對象。而所有的函數都是可調用對象。

一個類實例也可以變成一個可調用對象,只需要實現一個特殊方法__call__()。

我們把Person類變成一個可調用對象:

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def __call__(self, friend):
        print ('My name is %s...' % self.name)
        print ('My friend is %s...' % friend)

現在可以對Person實例直接調用:

>>> p = Person('Bob', 'male')
>>> p('Tim')
My name is Bob...
My friend is Tim...

單看p('Tim')你無法確定p是一個函數還是一個類實例,所以,在Python中,函數也是對象,對象和函數的區別并不顯著。

總結

以上是生活随笔為你收集整理的python中的类与继承的全部內容,希望文章能夠幫你解決所遇到的問題。

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