類是一個抽象的概念,我們可以把它理解為具有相同屬性和方法的一組對象的集合,而實例則是一個具體的對象。我們還是先來看看在 Python 中怎么定義一個類。
這里以動物(Animal)類為例,Python 提供關(guān)鍵字 class 來聲明一個類:
class Animal(object):
pass
其中,Animal 是類名,通常類名的首字母采用大寫(如果有多個單詞,則每個單詞的首字母大寫),后面緊跟著 (object),表示該類是從哪個類繼承而來的,所有類最終都會繼承自 object 類。
類定義好了,接下來我們就可以創(chuàng)建實例了:
>>> animal = Animal() # 創(chuàng)建一個實例對象
>>> animal
<__main__.Animal at 0x1030a44d0>
我們在創(chuàng)建實例的時候,還可以傳入一些參數(shù),以初始化對象的屬性,為此,我們需要添加一個 __init__ 方法:
class Animal(object):
def __init__(self, name):
self.name = name
然后,在創(chuàng)建實例的時候,傳入?yún)?shù):
>>> animal = Aniaml('dog1') # 傳入?yún)?shù) 'dog1'
>>> animal.name # 訪問對象的 name 屬性
'dog1'
我們可以把 __init__ 理解為對象的初始化方法,它的第一個參數(shù)永遠是 self,指向創(chuàng)建的實例本身。定義了 __init__ 方法,我們在創(chuàng)建實例的時候,就需要傳入與 __init__ 方法匹配的參數(shù)。
接下來,我們再來添加一個方法:
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
我們添加了方法 greet,看看下面的使用:
>>> dog1 = Animal('dog1')
>>> dog1.name
'dog1'
>>> dog1.greet()
Hello, I am dog1.
現(xiàn)在,讓我們做一下總結(jié)。我們在 Animal 類定義了兩個方法:__init__ 和 greet。__init__ 是 Python 中的特殊方法(special method),它用于對對象進行初始化,類似于 C++ 中的構(gòu)造函數(shù);greet 是我們自定義的方法。
注意到,我們在上面定義的兩個方法有一個共同點,就是它們的第一個參數(shù)都是 self,指向?qū)嵗旧?,也就是說它們是和實例綁定的函數(shù),這也是我們稱它們?yōu)榉椒ǘ皇呛瘮?shù)的原因。
在某些情況下,我們希望限制用戶訪問對象的屬性或方法,也就是希望它是私有的,對外隱蔽。比如,對于上面的例子,我們希望 name 屬性在外部不能被訪問,我們可以在屬性或方法的名稱前面加上兩個下劃線,即 __,對上面的例子做一點改動:
class Animal(object):
def __init__(self, name):
self.__name = name
def greet(self):
print 'Hello, I am %s.' % self.__name
>>> dog1 = Animal('dog1')
>>> dog1.__name # 訪問不了
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-206-7f6730db631e> in <module>()
----> 1 dog1.__name
AttributeError: 'Animal' object has no attribute '__name'
>>> dog1.greet() # 可以訪問
Hello, I am dog1.
可以看到,加了 __ 的 __name 是不能訪問的,而原來的 greet 仍可以正常訪問。
需要注意的是,在 Python 中,以雙下劃線開頭,并且以雙下劃線結(jié)尾(即 __xxx__)的變量是特殊變量,特殊變量是可以直接訪問的。所以,不要用 __name__ 這樣的變量名。
另外,如果變量名前面只有一個下劃線 _,表示不要隨意訪問這個變量,雖然它可以直接被訪問。
當(dāng)我們拿到一個對象時,我們往往會考察它的類型和方法等,比如:
>>> a = 123
>>> type(a)
int
>>> b = '123'
>>> type(b)
str
當(dāng)我們拿到一個類的對象時,我們用什么去考察它呢?回到前面的例子:
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
type使用 type(obj) 來獲取對象的相應(yīng)類型:
>>> dog1 = Animal('dog1')
>>> type(dog1)
__main__.Animal
isinstance使用 isinstance(obj, type) 判斷對象是否為指定的 type 類型的實例:
>>> isinstance(dog1, Animal)
True
第 3 招:使用 hasattr/getattr/setattr
hasattr(obj, attr) 判斷對象是否具有指定屬性/方法;getattr(obj, attr[, default]) 獲取屬性/方法的值, 要是沒有對應(yīng)的屬性則返回 default 值(前提是設(shè)置了 default),否則會拋出 AttributeError 異常;setattr(obj, attr, value) 設(shè)定該屬性/方法的值,類似于 obj.attr=value;看下面例子:
>>> hasattr(dog1, 'name')
True
>>> hasattr(dog1, 'x')
False
>>> hasattr(dog1, 'greet')
True
>>> getattr(dog1, 'name')
'dog1'
>>> getattr(dog1, 'greet')
<bound method Animal.greet of <__main__.Animal object at 0x10c3564d0>>
>>> getattr(dog1, 'x')
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-241-42f5b7da1012> in <module>()
----> 1 getattr(dog1, 'x')
AttributeError: 'Animal' object has no attribute 'x'
>>> getattr(dog1, 'x', 'xvalue')
'xvalue'
>>> setattr(dog1, 'age', 12)
>>> dog1.age
12
dir使用 dir(obj) 可以獲取相應(yīng)對象的所有屬性和方法名的列表:
>>> dir(dog1)
['__class__',
'__delattr__',
'__dict__',
'__doc__',
'__format__',
'__getattribute__',
'__hash__',
'__init__',
'__module__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'age',
'greet',
'name']
type(obj):來獲取對象的相應(yīng)類型;isinstance(obj, type):判斷對象是否為指定的 type 類型的實例;hasattr(obj, attr):判斷對象是否具有指定屬性/方法;getattr(obj, attr[, default]) 獲取屬性/方法的值, 要是沒有對應(yīng)的屬性則返回 default 值(前提是設(shè)置了 default),否則會拋出 AttributeError 異常;setattr(obj, attr, value):設(shè)定該屬性/方法的值,類似于 obj.attr=value;dir(obj):可以獲取相應(yīng)對象的所有屬性和方法名的列表: