在本章中,我們將詳細(xì)討論面向?qū)ο蟮男g(shù)語和編程概念。類只是一個實例的工廠。 該工廠包含描述如何制作實例的藍圖。 一個實例或?qū)ο笫菑脑擃悩?gòu)造而來的。 在大多數(shù)情況下,我們可以有一個以上的類實例。 每個實例都有一組屬性,這些屬性在一個類中定義,因此每個特定類的每個實例都應(yīng)該具有相同的屬性。
類包:行為和狀態(tài)
一個類將允許將對象的行為和狀態(tài)捆綁在一起。 觀察下圖以更好地理解 -

討論類包時,以下幾點需要注意 -
類具有方法和屬性
在Python中,創(chuàng)建方法定義了一個類行為。 方法是在一個類中定義的函數(shù)提供的OOP名稱。 歸納如下 -
object.attribute例如,觀察下面的一段代碼 -
var = “Hello, John”
print( type (var)) # ‘str’> or <class 'str'>
print(var.upper()) # upper() method is called, HELLO, JOHN
以下代碼顯示了如何創(chuàng)建第一個類,然后創(chuàng)建它的實例。
class MyClass(object):
pass
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj)
這里創(chuàng)建了一個名為MyClass的類,它不執(zhí)行任何任務(wù)。MyClass類中的參數(shù)對象涉及類繼承,將在后面的章節(jié)中討論。 傳入上面的代碼表明這個塊是空的,也就是說它是一個空類定義。
讓我們創(chuàng)建一個MyClass()類的實例this_obj并按照顯示的那樣打印它 -
<__main__.MyClass object at 0x03B08E10>
<__main__.MyClass object at 0x0369D390>
在這里,我們創(chuàng)建了一個MyClass實例。 十六進制代碼指的是存儲對象的地址。 另一個例子指向另一個地址。
現(xiàn)在在類MyClass()中定義一個變量,并從該類的實例中獲取變量,如下面的代碼所示 -
class MyClass(object):
var = 9
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj.var)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj.var)
執(zhí)行上面給出的代碼時,可以觀察到以下輸出 -
9
9
由于實例知道它實例化了哪個類,因此當(dāng)從實例請求屬性時,實例會查找屬性和類。 這被稱為屬性查找。
在類中定義的函數(shù)稱為方法。 實例方法需要一個實例才能調(diào)用它并且不需要裝飾器。 創(chuàng)建實例方法時,第一個參數(shù)始終為self。 盡管可以用其他名稱來調(diào)用它(self),但建議使用self,因為它是一個命名約定。
class MyClass(object):
var = 9
def firstM(self):
print("hello, World")
obj = MyClass()
print(obj.var)
obj.firstM()
執(zhí)行上面給出的代碼時,可以觀察到以下輸出 -
9
hello, World
請注意,在上面的程序中,定義了一個以self為參數(shù)的方法。 但不能調(diào)用該方法,因為我們沒有聲明任何參數(shù)。
class MyClass(object):
def firstM(self):
print("hello, World")
print(self)
obj = MyClass()
obj.firstM()
print(obj)
執(zhí)行上面給出的代碼時,可以觀察到以下輸出 -
hello, World
<__main__.MyClass object at 0x036A8E10>
<__main__.MyClass object at 0x036A8E10>
封裝是面向?qū)ο蟮幕A(chǔ)之一。 OOP使我們能夠以下列方式隱藏對開發(fā)人員有利的對象內(nèi)部工作的復(fù)雜性 -
面向?qū)ο缶幊淘诤艽蟪潭壬弦蕾囉诜庋b。術(shù)語封裝和抽象(也稱為數(shù)據(jù)隱藏)通常用作同義詞。 它們幾乎是同義詞,因為抽象是通過封裝來實現(xiàn)的。
封裝提供了限制訪問某些對象組件的機制,這意味著對象的內(nèi)部表示無法從對象定義的外部看到。 訪問這些數(shù)據(jù)通常是通過特殊方法來實現(xiàn)的 - Getters 和 Setters 。
這些數(shù)據(jù)存儲在實例屬性中,可以在類以外的任何位置進行操作。 為了保護它,只能使用實例方法訪問該數(shù)據(jù)。 不應(yīng)允許直接訪問。
class MyClass(object):
def setAge(self, num):
self.age = num
def getAge(self):
return self.age
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())
執(zhí)行上面給出的代碼時,可以觀察到以下輸出 -
45
Fourty Five
只有在數(shù)據(jù)正確且有效的情況下,才能使用異常處理結(jié)構(gòu)來存儲數(shù)據(jù)。 正如我們上面所看到的,用戶對setAge()方法的輸入沒有限制。 它可以是字符串,數(shù)字或列表。 因此,我們需要檢查上面的代碼以確保存儲的正確性。
class MyClass(object):
def setAge(self, num):
self.age = num
def getAge(self):
return self.age
## 實例化對象
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())
只要實例化類的對象,就會隱式調(diào)用__init__方法。這將初始化對象。
x = MyClass()
上面顯示的代碼行將創(chuàng)建一個新實例并將該對象分配給局部變量x。
實例化操作(即調(diào)用類對象)創(chuàng)建一個空對象。 許多類喜歡創(chuàng)建具有定制到特定初始狀態(tài)的實例的對象。 因此,一個類可以定義一個名為'__init __()'的特殊方法,如圖所示 -
def __init__(self):
self.data = []
在實例化過程中,Python調(diào)用__init__來定義一個額外的屬性,這個屬性在實例化一個類時可能會發(fā)生,該類可能會為該對象設(shè)置一些起始值或運行實例化所需的例程。 所以在這個例子中,一個新的,初始化的實例可以通過 -
x = MyClass()
__init __()方法可以有單個或多個參數(shù),以獲得更大的靈活性。 init代表初始化,因為它初始化實例的屬性。 它被稱為類的構(gòu)造函數(shù)。
class myclass(object):
def __init__(self,aaa, bbb):
self.a = aaa
self.b = bbb
x = myclass(4.5, 3)
print(x.a, x.b)
執(zhí)行上面示例代碼,輸出結(jié)果如下 -
4.5 3
在類中定義的屬性稱為“類屬性”,并且在函數(shù)中定義的屬性稱為“實例屬性”。 在定義的時候,這些屬性并不是以self為前綴的,因為這些屬性是類的屬性,而不是特定實例的屬性。
類屬性可以通過類本身(className.attributeName)以及類的實例(inst.attributeName)來訪問。 因此,這些實例可以訪問實例屬性以及類屬性。
>>> class myclass():
age = 21
>>> myclass.age
21
>>> x = myclass()
>>> x.age
21
>>>
在實例中可以覆蓋類屬性,即使它不是破解封裝的好方法。
Python中有屬性的查找路徑。 第一個是在類中定義的方法,然后是上面的類。
>>> class myclass(object):
classy = 'class value'
>>> dd = myclass()
>>> print (dd.classy) # This should return the string 'class value'
class value
>>>
>>> dd.classy = "Instance Value"
>>> print(dd.classy) # Return the string "Instance Value"
Instance Value
>>>
>>> # This will delete the value set for 'dd.classy' in the instance.
>>> del dd.classy
>>> >>> # Since the overriding attribute was deleted, this will print 'class
value'.
>>> print(dd.classy)
class value
>>>
上面代碼中,覆蓋實例dd中的'classy'類屬性。 當(dāng)它被覆蓋時,Python解釋器會讀取被覆蓋的值。 但是,一旦新值被'del'刪除,被覆蓋的值就不會再出現(xiàn)在實例中,因此查找會達到上面的級別并從類中獲取。
在本節(jié)中,讓我們了解類數(shù)據(jù)如何與實例數(shù)據(jù)相關(guān)。 可以將數(shù)據(jù)存儲在類或?qū)嵗小?當(dāng)我們設(shè)計一個類時,決定哪些數(shù)據(jù)屬于實例,哪些數(shù)據(jù)應(yīng)該存儲到整個類中。
一個實例可以訪問類數(shù)據(jù)。 如果創(chuàng)建了多個實例,那么這些實例可以訪問它們各自的屬性值以及整個類數(shù)據(jù)。
因此,類數(shù)據(jù)是所有實例之間共享的數(shù)據(jù)。 遵守下面給出的代碼以獲得更好的低估 -
class InstanceCounter(object):
count = 0 # class attribute, will be accessible to all instances
def __init__(self, val):
self.val = val
InstanceCounter.count +=1 # Increment the value of class attribute, accessible through class name
# In above line, class ('InstanceCounter') act as an object
def set_val(self, newval):
self.val = newval
def get_val(self):
return self.val
def get_count(self):
return InstanceCounter.count
a = InstanceCounter(9)
b = InstanceCounter(18)
c = InstanceCounter(27)
for obj in (a, b, c):
print ('val of obj: %s' %(obj.get_val())) # Initialized value ( 9, 18, 27)
print ('count: %s' %(obj.get_count())) # always 3
執(zhí)行上面示例時,得到以下結(jié)果 -
val of obj: 9
count: 3
val of obj: 18
count: 3
val of obj: 27
count: 3
簡而言之,類屬性對于類的所有實例都是相同的,而實例屬性對于每個實例都是特定的。 對于兩個不同的實例,將有兩個不同的實例屬性。
class myClass:
class_attribute = 99
def class_method(self):
self.instance_attribute = 'I am instance attribute'
print (myClass.__dict__)
執(zhí)行上面給出的代碼時,可以觀察到以下輸出 -
{'__module__': '__main__', 'class_attribute': 99, 'class_method': , '__dict__': , '__weakref__': , '__doc__': None}
如圖所示的實例屬性myClass .__ dict__ -
>>> a = myClass()
>>> a.class_method()
>>> print(a.__dict__)
{'instance_attribute': 'I am instance attribute'}