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

歡迎訪問 生活随笔!

生活随笔

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

python

python高级属性 用法 编程_python高级编程之面向对象高级编程

發(fā)布時(shí)間:2025/3/11 python 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python高级属性 用法 编程_python高级编程之面向对象高级编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 面向?qū)ο缶幊?/p>

面向?qū)ο筮@節(jié)比較簡(jiǎn)單,就稍微總結(jié)幾個(gè)特殊的點(diǎn)。

特殊方法__init__前后分別有兩個(gè)下劃線,__init__方法的第一個(gè)參數(shù)永遠(yuǎn)是self,表示創(chuàng)建的實(shí)例本身,因此,在__init__方法內(nèi)部,就可以把各種屬性綁定到self,因?yàn)閟elf就指向創(chuàng)建的實(shí)例本身。

有了__init__方法,在創(chuàng)建實(shí)例的時(shí)候,就不能傳入空的參數(shù)了,必須傳入與__init__方法匹配的參數(shù),但self不需要傳,Python解釋器自己會(huì)把實(shí)例變量傳進(jìn)去。

如果要讓內(nèi)部屬性不被外部訪問,可以把屬性的名稱前加上兩個(gè)下劃線__,在Python中,實(shí)例的變量名如果以__開頭,就變成了一個(gè)私有變量(private),只有內(nèi)部可以訪問,外部不能訪問。

需要注意的是,在Python中,變量名類似__xxx__的,也就是以雙下劃線開頭,并且以雙下劃線結(jié)尾的,是特殊變量,特殊變量是可以直接訪問的,不是private變量,所以,不能用__name__、__score__這樣的變量名。

多態(tài):當(dāng)我們需要傳入Dog、Cat、Tortoise……時(shí),我們只需要接收Animal類型就可以了,因?yàn)镈og、Cat、Tortoise……都是Animal類型,然后,按照Animal類型進(jìn)行操作即可。由于Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類或者子類,就會(huì)自動(dòng)調(diào)用實(shí)際類型的run()方法,這就是多態(tài)。

“鴨子特性”:對(duì)于靜態(tài)語言(例如Java)來說,如果需要傳入Animal類型,則傳入的對(duì)象必須是Animal類型或者它的子類,否則,將無法調(diào)用run()方法。

對(duì)于Python這樣的動(dòng)態(tài)語言來說,則不一定需要傳入Animal類型。我們只需要保證傳入的對(duì)象有一個(gè)run()方法就可以了。

2 面向?qū)ο蟾呒?jí)編程

2.1 獲取對(duì)象信息

2.1.1 type()

判斷對(duì)象類型,使用type()函數(shù):

>>> type(123)

>>> type('str')

>>> type(None)

如果要判斷一個(gè)對(duì)象是否是函數(shù)可以使用types模塊中定義的常量:

>>> import types

>>> def fn():

... pass

...

>>> type(fn)==types.FunctionType

True

>>> type(abs)==types.BuiltinFunctionType

True

>>> type(lambda x: x)==types.LambdaType

True

>>> type((x for x in range(10)))==types.GeneratorType

True

對(duì)于class的繼承關(guān)系來說,使用type()就很不方便。我們要判斷class的類型,可以使用isinstance()函數(shù)。

2.1.2 dir()

如果要獲得一個(gè)對(duì)象的所有屬性和方法,可以使用dir()函數(shù),它返回一個(gè)包含字符串的list,比如,獲得一個(gè)str對(duì)象的所有屬性和方法:

>>> dir('ABC')

['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

類似__xxx__的屬性和方法在Python中都是有特殊用途的,比如__len__方法返回長(zhǎng)度。在Python中,如果你調(diào)用len()函數(shù)試圖獲取一個(gè)對(duì)象的長(zhǎng)度,實(shí)際上,在len()函數(shù)內(nèi)部,它自動(dòng)去調(diào)用該對(duì)象的__len__()方法,所以,下面的代碼是等價(jià)的:

>>> len('ABC')

3

>>> 'ABC'.__len__()

3

僅僅把屬性和方法列出來是不夠的,配合getattr()、setattr()以及hasattr(),我們可以直接操作一個(gè)對(duì)象的狀態(tài):

>>> class MyObject(object):

... def __init__(self):

... self.x = 9

... def power(self):

... return self.x * self.x

...

>>> obj = MyObject()

緊接著,可以測(cè)試該對(duì)象的屬性:

>>> hasattr(obj, 'x') # 有屬性'x'嗎?

True

>>> obj.x

9

>>> hasattr(obj, 'y') # 有屬性'y'嗎?

False

>>> setattr(obj, 'y', 19) # 設(shè)置一個(gè)屬性'y'

>>> hasattr(obj, 'y') # 有屬性'y'嗎?

True

>>> getattr(obj, 'y') # 獲取屬性'y'

19

>>> obj.y # 獲取屬性'y'

19

如果試圖獲取不存在的屬性,會(huì)拋出AttributeError的錯(cuò)誤:

>>> getattr(obj, 'z') # 獲取屬性'z'

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'MyObject' object has no attribute 'z'

可以傳入一個(gè)default參數(shù),如果屬性不存在,就返回默認(rèn)值:

>>> getattr(obj, 'z', 404) # 獲取屬性'z',如果不存在,返回默認(rèn)值404

404

也可以獲得對(duì)象的方法:

>>> hasattr(obj, 'power') # 有屬性'power'嗎?

True

>>> getattr(obj, 'power') # 獲取屬性'power'

>

>>> fn = getattr(obj, 'power') # 獲取屬性'power'并賦值到變量fn

>>> fn # fn指向obj.power

>

>>> fn() # 調(diào)用fn()與調(diào)用obj.power()是一樣的

81

2.2 使用__slots__

如果我們想要限制實(shí)例的屬性怎么辦?比如,只允許對(duì)Student實(shí)例添加name和age屬性。

為了達(dá)到限制的目的,Python允許在定義class的時(shí)候,定義一個(gè)特殊的__slots__變量,來限制該class實(shí)例能添加的屬性:

class Student(object):

__slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱

然后,我們?cè)囋?#xff1a;

>>> s = Student() # 創(chuàng)建新的實(shí)例

>>> s.name = 'Michael' # 綁定屬性'name'

>>> s.age = 25 # 綁定屬性'age'

>>> s.score = 99 # 綁定屬性'score'

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'Student' object has no attribute 'score'

2.3 使用@property

在綁定屬性時(shí),如果我們直接把屬性暴露出去,雖然寫起來很簡(jiǎn)單,但是沒辦法檢查參數(shù),導(dǎo)致可以隨便給屬性賦值。

對(duì)于類的方法,裝飾器一樣起作用。Python內(nèi)置的@property裝飾器就是負(fù)責(zé)把一個(gè)方法變成屬性調(diào)用的:

class Student(object):

@property

def score(self):

return self._score

@score.setter

def score(self, value):

if not isinstance(value, int):

raise ValueError('score must be an integer!')

if value < 0 or value > 100:

raise ValueError('score must between 0 ~ 100!')

self._score = value

@property的使用方法是:把一個(gè)getter方法變成屬性,只需要加上@property就可以了,此時(shí),@property本身又創(chuàng)建了另一個(gè)裝飾器@score.setter,負(fù)責(zé)把一個(gè)setter方法變成屬性賦值,于是,我們就擁有一個(gè)可控的屬性操作。

>>> s = Student()

>>> s.score = 60 # OK,實(shí)際轉(zhuǎn)化為s.set_score(60)

>>> s.score # OK,實(shí)際轉(zhuǎn)化為s.get_score()

60

>>> s.score = 9999

Traceback (most recent call last):

...

ValueError: score must between 0 ~ 100!

注意到這個(gè)神奇的@property,我們?cè)趯?duì)實(shí)例屬性操作的時(shí)候,就知道該屬性很可能不是直接暴露的,而是通過getter和setter方法來實(shí)現(xiàn)的。

還可以定義只讀屬性,只定義getter方法,不定義setter方法就是一個(gè)只讀屬性。

2.4 多重繼承

在設(shè)計(jì)類的繼承關(guān)系時(shí),通常,主線都是單一繼承下來的,例如,Ostrich繼承自Bird。但是,如果需要“混入”額外的功能,通過多重繼承就可以實(shí)現(xiàn),比如,讓Ostrich除了繼承自Bird外,再同時(shí)繼承Runnable。Python允許使用多重繼承,這種設(shè)計(jì)通常稱之為MixIn。

MixIn的目的就是給一個(gè)類增加多個(gè)功能,這樣,在設(shè)計(jì)類的時(shí)候,我們優(yōu)先考慮通過多重繼承來組合多個(gè)MixIn的功能,而不是設(shè)計(jì)多層次的復(fù)雜的繼承關(guān)系。

2.5 定制類

后面用到實(shí)際例子時(shí)再補(bǔ)充。

2.6 使用枚舉類

當(dāng)我們需要定義常量時(shí),一個(gè)辦法是用大寫變量通過整數(shù)來定義,例如月份:

JAN = 1

FEB = 2

MAR = 3

...

NOV = 11

DEC = 12

好處是簡(jiǎn)單,缺點(diǎn)是類型是int,并且仍然是變量。

更好的方法是為這樣的枚舉類型定義一個(gè)class類型,然后,每個(gè)常量都是class的一個(gè)唯一實(shí)例。Python提供了Enum類來實(shí)現(xiàn)這個(gè)功能:

from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

這樣我們就獲得了Month類型的枚舉類,可以直接使用Month.Jan來引用一個(gè)常量,或者枚舉它的所有成員:

for name, member in Month.__members__.items():

print(name, '=>', member, ',', member.value)

value屬性則是自動(dòng)賦給成員的int常量,默認(rèn)從1開始計(jì)數(shù)。

如果需要更精確地控制枚舉類型,可以從Enum派生出自定義類:

from enum import Enum, unique

@unique

class Weekday(Enum):

Sun = 0 # Sun的value被設(shè)定為0

Mon = 1

Tue = 2

Wed = 3

Thu = 4

Fri = 5

Sat = 6

@unique裝飾器可以幫助我們檢查保證沒有重復(fù)值。

2.7 使用元類

type()函數(shù)可以查看一個(gè)類型或變量的類型,例如Hello是一個(gè)class,它的類型就是type,而h是一個(gè)實(shí)例,它的類型就是class Hello。type()函數(shù)既可以返回一個(gè)對(duì)象的類型,又可以創(chuàng)建出新的類型,比如,我們可以通過type()函數(shù)創(chuàng)建出Hello類,而無需通過class Hello(object)...的定義。

我們說class的定義是運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建的,而創(chuàng)建class的方法就是使用type()函數(shù)。通過type()函數(shù)創(chuàng)建的類和直接寫class是完全一樣的,因?yàn)镻ython解釋器遇到class定義時(shí),僅僅是掃描一下class定義的語法,然后調(diào)用type()函數(shù)創(chuàng)建出class:

>>> def fn(self, name='world'): # 先定義函數(shù)

... print('Hello, %s.' % name)

...

>>> Hello = type('Hello', (object,), dict(hello=fn)) # 創(chuàng)建Hello class

>>> h = Hello()

>>> h.hello()

Hello, world.

>>> print(type(Hello))

>>> print(type(h))

要?jiǎng)?chuàng)建一個(gè)class對(duì)象,type()函數(shù)依次傳入3個(gè)參數(shù):

class的名稱;

繼承的父類集合,注意Python支持多重繼承,如果只有一個(gè)父類,別忘了tuple的單元素寫法;

class的方法名稱與函數(shù)綁定,這里我們把函數(shù)fn綁定到方法名hello上。

2.7.1 metaclass

除了使用type()動(dòng)態(tài)創(chuàng)建類以外,要控制類的創(chuàng)建行為,還可以使用metaclass。metaclass,直譯為元類,簡(jiǎn)單的解釋就是:當(dāng)我們定義了類以后,就可以根據(jù)這個(gè)類創(chuàng)建出實(shí)例,所以:先定義類,然后創(chuàng)建實(shí)例。

但是如果我們想創(chuàng)建出類呢?那就必須根據(jù)metaclass創(chuàng)建出類,所以:先定義metaclass,然后創(chuàng)建類。連接起來就是:先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實(shí)例。

所以,metaclass允許你創(chuàng)建類或者修改類。換句話說,你可以把類看成是metaclass創(chuàng)建出來的“實(shí)例”。

先看一個(gè)簡(jiǎn)單的例子,這個(gè)metaclass可以給我們自定義的MyList增加一個(gè)add方法。定義ListMetaclass,按照默認(rèn)習(xí)慣,metaclass的類名總是以Metaclass結(jié)尾,以便清楚地表示這是一個(gè)metaclass:

# metaclass是類的模板,所以必須從`type`類型派生:

class ListMetaclass(type):

def __new__(cls, name, bases, attrs):

attrs['add'] = lambda self, value: self.append(value)

return type.__new__(cls, name, bases, attrs)

有了ListMetaclass,我們?cè)诙x類的時(shí)候還要指示使用ListMetaclass來定制類,傳入關(guān)鍵字參數(shù)metaclass:

class MyList(list, metaclass=ListMetaclass):

pass

當(dāng)我們傳入關(guān)鍵字參數(shù)metaclass時(shí),魔術(shù)就生效了,它指示Python解釋器在創(chuàng)建MyList時(shí),要通過ListMetaclass.__new__()來創(chuàng)建,在此,我們可以修改類的定義,比如,加上新的方法,然后,返回修改后的定義。__new__()方法接收到的參數(shù)依次是:

當(dāng)前準(zhǔn)備創(chuàng)建的類的對(duì)象;

類的名字;

類繼承的父類集合;

類的方法集合。

測(cè)試一下MyList是否可以調(diào)用add()方法:

>>> L = MyList()

>>> L.add(1)

>> L

[1]

而普通的list沒有add()方法:

>>> L2 = list()

>>> L2.add(1)

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'list' object has no attribute 'add'

使用元類這塊比較復(fù)雜,等樓主后面涉及到這塊的實(shí)際例子再來補(bǔ)充這塊。

總結(jié)

以上是生活随笔為你收集整理的python高级属性 用法 编程_python高级编程之面向对象高级编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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