面向對象

類定義形式示例如下:

class Employee:
   #定義成員變量
   empCount = 0

    #構造函數
    def __init__(self, name, salary):
       self.name = name
       self.salary = salary
       Employee.empCount += 1
    
    #定義方法
    def displayCount(self):
       print "Total Employee %d" % Employee.empCount

    #定義方法
    def displayEmployee(self):
       print "Name : ", self.name,  ", Salary: ", self.salary

基礎重載方法

  1. __init__ ( self [,args...] )

    構造函數,初始化一些數據,相當於C#、Java中的 classname(args)

    簡單的調用方法: obj = className(args)

  2. __del__( self )

    析構方法, 刪除一個對象,相當於php的 __destruct()

    簡單的調用方法 : dell obj

  3. __repr__( self )

    轉化爲供解釋器讀取的形式

    簡單的調用方法 : repr(obj)

  4. __str__( self )

    用於將值轉化爲適於人閱讀的形式,相當於Java的 toString()

    簡單的調用方法 : str(obj)

  5. __cmp__ ( self, x )

    對象比較

    簡單的調用方法 : cmp(obj, x)

運算符重載

除了上面的基礎重載方法,還有一些方法可以重載,如運算

下例將運算符'+'重載:

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b

   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2,10)
v2 = Vector(5,-2)

#結果:(7,8)
print v1 + v2

私有和公開

對於私有,Python的變量名和方法名前加兩個下劃線,'__attr' 和 '__method(args)'。

類內部引用私有變量和私有函數,self.__attrName 和 self.__method(args)。

類外部訪問私有屬性,object._className__attrName。

對於公開,Python的變量名和方法名前無雙下劃線。

類屬性

類屬性即靜態屬性,以Classname.attr形式引用。

類屬性分爲變量和方法(Python中方法也是一種屬性)

  1. 變量:

    類變量即爲靜態變量,以Classname.attr形式引用。

    一些特殊的類屬性(變量):

    • __doc__,類的文檔字符串
    • __name__,類的名稱
    • __base__,類的所有基類(構成的tuple)
    • __dict__,類的屬性(構成的dict)
    • __module__,類所在的module
    • __class__,實例對應的類
  2. 方法:

    類方法以Classname.method()形式引用。

    @classmethod
    def cm(cls):
        print('I\'m a class method ')

    類方法需在方法聲明上方添加@classmethod,方法至少有一個參數,參數名可隨意,第一個參數代表方法所在的類。

    類方法只能訪問類屬性(靜態屬性),不能訪問實例屬性。

靜態方法

@staticmethod
def sm():
    print('I\' a static method')

靜態方法只能訪問類屬性(靜態屬性),不能訪問實例屬性。

實例屬性

實例屬性屬於類的實例,引用時依賴類的實例,通過instance.arrt引用。在該類內部引用體現爲self.attr,在該類外部引用體現爲object.attr。

實例屬性也分爲變量和方法。

  1. 變量

    第一次引用實例屬性(變量)時,若存在同名的類屬性(變量),則實例屬性(變量)的值即爲類屬性(變量)的值,若不存在則會拋出異常。

    第一次對實例屬性(變量)賦值時,會新增或修改該屬性。

  2. 方法

    類中定義的函數,第一個參數爲self,指向調用該方法的實例本身。構造函數__init(self,args)__也可視爲一個特殊的實例方法。

    class Person(object):
    
        def __init__(self, name):
            self.__name = name
    
        def get_name(self):
            return self.__name
    
    p1 = Person('Bob')
    print p1.get_name()  # self不需要顯式傳入

    注意上面代碼中,p1.get_name() 和 p1.get_name的區別,前者是一個函數的調用,後者是一個函數。

    types.MethodType()可以動態地爲實例創建方法:

    import types
    
    def fn_get_grade(self):
        if self.score >= 80:
            return 'A'
        if self.score >= 60:
            return 'B'
        return 'C'
    
    class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    p1 = Person('Bob', 90)
    p1.get_grade = types.MethodType(fn_get_grade, p1, Person)
    
    #輸出'A'
    print p1.get_grade()
    

類的繼承

形式:

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
        
class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

Person無父類,則定義時以Person(object)或Person()形式定義。

Student初始化時,需使用super(Student, self)獲取父類,然後調用父類的構造方法(此處無self參數),否則Person將無name和gender。

isinstance(a,ClassA)方法可以判斷實例a是否是ClassA類型。

Python中類可以多重繼承,如Student(Person,Child)。

type(instance)

獲取實例的類型

dir(instance)

獲取實例的所有實例屬性,list形式

getattr(instance,'attrName')

根據屬性名獲取實例的屬性值

setattr(instance,'attrName',value)

根據屬性名設置實例的屬性

特殊方法

  • __str__() 將一個實例轉換成一個str,用於展示給用戶,那麼該實例的類需要實現該方法。
  • __repr__() 將一個實例轉換成一個str,用於展示給開發者,那麼該實例的類需要實現該方法。
  • __cmp__() 比較方法,用於本實例與另一個相同類型的實例進行比較。 返回-1,排在前面;返回1,排在後面;返回0,兩者相等。

    將學生按照分數由高到低排列,若相同,按照姓名排列。
    ```
    class Student(object):

      def __init__(self, name, score):
          self.name = name
          self.score = score
    
      def __str__(self):
          return '(%s: %s)' % (self.name, self.score)
    
      __repr__ = __str__
    
      def __cmp__(self, s):
          if self.score == s.score:
              return cmp(self.name, s.name)
          return -cmp(self.score, s.score)
    L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
    print sorted(L)
    ```
  • __len__() 返回實例的元素的個數。

    class Fib(object):
    
    def __init__(self, num):
        a, b, L = 0, 1, []
        for n in range(num):
            L.append(a)
            a, b = b, a + b
        self.numbers = L
    
    def __str__(self):
        return str(self.numbers)
    
    __repr__ = __str__
    
    def __len__(self):
        return len(self.numbers)
    
    
    f = Fib(10)
    print f
    print len(f)
  • __add__() 加法
  • __sub__() 減法
  • __mul__() 乘法
  • __div__() 除法

    例如有理數的四則運算:
    ```
    def gcd(a, b):
    if b == 0:
    return a
    return gcd(b, a % b)

    class Rational(object):
    def init(self, p, q):
    self.p = p
    self.q = q

      def __add__(self, r):
          return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
    
      def __sub__(self, r):
          return Rational(self.p * r.q - self.q * r.p, self.q * r.q)
    
      def __mul__(self, r):
          return Rational(self.p * r.p, self.q * r.q)
    
      def __div__(self, r):
          return Rational(self.p * r.q, self.q * r.p)
    
      def __str__(self):
          g = gcd(self.p, self.q)
          return '%s/%s' % (self.p / g, self.q / g)
    
      __repr__ = __str__

    r1 = Rational(1, 2)
    r2 = Rational(1, 4)
    print r1 + r2
    print r1 - r2
    print r1 * r2
    print r1 / r2
    ```

數值數據類型轉換

重寫__int__()和__float__()方法

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

    def __int__(self):
        return self.p // self.q

    def __float__(self):
        return float(self.p)/self.q

print float(Rational(7, 2))
print float(Rational(1, 3))

設置屬性的get和set

使用@property和@propertyname.setter來分別表示get和set操作。

@property---這是關鍵字,固定格式,能讓方法當“屬性”用。

@score.setter---前面的"score"是@property緊跟的下面定義的那個方法的名字,"setter"是關鍵字,這種“@+方法名字+點+setter”是個固定格式與@property搭配使用。

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.__score = score

    @property
    def score(self):
        return self.__score

    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

    @property
    def grade(self):
        if self.score<60:
            return 'C'
        elif self.score>80:
            return 'A'
        else:
            return 'B'

s = Student('Bob', 59)
print s.grade

s.score = 60
print s.grade

s.score = 99
print s.grade

__slots__

__slots__用於限制類能所有的屬性。只對當前的類起作用,對子類不起作用。

# 限制Student只能最多擁有'name'、'gender'、'score'這三個屬性,當動態再次添加額外的屬性時會報錯。
class Student(object):
    __slots__ = ('name', 'gender', 'score')
    def __init__(self, name, gender, score):
        self.name = name
        self.gender = gender
        self.score = score

__call__

Python中函數是對象,所有的函數都是可調用對象。類實例可變爲可調用對象,需要實現__call__方法。

class Fib(object):
    
    def __call__(self,num):
        a, b, L = 0, 1, []
        for n in range(num):
            L.append(a)
            a, b = b, a + b
        return L

f = Fib()
# 輸出斐波那契數列 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
print f(10)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章