不一樣的Python(8)——類型

1. 以關鍵字class開始定義一個新的類型:
class Employee:
  def setname(self, who):
    self.name = who
  def display(self):
    print self.name 

self相當於C++中的this指針。C++的this指針是隱含的,但Python中self是需要顯示地寫出。

2. Python 把對象(object)分爲class object和instance object。每個類型都有一個對象,該對象能生成多個實例對象。

3. 可以通過類型對象或者實例對象調用類型的方法。比如下列兩種調用setname的方式是等價的:

e = Employee()
e.setname('Harry')
Employee.setname(e, 'Harry')

4. 實例對象的成員變量不需要提前聲明,它們在賦值時自動創建。

5. 可以在類型定義之外爲實例對象添加新的成員變量,比如:

e.lastname = 'He'

6. 可以在類型定義之外爲類型添加新的成員函數,比如:

def upperName(self):
  return self.name.upper()

Employee.method = upperName
e.method()

7. 如果子類沒有重寫__init__,會自動調用父類的__init__函數:

class A:
    def __init__(self):
        print 'A is instantiated'


class B (A):
    pass

if __name__ == '__main__':
    b = B()

此時A.__init__仍然會被調用

如果子類重寫了__init__函數,父類的__init__函數不會自動自動被調用,如以下代碼:

class A:
    def __init__(self):
        print 'A is instantiated'


class B (A):
    def __init__(self):
        print 'B is instantiated'
    

if __name__ == '__main__':
    b = B()


如果希望父類的__init__函數被調用,需要在子類的__init__函數裏顯示地調用:如以下代碼:

class A:
    def __init__(self):
        print 'A is instantiated'


class B (A):
    def __init__(self):
        A.__init__(self)
        print 'B is instantiated'
    

if __name__ == '__main__':
    b = B()


8. Python的class不支持類似於C++/C#/Java的static函數/方法

9. metaclass可以用來生成新的class。詳細討論可以參考http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python

10. static變量和實例的變量:

>>> class Test(object):
...     i = 3
...
>>> Test.i
3
>>> t = Test()
>>> t.i     # static variable accessed via instance
3
>>> t.i = 5 # but if we assign to the instance ...
>>> Test.i  # we have not changed the static variable
3
>>> t.i     # we have overwritten Test.i on t by creating a new attribute t.i
5
>>> Test.i = 6 # to change the static variable we do it by assigning to the class
>>> t.i
5
>>> Test.i
6

11.在Python中沒有類似於C/C++/C#的enum類型。下面是幾種用Python模擬enum的方法:

(1) 生成新的type:

def enum(**enums):
    return type('Enum', (), enums)

>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'

或者自動編號:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1

如果需要逆向查找:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    reverse = dict((value, key) for key, value in enums.iteritems())
    enums['reverse_mapping'] = reverse
    return type('Enum', (), enums)

>>> Numbers.reverse_mapping['three']
'THREE'

(2)基於set:

class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError
Animals = Enum(["DOG", "CAT", "HORSE"])

print Animals.DOG

(3)基於tuple:

(Pen, Pencil, Eraser) = range(0, 3)

或者:

class Stationery:
    (Pen, Pencil, Eraser) = range(0, 3)

12. 如果類型需要支持+、-、×、/,則需要添加__add__、__sub__、__mul__、__rmul__、__div__等。如果需要支持比較,則需要添加__cmp__。完整列表參考Think like a Computer Scientist的Appendix B。








 

發佈了35 篇原創文章 · 獲贊 7 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章