第1章课程介绍Python入门中我们学习了:如何安装Python环境变量和数据类型:Python内置的基本类型List列表和Tuple元组:顺序的集合类型条件判断和循环:控制程序流程函数:定义和调用函数切片:如何对list进行切片迭代:如何用for循环迭代集合类型列表生成式:如何快速生成列表Python进阶课程我们讲要学习:函数式编程:不是函数编程哦,是函数式编程模块:如何使用模块面向对象编程:面向对象的概念、属性、方法定制类:利用Python的特殊方法定制类第2章函数式编程1.什么是函数式编程:函数:function函数式:functional,一种编程范式函数式编程特点:把计算视为函数而非指令,贴近计算纯函数式编程:不需要变量,没有副作用,测试简单支持告诫函数,代码简洁Python支持的函数式编程特点:不是纯函数式编程:允许有变量支持高阶函数:函数也可以作为变量传入支持闭包:有了闭包就能返回函数有限度的支持匿名函数2.高阶函数变量可以指向函数,函数名其实就是指向函数的变量,而高阶函数其实就是可以接收函数做参数的函数。Len([1,2,3])=3Demo:接收abs函数定义一个函数,接收想,x,y,f三个参数,其中x,y是普通参数,z是函数。defadd(x,y,f)returnf(x)+f(y)把函数作为参数传入另一个函数创建实例属性虽然可以通过Person类创建出xiaoming、xiaohong等实例,但是这些实例看上除了地址不同外,没有什么其他不同。在现实世界中,区分xiaoming、xiaohong要依靠他们各自的名字、性别、生日等属性。如何让每个实例拥有各自不同的属性?由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值,例如,给xiaoming这个实例加上name、gender和birth属性:xiaoming=Person()xiaoming.name='XiaoMing'xiaoming.gender='Male'xiaoming.birth='1990-1-1'给xiaohong加上的属性不一定要和xiaoming相同:xiaohong=Person()xiaohong.name='XiaoHong'xiaohong.school='No.1HighSchool'xiaohong.grade=2实例的属性可以像普通变量一样进行操作:xiaohong.grade=xiaohong.grade+1任务请创建包含两个Person类的实例的list,并给两个实例的name赋值,然后按照name进行排序。sorted()是高阶函数,接受一个比较函数。参考代码:classPerson(object):passp1=Person()p1.name='Bart'p2=Person()p2.name='Adam'p3=Person()p3.name='Lisa'L1=[p1,p2,p3]L2=sorted(L1,lambdap1,p2:cmp(p1.name,p2.name))printL2[0].nameprintL2[1].nameprintL2[2].name初始化实例属性虽然我们可以自由地给一个实例绑定各种属性,但是,现实世界中,一种类型的实例应该拥有相同名字的属性。例如,Person类应该在创建的时候就拥有name、gender和birth属性,怎么办?在定义Person类时,可以为Person类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用,我们就能在此为每个实例都统一加上以下属性:classPerson(object):def__init__(self,name,gender,birth):self.name=nameself.gender=genderself.birth=birth__init__()方法的第一个参数必须是self(也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定,和定义函数没有任何区别。相应地,创建实例时,就必须要提供除self以外的参数:xiaoming=Person('XiaoMing','Male','1991-1-1')xiaohong=Person('XiaoHong','Female','1992-2-2')有了__init__()方法,每个Person实例在创建时,都会有name、gender和birth这3个属性,并且,被赋予不同的属性值,访问属性使用.操作符:printxiaoming.name#输出'XiaoMing'printxiaohong.birth#输出'1992-2-2'要特别注意的是,初学者定义__init__()方法常常忘记了self参数:classPerson(object):...def__init__(name,gender,birth):...pass...xiaoming=Person('XiaoMing','Male','1990-1-1')Traceback(mostrecentcalllast):Filestdin,line1,inmoduleTypeError:__init__()takesexactly3arguments(4given)这会导致创建失败或运行不正常,因为第一个参数name被Python解释器传入了实例的引用,从而导致整个方法的调用参数位置全部没有对上。任务请定义Person类的__init__方法,除了接受name、gender和birth外,还可接受任意关键字参数,并把他们都作为属性赋值给实例。要定义关键字参数,使用**kw;除了可以直接使用self.name='xxx'设置一个属性外,还可以通过setattr(self,'name','xxx')设置属性。参考代码:classPerson(object):def__init__(self,name,gender,birth,**kw):self.name=nameself.gender=genderself.birth=birthfork,vinkw.iteritems():setattr(self,k,v)xiaoming=Person('XiaoMing','Male','1990-1-1',job='Student')printxiaoming.nameprintxiaoming.job访问限制我们可以给一个实例绑定很多属性,如果有些属性不希望被外部访问到怎么办?Python对属性权限的控制是通过属性名来实现的,如果一个属性由双下划线开头(__),该属性就无法被外部访问。看例子:classPerson(object):def__init__(self,name):self.name=nameself._title='Mr'self.__job='Student'p=Person('Bob')printp.name#=Bobprintp._title#=Mrprintp.__job#=ErrorTraceback(mostrecentcalllast):Filestdin,line1,inmoduleAttributeError:'Person'objecthasnoattribute'__job'可见,只有以双下划线开头的__job不能直接被外部访问。但是,如果一个属性以__xxx__的形式定义,那它又可以被外部访问了,以__xxx__定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用__xxx__定义。以单下划线开头的属性_xxx虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。任务请给Person类的__init__方法中添加name和score参数,并把score绑定到__score属性上,看看外部是否能访问到。以双下划线开头的属性无法被外部访问,__xxx__除外。参考代码:classPerson(object):def__init__(self,name,score):self.name=nameself.__score=scorep=Person('Bob',59)printp.nameprintp.__score输出结果:BobTraceback(mostrecentcalllast):File./6172/58Wr/index.py,line9,inprintp.__scoreAttributeError:'Person'objecthasnoattribute'__score'创建类属性类是模板,而实例则是根据类创建的对象。绑定在一个实例上的属性不会影响其他实例,但是,类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。定义类属性可以直接在class中定义:classPerson(object):address='Earth'def__init__(self,name):self.name=name因为类属性是直接绑定在类上的,所以,访问类属性不需要创建实例,就可以直接访问:printPerson.address#=Earth对一个实例调用类的属性也是可以访问的,所有实例都可以访问到它所属的类的属性:p1=Person('Bob')p2=Person('Alice')printp1.address#=Earthprintp2.address#=Earth由于Python是动态语言,类属性也是可以动态添加和修改的:Person.address='China'printp1.address#='China'printp2.address#='China'因为类属性只有一份,所以,当Person类的address改变时,所有实例访问到的类属性都改变了。任务请给Person类添加一个类属性count,每创建一个实例,count属性就加1,这样就可以统计出一共创建了多少个Person的实例。?不会了怎么办由于创建实例必定会调用__init__()方法,所以在这里修改类属性count很合适。参考代码:classPerson(object):count=0def__init__(self,name):Person.count=Person.count+1self.name=namep1=Person('Bob')printPerson.count#=1p2=Person('Alice')printPerson.count#=2p3=Person('Tim')printPerson.count#=3#输出结果:123类属性和实例属性名字冲突怎么办修改类属性会导致所有实例访问到的类属性全部都受影响,但是,如果在实例变量上修改类属性会发生什么问题呢?classPerson(object):address='Earth'def__init__(self,name):self.name=namep1=Person('Bob')p2=Person('Alice')print'Person.address='+Person.addressp1.address='China'print'p1.address='+p1.addressprint'Person.address='+Person.addressprint'p2.address='+p2.address结果如下:Person.address=Earthp1.address=ChinaPerson.address=Earthp2.address=Earth我们发现,在设置了p1.address='China'后,p1访问address确实变成了'China',但是,Person.address和p2.address仍然是'Earch',怎么回事?原因是p1.address='China'并