1.面向对象编程
1. 类和实例
注意,类的所有方法,的第一个参数一定是self。
在调用类的方法时,不需要传入第一个参数self。#!/usr/bin/env python # -*- coding: utf-8 -*- #定义一个类Student,继承自object class Student(object): #构造器 def __init__(self,name,score): #将name和score保存的私有成员变量中 self.__name = name self.__score = score #定义一个公有的show方法 def show(self): print 'name =%s,score =%.2f' %(self.__name,self.__score) s = Student(18,99.5) s.show() #用这种方式去访问类中私有的变量,是非常不建议的。因为,在不同的python版本中,可能会不同。 #正确的做法应该是添加setter和getter方法。 #print s._Student__name
2.继承和多态
#!/usr/bin/env python # -*- coding: utf-8 -*- class Person(object): def show(self): print 'Person show' #继承Person类 class Student(Person): def show(self): print 'Student show' #多态 def run(p): p.show() run(Person()) run(Student())
3. 获取对象信息
判断对象类型,使用type()函数
Python把每种type类型都定义好了常量,放在types模块里,使用之前,需要先导入:types模块
所有类型本身的类型就是TypeType#!/usr/bin/env python # -*- coding: utf-8 -*- class Person(object): def show(self): print 'Person show' class Student(Person): def show(self): print 'Student show' p = Person() s = Student() print type(123) print type('abc') print type(int) print type(p) print type(s) import types print type('abc') == types.StringType
运行结果
<type 'int'> <type 'str'> <type 'type'> <class '__main__.Person'> <class '__main__.Student'> True
4.isinstance详解
#!/usr/bin/env python # -*- coding: utf-8 -*- class Person(object): def show(self): print 'Person show' class Student(Person): def show(self): print 'Student show' p = Person() s = Student() #判断是否是某个类的实例 print isinstance(p,Person) print isinstance(s,Person) print isinstance(p,Student) #判断是否是某两个类中任意一个类的实例 print isinstance(p,(Student,Person)) #判断是str或者unicode类型中的任意一个 print isinstance('a',(str,unicode)) print isinstance(u'a',(str,unicode)) #由于str和unicode都是从basestring继承下来的,所以,还可以把上面的代码简化为: print isinstance(u'a',basestring)
5.使用dir()
如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list
类似xxx的属性和方法在Python中都是有特殊用途的,比如len方法返回长度。在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的len()方法
getattr()、setattr()以及hasattr()
如果试图获取不存在的属性,会抛出AttributeError的错误。可以传入一个default参数,如果属性不存在,就返回默认值#!/usr/bin/env python # -*- coding: utf-8 -*- class Person(object): def show(self): print 'Person show' p = Person() print dir(Person) == dir(p) #获取对象的所有属性和方法 dir(p) #调用len('ABC')等同于调用'ABC'.__len__() print len('ABC') print 'ABC'.__len__() #判断对象是否包含某个属性,如果不包含,则添加则属性 if hasattr(p,'score'): print p.score else: setattr(p,'score',65.5) print p.score def err(): print 'no method' #获取一个对象的某个属性,并传入默认值。 fn1 = getattr(p,'show',err) fn2 = getattr(p,'show2',err) fn1() fn2()
2.面向对象高级编程
1.为对象或者类动态绑定属性或者方法
#!/usr/bin/env python # -*- coding: utf-8 -*- class Person(object): def show(self): print 'Person show' p = Person() #为对象动态绑定属性 p.name = 'zhangsan' print p.name #导入MethodType模块,以便为对象或类动态绑定方法 from types import MethodType def test(self): print 'test succ' self.show() #为对象动态绑定方法(此方法只会作用在当前对象上) p.test = MethodType(test,p,Person) p.test() #为类动态绑定方法(此方法会作用在所有对象上) Person.test = MethodType(test,None,Person) p2 = Person() p2.test(
2.使用slots限定class可以绑定的属性
Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class能添加的属性
注意,子类不受父类的slots的限制
如果子类也定义了slots,那么他可以添加的属性为父类中slots定义的和子类自己的slotsclass Student(object): __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称 ...省略...
3.@property
作用:把一个方法变为属性。(其实是简化getter和setter的调用,让getter和setter方法可以像直接操作属性一样简单)
把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值#!/usr/bin/env python # -*- coding: utf-8 -*- class Student(object): @property def birth(self): return self.__birth @birth.setter def birth(self,value): self.__birth = value @property def age(self): return 2016 - self.__birth s = Student() s.birth = 1991 print 'birth =',s.birth print 'age =',s.age
4.多重继承
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为Mixin。
#!/usr/bin/env python # -*- coding: utf-8 -*- class Animal(object): pass class Mammal(Animal): pass class Bird(Animal): pass class RunnableMixin(object): def run(self): print('Running...') class FlyableMixin(object): def fly(self): print('Flying...') #多重继承(同时继承自Mammal和RunnableMixin) class Dog(Mammal,RunnableMixin): pass #多重继承(同时继承自Mammal和FlyableMixin) class Bat(Mammal,FlyableMixin): pass d = Dog() b = Bat() d.run() b.fly()
5.定制类
1.str和repr-定制显示信息
#!/usr/bin/env python # -*- coding: utf-8 -*- class Student(object): #构造器 def __init__(self,name): self.__name = name #定制给用户看的类信息 #当调用print xxx时,会调用__str__方法 def __str__(self): return 'Student object (name:%s)' % self.__name #定制给程序员看的类信息 #当在交互终端直接输入xxx时,会调用__repr__方法 __repr__ = __str__ s = Student('zhangsan') print s
2.iter、next、getitem-让一个对象成为可迭代对象
让一个对象成为一个可以被迭代,可以使用下标索引元素,可以切片的对象。
#!/usr/bin/env python # -*- coding: utf-8 -*- class Fib(object): def __init__(self): self.a,self.b = 0,1 #初始化两个计数器a,b #对迭代的支持 def __iter__(self): return self #实例本身就是迭代对象,故返回自己 #对迭代的支持 def next(self): self.a,self.b = self.b,self.a + self.b if self.a > 10000: raise StopIteration() return self.a #返回下一个值 def __getitem__(self,n): #对使用下标索引元素的支持 if isinstance(n,int): a,b = 1,1 for x in range(n): a,b = b,a+b return a #对切片方法的支持 if isinstance(n,slice): start = n.start stop = n.stop a,b = 1,1 L = [] for x in range(stop): if x >= start: L.append(a) a,b = b,a+b return L f = Fib() for i in f: print i print '\n' print f[2] print '\n' print f[2:4]
3.getattr-访问不存在的属性或方法
#!/usr/bin/env python # -*- coding: utf-8 -*- class Student(object): #当且仅当对象的属性或方法不存在的时候,才会调用getattr方法 def __getattr__(self,attr_name): if attr_name == 'age': return lambda:25 s = Student() print s.age()
4.call-把实例变量当函数调用
#!/usr/bin/env python # -*- coding: utf-8 -*- class Student(object): def __init__(self,age): self.__age = age def __call__(self,age): return age def getAge(self): return self.__age s = Student(18) #此时调用的为getAge方法 print s.getAge() #判断实例变量是否可以直接当函数调用 if(callable(s)): #直接把对象当方法调用,则调用的为__call__方法 print s(29) else: print 'can not call instance'
6.使用type()函数创建一个新的类型
要创建一个class对象,type()函数依次传入3个参数:
- class的名称
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
- class的方法名称与函数绑定
#!/usr/bin/env python # -*- coding: utf-8 -*- def fn(self,name='world'): #先定义函数 print('Hello,%s' % name) Hello = type('Hello',(object,),dict(hello=fn)) #创建Hello class h = Hello() h.hello() print(type(Hello)) print(type(h))
7.使用metaclass创建一个list类的子类
new方法接收到的参数依次是:
1. 当前准备创建的类的对象
2. 类的名字
3. 类继承的父类集合
4. 类的方法集合#!/usr/bin/env python # -*- coding: utf-8 -*- # metaclass是创建类,所以必须从'type'类型派生 class ListMetaclass(type): def __new__(cls,name,bases,attrs): attrs['add'] = lambda self,value: self.append(value) return type.__new__(cls,name,bases,attrs) class MyList(list): __metaclass__ = ListMetaclass #指示使用ListMetaclass来定制类 L = MyList() L.add(1) L.add('aa') print L
8.ORM——metaclass使用场景
当用户定义一个class User(Model)时,Python解释器首先在当前类User的定义中查找metaclass,如果没有找到,就继续在父类Model中查找metaclass,找到了,就使用Model中定义的metaclass的ModelMetaclass来创建User类,也就是说,metaclass可以隐式的继承到子类,但子类自己却感觉不到。
在ModelMetaclass中,一共做了几件事情:
1. 排除掉对Model类的修改
2. 在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个mappings的dict中,同时从类属性中删除该Field属性,否则,容易运行时错误
3. 把表名保存到table中,这里简化为表名默认为类名#!/usr/bin/env python # -*- coding: utf-8 -*- class Field(object): def __init__(self,name,column_type): self.name = name self.column_type = column_type def __str__(self): return '<%s:%s>' % (self.__class__.__name__,self.name) class StringField(Field): def __init__(self,name): super(StringField,self).__init__(name,'varchar(100)') class IntegerField(Field): def __init__(self,name): super(IntegerField,self).__init__(name,'bigint') class ModelMetaclass(type): def __new__(cls,name,bases,attrs): #当Model类创建时,会进入if条件中,然后使用type创建类后,直接返回Model类 if name=='Model': print '--->attrs:%s' % attrs return type.__new__(cls,name,bases,attrs) print '<--->attrs:%s' % attrs #当User类创建时,不会进入if条件,而会执行下面的逻辑 mappings = dict() #对User类中的所有属性或者方法进行遍历,发现有值为Field类型的属性,则将属性名以及此属性的值(注意,属性的值其实是一个Field的子类类型)加入到mappings中 #此Mappings用于记录User类中每个属性都是什么类型的 for k,v in attrs.iteritems(): if isinstance(v,Field): print('Found mapping:%s==>%s' % (k,v)) mappings[k] = v #将User类中所有Field类型的属性全部删除 for k in mappings.iterkeys(): attrs.pop(k) #将__table__属性的值设置为类名 attrs['__table__'] = name #假设表名和类名一致 #将__mappings__属性的值设置为保存有"列名<--->类类型"映射关系的mappings attrs['__mappings__'] = mappings #保存属性和列的映射关系 #修改过attrs,使用type创建一个类,并返回 return type.__new__(cls,name,bases,attrs)