Python 函数式编程和面向对象编程等(进阶)

函数式编程


        函数:function。
        函数式:functional,一种编程范式。函数式编程是一种抽象计算机的编程模式。

        函数!= 函数式(如计算!=计算机)

        如下是不同语言的抽象 层次不同
         Python 函数式编程和面向对象编程等(进阶)_第1张图片

高阶函数

        能接收函数做参数的函数

  1. 变量可以指向函数
  2. 函数的参数可以接收变量
  3. 一个函数可以接收另一个函数作为参数

例子

        接收abs函数, 定义一个函数,接收x,y,z三个参数。其中x,y是数值,z是函数 。
1
2
3
def  add(x,y,z):
     return  z(x) + z(y)
print  add( - 2 , - 3 , abs )
        其他高阶函数: map()函数、reduce()函数、filter()函数。

        PS:Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数!

闭包

        像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。

        特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:         

# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()

        你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。


        原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:

>>> f1()
9     # 因为f1现在才计算i*i,但现在i的值已经变为3


        因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。


匿名函数(lambda )
>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]

        通过对比可以看出,匿名函数lambda x: x * x 实际上就是:

def f(x):
    return x * x

        关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数

        (匿名函数有个限制,就是 只能有一个表达式不写return,返回值就是该表达式的结果,返回函数的时候,也可以返回匿名函数。)

装饰器 decorator

        Python 的  decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。

        使用 decorator 用 Python 提供的  @ 语法,这样可以避免手动编写  f = decorate(f) 这样的代码, 极大简化Python代码。
         Python 函数式编程和面向对象编程等(进阶)_第2张图片

模块 

        导入系统自带的模块 math: 
        import math

        如果我们只希望导入用到的 math 模块的某几个函数,而不是所有函数,可以用下面的语句:
        from math import pow, sin, log

如果遇到名字冲突怎么办?

        如果使用 import 导入模块名,由于必须通过模块名引用函数名,因此不存在冲突;

        如果使用 from...import 导入 log 函数,势必引起冲突。这时,可以给函数起个“别名”来避免冲突:
        from math import log
        from logging import log as logger   # logging的log现在变成了logger

        print log(10)   # 调用的是math的log
        logger(10, 'import from logging')   # 调用的是logging的log

动态导入模块

        下面代码先尝试从cStringIO导入,如果失败了(比如cStringIO没有被安装),再尝试从StringIO导入。
1
2
3
4
try :
     from  cStringIO  import  StringIO
except  ImportError:
     from  StringIO  import  StringIO
     
        利用import ... as ...,还可以动态导入不同名称的模块
1
2
3
4
try :
     import  json
except  ImportError:
     import  simplejson as json

PS:
        1. Python的新版本会引入新的功能,但是实际上这些功能在上一个老版本中就已经存在了。要“试用”某一新的特性,就可以通过导入__future__模块的某些功能来实现。
        2. 如何区分包和普通目录:包下面有个__init__.py 每层都有。

安装第三方模块

        1. 使用easy_install
        2. pip(推荐,内置到Python2.7.9)
1
2
3
4
5
wget  "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz#md5=834b2904f92d46aaa333267fb1c922bb"  --no-check-certificate  #下载pip
tar  -xzvf pip-1.5.4. tar .gz
cd  pip-1.5.4  #(会提示安装setuptools,yum install python-setuptools 即可)
python setup.py  install
pip  install  pymongo  #可以使用pip安装第三方模块了
        也可以直接 yum install python-pip 

面向对象编程


定义类并创建实例

        定义一个Person类如下
1
2
class  Person( object ):
     pass
        (object),表示该类是从哪个类继承下来的。

        创建实例
        xiaoming = Person()

如何让每个实例拥有各自不同的属性?

        由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值,例如,给xiaoming这个实例加上name、gender和birth属性: 
1
2
3
4
xiaoming  =  Person()
xiaoming.name  =  'Xiao Ming'
xiaoming.gender  =  'Male'
xiaoming.birth  =  '1990-1-1'

        给xiaohong加上的属性不一定要和xiaoming相同:
1
2
3
4
xiaohong  =  Person()
xiaohong.name  =  'Xiao Hong'
xiaohong.school  =  'No. 1 High School'
xiaohong.grade  =  2

        实例的属性可以像普通变量一样进行操作:
1
xiaohong.grade  =  xiaohong.grade  +  1

初始化实例属性
1
2
3
4
5
class  Person( object ):
     def  __init__( self , name, gender, birth):
         self .name  =  name
         self .gender  =  gender
         self .birth  =  birth
        __init__() 方法的第一个参数必须是 self(也可以用别的名字,但建议使用习惯用法)。后续参数则可以自由指定,和定义函数没有任何区别。
        
        相应地,创建实例时,就必须要提供除 self 以外的参数:
1
2
xiaoming  =  Person( 'Xiao Ming' 'Male' '1991-1-1' )
xiaohong  =  Person( 'Xiao Hong' 'Female' '1992-2-2' )

定义实例方法
1
2
3
4
5
6
class  Person( object ):
     def  __init__( self , name):
         self .__name  =  name
  
     def  get_name( self ):  #它的第一个参数永远是 self,指向调用该方法的实例本身
         return  self .__name

定义类方法(类似Java的静态方法)
1
2
3
4
5
6
7
8
9
10
11
12
class  Person( object ):
     count  =  0
     @ classmethod
     def  how_many( cls ):  #类方法
         return  cls .count
     def  __init__( self , name):
         self .name  =  name
         Person.count  =  Person.count  +  1
 
print  Person.how_many()
p1  =  Person( 'Bob' )
print  Person.how_many()

访问限制
    
        如果一个属性由双下划线开头(__),该属性就无法被外部访问(相当于private)。 但是,如果一个属性以"__xxx__"的形式定义,那它又可以被外部访问了,以"__xxx__"定义的属性在 Python 的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"__xxx__"定义。

题目

请定义Person类的__init__方法,除了接受 name、gender 和 birth 外,还可接受任意关键字参数,并把他们都作为属性赋值给实例。

要定义关键字参数,使用 **kw

除了可以直接使用self.name = 'xxx'设置一个属性外,还可以通过 setattr(self, 'name', 'xxx') 设置属性。

参考代码:

class Person(object):
    def __init__(self, name, gender, birth, **kw):
        self.name = name
        self.gender = gender
        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

类的继承

继承一个类
1
2
3
4
class  Person( object ):
     def  __init__( self , name, gender):
         self .name  =  name
         self .gender  =  gender
        定义 Student 类时,只需要把额外的属性加上,例如score:
1
2
3
4
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()可以判断一个变量的类型
1
>>>  isinstance (p, Person)

获取对象信息

        除了用 isinstance() 判断它是否是某种类型的实例外, type() 函数获取变量的类型,它返回一个 Type 对象。 可以用 dir() 函数获取变量的所有属性: dir(s)。


参考

        慕课网,python进阶

你可能感兴趣的:(Python)