面向对象
类
类定义形式示例如下:
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): 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)