python学习笔记05-python面向对象编程

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定义的和子类自己的slots

class 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个参数: 

  1. class的名称
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
  3. 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)

猜你喜欢

转载自blog.csdn.net/ybf326/article/details/83928505