類是一個抽象的概念,我們可以把它理解為具有相同屬性和方法的一組對象的集合,而實例則是一個具體的對象。我們還是先來看看在 Python 中怎么定義一個類。
這里以動物(Animal)類為例,Python 提供關鍵字 class
來聲明一個類:
class Animal(object):
pass
其中,Animal
是類名,通常類名的首字母采用大寫(如果有多個單詞,則每個單詞的首字母大寫),后面緊跟著 (object)
,表示該類是從哪個類繼承而來的,所有類最終都會繼承自 object
類。
類定義好了,接下來我們就可以創(chuàng)建實例了:
>>> animal = Animal() # 創(chuàng)建一個實例對象
>>> animal
<__main__.Animal at 0x1030a44d0>
我們在創(chuàng)建實例的時候,還可以傳入一些參數,以初始化對象的屬性,為此,我們需要添加一個 __init__
方法:
class Animal(object):
def __init__(self, name):
self.name = name
然后,在創(chuàng)建實例的時候,傳入參數:
>>> animal = Aniaml('dog1') # 傳入參數 'dog1'
>>> animal.name # 訪問對象的 name 屬性
'dog1'
我們可以把 __init__
理解為對象的初始化方法,它的第一個參數永遠是 self
,指向創(chuàng)建的實例本身。定義了 __init__
方法,我們在創(chuàng)建實例的時候,就需要傳入與 __init__
方法匹配的參數。
接下來,我們再來添加一個方法:
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.
現在,讓我們做一下總結。我們在 Animal 類定義了兩個方法:__init__
和 greet
。__init__
是 Python 中的特殊方法(special method),它用于對對象進行初始化,類似于 C++ 中的構造函數;greet
是我們自定義的方法。
注意到,我們在上面定義的兩個方法有一個共同點,就是它們的第一個參數都是 self
,指向實例本身,也就是說它們是和實例綁定的函數,這也是我們稱它們?yōu)榉椒ǘ皇呛瘮档脑颉?/p>
在某些情況下,我們希望限制用戶訪問對象的屬性或方法,也就是希望它是私有的,對外隱蔽。比如,對于上面的例子,我們希望 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 中,以雙下劃線開頭,并且以雙下劃線結尾(即 __xxx__
)的變量是特殊變量,特殊變量是可以直接訪問的。所以,不要用 __name__
這樣的變量名。
另外,如果變量名前面只有一個下劃線 _
,表示不要隨意訪問這個變量,雖然它可以直接被訪問。
當我們拿到一個對象時,我們往往會考察它的類型和方法等,比如:
>>> a = 123
>>> type(a)
int
>>> b = '123'
>>> type(b)
str
當我們拿到一個類的對象時,我們用什么去考察它呢?回到前面的例子:
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
type
使用 type(obj)
來獲取對象的相應類型:
>>> 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])
獲取屬性/方法的值, 要是沒有對應的屬性則返回 default 值(前提是設置了 default),否則會拋出 AttributeError 異常;setattr(obj, attr, value)
設定該屬性/方法的值,類似于 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)
可以獲取相應對象的所有屬性和方法名的列表:
>>> 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)
:來獲取對象的相應類型;isinstance(obj, type)
:判斷對象是否為指定的 type 類型的實例;hasattr(obj, attr)
:判斷對象是否具有指定屬性/方法;getattr(obj, attr[, default])
獲取屬性/方法的值, 要是沒有對應的屬性則返回 default 值(前提是設置了 default),否則會拋出 AttributeError 異常;setattr(obj, attr, value)
:設定該屬性/方法的值,類似于 obj.attr=value;dir(obj)
:可以獲取相應對象的所有屬性和方法名的列表: