類
類定義形式示例如下:
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
基礎重載方法
__init__ ( self [,args...] )
構造函數,初始化一些數據,相當於C#、Java中的 classname(args)
簡單的調用方法: obj = className(args)
__del__( self )
析構方法, 刪除一個對象,相當於php的 __destruct()
簡單的調用方法 : dell obj
__repr__( self )
轉化爲供解釋器讀取的形式
簡單的調用方法 : repr(obj)
__str__( self )
用於將值轉化爲適於人閱讀的形式,相當於Java的 toString()
簡單的調用方法 : str(obj)
__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中方法也是一種屬性)
變量:
類變量即爲靜態變量,以Classname.attr形式引用。
一些特殊的類屬性(變量):
- __doc__,類的文檔字符串
- __name__,類的名稱
- __base__,類的所有基類(構成的tuple)
- __dict__,類的屬性(構成的dict)
- __module__,類所在的module
- __class__,實例對應的類
方法:
類方法以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。
實例屬性也分爲變量和方法。
變量
第一次引用實例屬性(變量)時,若存在同名的類屬性(變量),則實例屬性(變量)的值即爲類屬性(變量)的值,若不存在則會拋出異常。
第一次對實例屬性(變量)賦值時,會新增或修改該屬性。
方法
類中定義的函數,第一個參數爲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):
L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]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)
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 = qdef __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)