类
定义与创建
按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。
由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值,例如,给xiaoming这个实例加上name、gender和birth属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Person(object): pass p1 = Person() p1.name = 'Bart' p2 = Person() p2.name = 'Adam' p3 = Person() p3.name = 'Lisa' L1 = [p1, p2, p3] L2 = sorted(L1,lambda p1,p2 : cmp(p1.name,p2.name)) print L2[0].name print L2[1].name print L2[2].name
|
初始化
init()方法,当创建实例时,init()方法被自动调用,我们就能在此为每个实例都统一加上属性
init() 方法的第一个参数必须是 self(也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定,和定义函数没有任何区别。
1 2 3 4 5 6 7 8 9 10 11 12
| class Person(object): def __init__(self,name,sex,birth,**kw): self.name = name self.sex=sex self.birth=birth for k, v in kw.iteritems(): setattr(self, k, v) xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student') print xiaoming.name print xiaoming.job
|
私有变量
如果一个属性由双下划线开头(__),该属性就无法被外部访问。但是,如果一个属性以”__xxx__“的形式定义,那它又可以被外部访问了,以”__xxx__“定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用”__xxx__“定义。
以单下划线开头的属性”_xxx”虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。
1 2 3 4 5 6 7 8 9
| class Person(object): def __init__(self, name): self.name = name self._title = 'Mr' self.__job = 'Student' p = Person('Bob') print p.name print p._title print p.__job
|
静态变量
静态变量只属于类的属性,由于Python是动态语言,类属性也是可以动态添加和修改的.
当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Person(object): count = 0 def __init__(self,name): self.name = name Person.count = Person.count + 1 p1 = Person('Bob') print Person.count p2 = Person('Alice') print Person.count p3 = Person('Tim') print Person.count
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Person(object): address = 'Earth' def __init__(self, name): self.name = name p1 = Person('Bob') p2 = Person('Alice') print 'Person.address = ' + Person.address p1.address = 'China' print 'p1.address = ' + p1.address print 'Person.address = ' + Person.address print 'p2.address = ' + p2.address del p1.address print p1.address
|
定义方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Person(object): def __init__(self, name, score): self.name = name self.__score = score def get_grade(self): if self.__score<60: return 'C' elif self.__score<90: return 'B' else: return 'A' p1 = Person('Bob', 90) p2 = Person('Alice', 65) p3 = Person('Tim', 48) print p1.get_grade() print p2.get_grade() print p3.get_grade()
|
因为方法也是一个属性,所以,它也可以动态地添加到实例上,只是需要用 types.MethodType() 把一个函数变为一个方法:
1 2 3 4 5 6 7 8 9 10 11
| class Person(object): def __init__(self, name, score): self.name = name self.score = score def get_grade(self): return 'A' p1 = Person('Bob', 90) print p1.get_grade print p1.get_grade()
|
类的方法
通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例。类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.count 实际上相当于 Person.count。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Person(object): __count = 0 def __init__(self,name): self.name = name Person.__count = Person.__count + 1 @classmethod def how_many(cls): return cls.__count print Person.how_many() p1 = Person('Bob') print Person.how_many()
|
类的继承
继承的初始化
1 2 3 4 5 6 7 8 9
| 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
|
一定要用 super(Student, self).__init__(name, gender) 去初始化父类,否则,继承自 Person 的 Student 将没有 name 和 gender。
函数super(Student, self)将返回当前类继承的父类,即 Person ,然后调用__init__()方法,注意self参数已在super()中传入,在__init__()中将隐式传递,不需要写出(也不能写)。
判断数据类型
函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以用在我们自定义的类,它们本质上都是数据类型.isinstance(s, Person)
Student和Teacher继承Person,a,b,c分别是Person,Student,Teacher的实例,a是person类,不是student或Teach,但是b即时Person又是Student。
多态
由于Python是动态语言,所以,传递给函数的参数 x 不一定是 子类 或 父类类型。任何数据类型的实例都可以,只要它有一个相同参数的方法即可:
这是动态语言和静态语言(例如Java)最大的差别之一。动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。
多继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class A(object): def __init__(self, a): print 'init A...' self.a = a class B(A): def __init__(self, a): super(B, self).__init__(a) print 'init B...' class C(A): def __init__(self, a): super(C, self).__init__(a) print 'init C...' class D(B, C): def __init__(self, a): super(D, self).__init__(a) print 'init D...'
|
获取对象信息
typetype(123)
dir()dir(123)
只显示自己的属性
1 2 3 4 5
| def only_my(s): if(s[0]!='_'): return s; print filter(only_my, dir(s))
|
dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() 和 setattr( )函数了:
1 2 3 4
| getattr(s, 'name') # 获取name属性 setattr(s, 'name', 'Adam') # 设置新的name属性 getattr(s, 'age') # 获取age属性,但是属性不存在,报错: getattr(s, 'age', 20) # 获取age属性,如果属性不存在,就返回默认值20:
|
定制类
特殊方法
__str__和__repr__
1 2 3 4 5 6 7 8 9 10 11
| class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender def __str__(self): return '(Person: %s, %s)' % (self.name, self.gender) __repr__ = __str__ p = Person('Bob', 'male') print p p
|
__cmp__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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.name < s.name: return -1 elif self.name > s.name: return 1 else: return 0
|
Student 类实现了cmp()方法,cmp用实例自身self和传入的实例 s 进行比较,如果 self 应该排在前面,就返回 -1,如果 s 应该排在前面,就返回1,如果两者相当,返回 0。
__len__
1 2 3 4 5 6 7
| class Students(object): def __init__(self, *args): self.names = args def __len__(self): return len(self.names) ss = Students('Bob', 'Alice', 'Tim') print len(ss)
|
四则运算与类型转化
实现分数的四则运算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| def gcd(a,b): if b==0 : return a else: return gcd(b,a%b) class Rational(object): def __init__(self, p, q): self.p = p self.q = q def __add__(self, r): tmp=Rational(self.p * r.q + self.q * r.p, self.q * r.q) tmp.reduces() return tmp def __sub__(self, r): tmp=Rational(self.p*r.q-self.q*r.p , self.q*r.q) tmp.reduces() return tmp def __mul__(self, r): tmp=Rational(self.p*r.p,self.q*r.q) tmp.reduces() return tmp def __div__(self, r): tmp=Rational(self.p*r.q,self.q*r.p) tmp.reduces() return tmp def __str__(self): return '%s/%s'%(self.p,self.q) __repr__ = __str__ def reduces(self): c = gcd(abs(self.p),abs(self.q)) self.p=self.p/c self.q=self.q/c def __int__(self): return self.p // self.q def __float__(self): return float(self.p)/self.q r1 = Rational(1, 2) r2 = Rational(1, 4) print r1 + r2 print r1 - r2 print r1 * r2 print r1 / r2 print int(Rational(7,3)) print float(Rational(5,2))
|
@property
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 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' if self.score < 80: return 'B' return 'A' s = Student('Bob', 59) print s.grade s.score = 60 print s.grade s.score = 99 print s.grade
|
__slots__
如果要限制添加的属性,例如,Student类只允许添加 name、gender和score 这3个属性,就可以利用Python的一个特殊的slots来实现。
1 2 3 4 5 6
| class Student(object): __slots__ = ('name', 'gender', 'score') def __init__(self, name, gender, score): self.name = name self.gender = gender self.score = score
|
__call__
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法call()。
1 2 3 4 5 6 7 8 9 10
| class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender def __call__(self, friend): print 'My name is %s...' % self.name print 'My friend is %s...' % friend p = Person('Bob', 'male') p('Tim')
|