美文网首页工作生活
Python进阶语法——函数式编程、模块,面向对象

Python进阶语法——函数式编程、模块,面向对象

作者: Super_Grace | 来源:发表于2019-07-02 20:31 被阅读4次

    一、 Python进阶学习

    ![1561517114609.png](https://img.haomeiwen.com/i18575213/055b0d93ec1ac882.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    一、函数式编程

    1.1函数式编程

    1561517114609.png 1561517172562.png ![1561517281088.png](https://img.haomeiwen.com/i18575213/acd06f8057bd7dfc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    1.2高阶函数

    1.2.1

    ![1561517550621.png](https://img.haomeiwen.com/i18575213/08d529dcc74f60b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    import math
    def add(x, y, f):
    return f(x) + f(y)
    print add(25, 9, math.sqrt)

    1.2.2python中map()函数

    map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。

    def f(x):
    return x*x
    print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    输出结果:

    [1, 4, 9, 10, 25, 36, 49, 64, 81]
    注意:map()函数不改变原有的 list,而是返回一个新的 list。


    1561518419092.png

    利用map()函数,可以把一个 list 转换为另一个 list,只需要传入转换函数。

    1.2.3python中reduce()函数

    reduce()函数也是一个高阶函数,接收的参数一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。

    (1)编写一个f函数,接收x和y,返回x和y的和:

    def f(x, y):
    return x + y
    调用 reduce(f, [1, 3, 5, 7, 9])时,reduce函数将做如下计算:

    先计算头两个元素:f(1, 3),结果为4;
    再把结果和第3个元素计算:f(4, 5),结果为9;
    再把结果和第4个元素计算:f(9, 7),结果为16;
    再把结果和第5个元素计算:f(16, 9),结果为25;
    由于没有更多的元素了,计算结束,返回结果25。
    上述计算实际上是对 list 的所有元素求和。
    虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。

    reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:

    reduce(f, [1, 3, 5, 7, 9], 100)
    结果是125

    (2)编写一个f函数,接收x和y,返回x和y的积:

    def prod(x, y):
    return x * y
    print reduce(prod, [2, 4, 5, 7, 12])

    1.2.4python中filter()函数

    filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。

    eg:请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
    import math
    def is_sqr(x):
    if math.sqrt(x)%1==0 :
    return x
    print filter(is_sqr, range(1, 101))

    注意:s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符

    当rm为空时,默认删除空白符(包括'\n', '\r', '\t', ' '),如下:
    a='\t\t123\r\n'
    a.strip()
    结果:'123'

    1.2.5python中自定义排序函数

    Python内置的 sorted()函数可对list进行排序:

    sorted([36, 5, 12, 9, 21])
    [5, 9, 12, 21, 36]

    但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。

    要实现倒序排序,只需要编写一个reversed_cmp函数:

    def reversed_cmp(x, y):
    if x > y:
    return -1
    if x < y:
    return 1
    return 0
    这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:

    参数先写list,再写f函数!!!!!

    sorted([36, 5, 12, 9, 21], reversed_cmp)
    [36, 21, 12, 9, 5]
    sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:

    sorted(['bob', 'about', 'Zoo', 'Credit'])
    ['Credit', 'Zoo', 'about', 'bob']
    'Zoo'排在'about'之前是因为'Z'的ASCII码比'a'小。

    任务
    对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。

    输入:['bob', 'about', 'Zoo', 'Credit']
    输出:['about', 'bob', 'Credit', 'Zoo']

    1.2.6返回函数

    请注意区分返回函数和返回值:

    def myabs():

    return abs   # 返回函数
    

    def myabs2(x):
    return abs(x) # 返回函数调用的结果,返回值是一个数值

    eg:
    def calc_sum(lst):
    def lazy_sum():
    return sum(lst)
    return lazy_sum

    调用calc_sum()并没有计算出结果,而是返回函数:

    f = calc_sum([1, 2, 3, 4])
    f
    eg:请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
    >import math
    def is_sqr(x):
    if math.sqrt(x)%1==0 :
    return x
    print filter(is_sqr, range(1, 101))

    >>注意:s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符

    >当rm为空时,默认删除空白符(包括'\n', '\r', '\t', ' '),如下:
    a='\t\t123\r\n'
    a.strip()
    结果:'123'

    ###1.2.5python中自定义排序函数
    Python内置的 sorted()函数可对list进行排序:
    >sorted([36, 5, 12, 9, 21])
    [5, 9, 12, 21, 36]

    但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。

    要实现倒序排序,只需要编写一个reversed_cmp函数:

    >def reversed_cmp(x, y):
    if x > y:
    return -1
    if x < y:
    return 1
    return 0
    这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:
    >>参数先写list,再写f函数!!!!!

    >> sorted([36, 5, 12, 9, 21], reversed_cmp)
    [36, 21, 12, 9, 5]
    sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:

    >> sorted(['bob', 'about', 'Zoo', 'Credit'])
    ['Credit', 'Zoo', 'about', 'bob']
    'Zoo'排在'about'之前是因为'Z'的ASCII码比'a'小。

    任务
    对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。

    输入:['bob', 'about', 'Zoo', 'Credit']
    输出:['about', 'bob', 'Credit', 'Zoo']
    ###1.2.6返回函数
    请注意区分返回函数和返回值:
    >def myabs():
    return abs # 返回函数
    def myabs2(x):
    return abs(x) # 返回函数调用的结果,返回值是一个数值

    >>eg:
    >def calc_sum(lst):
    def lazy_sum():
    return sum(lst)
    return lazy_sum

    调用calc_sum()并没有计算出结果,而是返回函数:

    >> f = calc_sum([1, 2, 3, 4])
    >> f
    <function lazy_sum at 0x1037bfaa0>
    对返回的函数进行调用时,才计算出结果:
    f()
    10

    1.2.7闭包(Closure)

    1、定义
    内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
    2、特点
    返回的函数还引用了外层函数的局部变量,要确保引用的局部变量在函数返回后不能变。举例如下:
    希望一次返回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
    因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
    修改后:

    def count():
    fs = []
    for i in range(1, 4):
    def f(j):
    def g():
    return j*j
    return g
    fi=f(i)
    fs.append(fi)
    return fs
    f1, f2, f3 = count()
    print f1(), f2(), f3()

    1.2.8匿名函数lambda

    关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。
    匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。
    使用匿名函数,可以不必定义函数名,直接创建一个函数对象:

    sorted([1, 3, 9, 5, 0], lambda x,y : -cmp(x,y))
    [9, 5, 3, 1, 0]

    返回函数的时候,也可以返回匿名函数:

    myabs = lambda x : -x if x < 0 else x
    myabs(-1)
    1

    1.2.9decorator装饰器

    1、装饰器定义

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


    1561535968062.png

    使用装饰器:


    1561536060596.png ![1561536294538.png](https://img.haomeiwen.com/i18575213/9b1a6698cf579312.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    2、编写无参数的decorator
    要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用:

    def log(f):
    def fn(*args, *kw):
    print 'call ' + f.name + '()...'
    return f(
    args, **kw)
    return fn

    eg:请编写一个@performance,它可以打印出函数调用的时间。

    计算函数调用的时间可以记录调用前后的当前时间戳,然后计算两个时间戳的差。
    import time
    def performance(f):
    def fn(*args, *kw):
    t1 = time.time()
    r = f(
    args, *kw)
    t2 = time.time()
    print 'call %s() in %fs' % (f.name, (t2 - t1))
    return r
    return fn
    performance
    def factorial(n):
    return reduce(lambda x,y: x
    y, range(1, n+1))
    print factorial(10)

    3、带参数的decorator
    如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时,log函数本身就需要传入'INFO'或'DEBUG'这样的参数,类似这样:

    @log('DEBUG')
    def my_func():
    pass

    把上面的定义翻译成高阶函数的调用,就是:

    my_func = log('DEBUG')(my_func)

    上面的语句看上去还是比较绕,再展开一下:

    log_decorator = log('DEBUG')
    my_func = log_decorator(my_func)

    eg:@performance只能打印秒,请给 @performace 增加一个参数,允许传入's'或'ms':


    1561539338978.png

    三层嵌套:最外层要先返回一个decorator,第二层返回wrapper,第三层返回原来的函数f

    1.2.10完善的decorator

    decorator“改造”后的函数,和原函数相比,除了功能多一点外,有没有其它不同的地方?

    (1)在没有decorator的情况下,打印函数名:

    def f1(x):
    pass
    print f1.name
    输出: f1

    (2)有decorator的情况下,再打印函数名:

    def log(f):
    def wrapper(*args, *kw):
    print 'call...'
    return f(
    args, **kw)
    return wrapper
    @log
    def f2(x):
    pass
    print f2.name
    输出: wrapper

    解决方案:
    Python内置的functools可以用来自动化完成这个“复制”的任务:

    import functools
    def log(f):
    @functools.wraps(f)
    def wrapper(*args, *kw):
    print 'call...'
    return f(
    args, **kw)
    return wrapper
    二、模块
    模块名冲突:

    1561600539881.png

    引用模块:


    ![1561600680685.png](https://img.haomeiwen.com/i18575213/d98ca2ccec31aed9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    包可以有多层:
    但每一层必须 包含一个文件__init.py

    ![![![1561603309443.png](https://img.haomeiwen.com/i18575213/e987af8cefcec89c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ](https://img.haomeiwen.com/i18575213/c420429ca6c80562.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ](https://img.haomeiwen.com/i18575213/847063dea88323c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    2.2导入模块

    若干种方式:(eg :os.path)

    import os
    import os.path
    from os import path
    from os.path import isdir, isfile

    [图片上传失败...(image-bf3006-1562071047270)]
    2、动态导入模块

    try:
    from cStringIO import StringIO
    except ImportError:
    from StringIO import StringIO
    try 的作用是捕获错误,并在捕获到指定错误时执行 except 语句。

    导入新版本的新特性:
    当新版本的一个特性与旧版本不兼容时,该特性将会在旧版本中添加到future中,以便旧的代码能在旧版本中测试新特性。

    from future import unicode_literals
    s = 'am I an unicode?'
    print isinstance(s, unicode)

    3、导入第三方模块
    python内置了许多模块,但仍有外部模块,可以导入使用
    eg:pip

    三、面向对象

    1561603249167.png
    1561603309443.png

    3.1实例化属性:

    请定义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

    3.2属性的访问限制:

    [图片上传中...(1561606531797.png-a6873d-1562070557388-0)]

    (1)以双下划线开头的属性‘__xxx'不能直接被外部访问。
    (2)以"xxx"的形式定义,那它又可以被外部访问了,以"xxx"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"xxx"定义。
    (3)以单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。

    3.3类属性

    实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
    定义类属性可以直接在 class 中定义:
    class Person(object):
    address = 'Earth'
    def init(self, name):
    self.name = name
    因为类属性是直接绑定在类上的,所以,访问类属性不需要创建实例,就可以直接访问:
    print Person.address
    => Earth
    p1 = Person('Bob')
    print p1.address
    => Earth

    类属性和实例属性名冲突:

    当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
    千万不要在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性。

    定义实例方法:

    虽然私有属性无法从外部访问,但是,从类的内部是可以访问的。除了可以定义实例的属性外,还可以定义实例的方法。
    实例的方法就是在类中定义的函数

    它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的.

    定义类方法:
    方法也分实例方法和类方法。
    在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。
    在class中定义类方法:

    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()
    通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例。类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.count 实际上相当于 Person.count。
    可以通过一个类方法获取类的私有属性。

    四、继承

    4.1继承

    1561620022645.png 1561620429253.png

    判断数据类型:
    函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以判断类的对象的类型

    isinstance(p, Person)
    True
    isinstance(p, Student)
    False

    PS:以上是2019-06-26到2019-06-07学习廖雪峰老师python进阶课程记录~

    相关文章

      网友评论

        本文标题:Python进阶语法——函数式编程、模块,面向对象

        本文链接:https://www.haomeiwen.com/subject/taathctx.html