Python:class類

類及其類屬性

1.屬性就是屬於另一個對象的數據或者函數元素,可以通過我們熟悉的句點屬性標示法來訪問。
2.類屬性僅與其被定義的類相綁定,由於實例對象在日常的面向對象編程中用得最多,實例數據屬性是你將會一直用到的主要數據屬性。
類數據屬性僅當需要更加“靜態”數據類型時才變得有用,他和任何實例都無關。

類的數據屬性

這種屬性是一種靜態變量,表示這些數據是與他們所屬的類對象綁定的,不依賴於任何類實例。

>>>
>>> class my(object):
...     foo=100  #類屬性
...
>>> print my.foo
100
>>> my.foo=my.foo+1
>>> my.foo
101
>>>

以上代碼沒有出現任何實例的引用

方法

方法其實就是類中定義的函數,他是屬於類屬性的,並不屬於實例屬性。雖然他是類屬性,但是並不能直接通過類來調用。

>>> class my(object):
...     def my_method(self):
...         pass
...
>>> c=my()
>>> c.my_method()  #通過實例調用
>>> my.my_method()  #通過類直接調用這個方法
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method my_method() must be called with my instance as first a
rgument (got nothing instead)
>>>

爲什麼會出錯,明明方法也是類屬性,接下來解釋這個問題
綁定(綁定以及非綁定方法)爲了與oop慣例保持一致,python嚴格要求,沒有實例,方法是不能被調用的,這種限制即Python所描述的綁定概念,方法必須與實例綁定才能被直接被調用。 非綁定方法可能可以被調用,但實例對象一定要明確給出,才能確保調用成功。

dir

要知道一個類有哪些屬性,有兩種方法,最簡單的是使用dir()內建函數,另爲一個就是通過訪問類的字典屬性__dict__,這是所有類都具備的特殊屬性之一。

>>> class myclass(object):
...     myversion=1.0
...     def show(self):
...         print myclass.myversion
...
>>> dir(myclass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut
e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e
x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_
_weakref__', 'myversion', 'show']
>>> myclass.__dict__
dict_proxy({'__module__': '__main__', 'show': <function show at 0x0000000002D51E
B8>, '__dict__': <attribute '__dict__' of 'myclass' objects>, 'myversion': 1.0,
'__weakref__': <attribute '__weakref__' of 'myclass' objects>, '__doc__': None})
>>>

從上面的代碼可以看出,dir()返回的僅是對象的屬性的一個名字列表,可以打印類屬性,還可以打印所有的實例屬性,而__dict__返回的是一個字典,他的鍵是屬性名,鍵值是相應的屬性對象的數據值。

特殊的類屬性

C.__name__      類C的名字(字符串)
C.__doc__       類C的文檔字符串
C.__bases__     類C的所有父類構成的元組
C.__dict__      類C的屬性
C.__module__    類C定義所在的模塊
C.__class__     實例C對應的類(僅新式類中)

實例

如果說類是一種數據結構定義的類型,那麼實例則聲明瞭一個這種類型的變量。

__init__()“構造器”方法

當類被調用的時候,實例化的第一步就是創建實例對象,一旦對象創建了,Python檢查是否實現了__init__()方法,默認情況下,如果沒有定義(或者覆蓋)特殊方法__init__(),對實例不會施加任何特別操作,任何所需要的特定操作,都需要程序員實現__init__(),覆蓋它的默認行爲。
如果__init__()已經被實現 ,那麼它將被調用,實例對象作爲第一個參數(self)被傳遞進去,調用類的時候,傳進去的任何參數都交給了__init__()

__new__()“構造器”方法

__init__()方法相比,__new__()方法更像一個真正的構造器,python可以對內建類型進行派生,因此,需要一種途徑來實例化不可變對象,比如派生字符串,數字等
__new__()相比與__init__()方法,__new__()必須返回一個合法的實例,這樣解釋器在調用__init__()時,就可以把這個實例作爲self傳給他。簡單的說就是new調用了init

__call__

有了這個特殊方法,就可以像函數一樣調用實例了

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

    def __call__(self,age):
        self.age=age
        return "%s is %s"%(self.name,self.age)


t=Test('cmustard')
print t(23)  #調用實例
"cmustard is 23"

實例屬性

實例僅擁有數據屬性(方法嚴格來說是類屬性),當一個實例被釋放後,他的屬性同時也被清除了。
構造器是最早設置實例屬性的地方,一旦__init__()執行完畢,返回實例對象,即完成了實例化過程

查看實例屬性

>>> class my(object):
...     pass
...
>>> c=my()
>>> c.foo='cmustard'
>>> c.bar=12312
>>> dir(c)  #所有屬性,包括類屬性和實例屬性
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut
e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e
x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_
_weakref__', 'bar', 'foo']

>>> c.__dict__  #返回實例對象構成的字典
{'foo': 'cmustard', 'bar': 12312}
>>>

實例屬性和類屬性比較

類屬性僅是與類相關的數據值,和實例屬性不同,類屬性和實例屬性無關。類和實例都是名字空間,類是類屬性的名字空間,實例則是實例屬性的。我們可以採用類來訪問類屬性,如果實例沒有同名的屬性的話,你也可以用實例來訪問。

>>> class my(object):
...     myversion=1
...     def __init__(self,name):
...         self.name=name
...
>>> class my(object):
...     myversion=1
...     def __init__(self,name):
...         self.name=name
...     def show(self,age):
...         print "name is %s age is %s"%(self.name,age)
...

>>> c=my('cmustard')
>>> c.name   #訪問實例屬性
'cmustard'
>>> c.myversion  #訪問myversion,實例屬性中沒有,於是訪問的是類屬性中的變量
1
>>> c2=my("abner")
>>> c2.show(22)  #訪問方法
name is abner age is 22
>>> c.show(18)
name is cmustard age is 18
>>> c2.myversion  #訪問myversion,實例屬性中沒有,於是訪問的是類屬性中的變量
1
>>> my.myversion  #通過類直接訪問類屬性
1
>>> c.myversion=100 #在實例c中修改myversion,相當與在實例c中動態添加了一個新的屬性
>>> c.myversion
100
>>> c2.myversion  #在實例c2中myversion的值依然沒有改變
1
>>> my.myversion=150 #通過類直接修改myversion的值
>>> c.myversion  #實例c中的值沒有發生改變,因爲實例c中已經有一個名叫myversion的變量了
100
>>> c2.myversion #實例c2中值隨着類的改變而改變,因爲實例c2中沒有myversion這個變量,只能訪問類屬性中的變量
150 
>>> my.myversion
150
>>>

綁定和方法調用

方法只有在所屬的類擁有實例的時候才能被調用,當存在一個實例的時候,方法才被認爲是綁定到了那個實例,沒有實例時方法就是未綁定的
self是什麼:self變量用於在類實例方法中引用方法所綁定的實例,因爲在方法的實例在任何方法調用中總是作爲一個參數傳遞的,self被選中用來代替實例。

調用綁定方法

就是用實例調用這個方法

調用非綁定方法

調用非綁定方法並不經常用到,主要應用場景:你在派生一個子類 ,而且你要覆蓋父類的方法,這時你需要調用哪個父類中想要覆蓋的構造方法。

class Foo(object):
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age
    def show(self):
        print "name is %s,sex is %s"%(self.name,self.sex)

class Bar(Foo):
    def __init__(self,name,sex,age,id,salary):
        super(Bar,self).__init__(name,sex,age) #這就是在調用父類非綁定方法
        #或者Foo.__init__(self,name,sex,age)  現在不用了
        self.id=id
        self.salary=salary

    def info(self):
        print "name is %s salary is %s"%(self.name,self.salary)


>>> f=Bar('cmustard','F',22,123123,1000)
>>> f.show()
name is cmustard,sex is F
>>> f.info()
name is cmustard salary is 1000
>>>

靜態方法和類方法

靜態方法中默認是不能訪問類變量和實例變量。
類方法不能訪問實例變量

class TestS(object):
    @staticmethod
    def foo():
        print "calling static method foo()"

class TestC(object):
    @classmethod
    def foo(cls):
        print "calling class method foo()"
        print "foo() is part of class",cls.__name__

>>> s=TestS()
>>> s.foo()
calling static method foo()
>>> TestS.foo()  #直接調用靜態方法
calling static method foo()
>>>
>>>
>>> c=TestC()
>>> TestC().foo()
calling class method foo()
foo() is part of class TestC
>>> c.foo()
calling class method foo()
foo() is part of class TestC
>>>

property屬性

@property裝飾器是把方法轉變成屬性訪問,簡單來說就是實例訪問這個方法的時候,不需要加括號

#coding:utf-8

class TestP(object):
    def __init__(self,name):
        self.name=name
        self.num=0

    @property
    def total(self):
        return "is %s"%self.num

    @total.setter  #設置屬性的值
    def total(self,num):
        self.num=num

    @total.deleter #刪除這個屬性
    def total(self):
        del self.num
p=TestP('cmustard')

print p.total  #is 0


#怎麼給他賦值呢  需要setter裝飾器
p.total=10
print p.total #is 10

#怎麼刪除這個屬性
del p.total
print p.total  #'TestP' object has no attribute 'num'


這個有什麼作用呢,我們還是可以直接改變num的值呀。。

p.num=100  
print p.num  #100

這時我們需要引用私有變量

class TestP(object):
    def __init__(self,name):
        self.name=name
        self.__num=0  #設置了一個私有變量

    @property
    def total(self):
        return "is %s"%self.__num

    @total.setter  #設置屬性的值
    def total(self,num):
        self.__num=num

    @total.deleter #刪除這個屬性
    def total(self):
        del self.__num
p=TestP('cmustard')
p.total=100
print p.total  #is 100


#倘若直接修改呢
p.__num=130
print p.__num #130
print p.__dict__  #{'_TestP__num': 100, 'num': 120, 'name': 'cmustard', '__num': 130},這裏只是在實例屬性中添加了一個新的變量
print p.total  #is 100  還是沒有改變

#特殊情況
p._TestP__num=110
print p.total #is 110  這就改變了,不過我們一般不會這麼用的
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章