这篇博客记录廖雪峰python教程的习题(二)

函数式编程

高阶函数—–sorted

首先我们需要明确一点就是sorted()函数是作用于一个列表,对列表中的每一项元素进行排序,因为sorted本身的作用就是对元素排序,如果后面还有key=function ,则是先对列表中的每一项元素按照function进行作用,sorted()函数在对返回的结果(仍然是存在一个list中)在进行排序!理解了上面的逻辑我们就可以做题啦。

“假设我们用一组tuple表示学生名字和成绩:
L = [(‘Bob’, 75), (‘Adam’, 92), (‘Bart’, 66), (‘Lisa’, 88)]
请用sorted()对上述列表分别按名字排序:”

代码如下:

#请用sorted()对上述列表分别按名字排序:
def main():
    L=[('Bob',98),('xuanxuan',90),('hehe',97),['Asas',100]]
    L1=sorted(L,key=sort_byname)
    print(L1)


def sort_byname(t):  #t这里代表着一个元组tuple因为list中每一项不再是单纯的一个元素,而是一个tuple
    return t[0].lower()
    #return t[0]

main()

需要注意的是这里sort_byname()函数的作用对象是sorted()函数中的list的每一项,在这里也就是一个tuple了,由于我们是希望对名字进行排序,sort_byname()函数只需要对一个tuple返回第一个元素值 也就是名字 ,然后sorted()函数会对返回来的值 再进行排序,自然就是按名字排序了

如果是按照分数进行排序呢:

#还是上面那个例子,请用sorted()对上述列表按分数进行排序
def main():
    L=[('Bob',98),('xuanxuan',90),('hehe',97),['Asas',100]]
    L1=sorted(L,key=sort_byscore)
    print(L1)

def sort_byscore(t):
    return t[1]

main()

返回函数

需要注意的是,如果一个函数的返回值仍然是一个函数或者函数的某种形式(比如说列表中的元素都是函数的形式等),那么只有当这个被返回的函数被调用时才会返回值。
现在通过例子说明一下啊:

返回函数,只有被返回的函数被调用时,才会计算里边参数的值

def count():
    fs=[]
    for i in range(1,4):
        def f():
            return i*i
        fs.append(f)
    return fs      

def main():
    f1,f2,f3=count()    #因为count()返回的是一个list 里边的元素都是函数,f1,f2,f3就以此对应了list列表中的三个函数,
    result1=f1()   #只不过这三个函数只有等到自己被调用时f1()时才会返回原本保存在函数中参数的值
    result2=f2()
    result3=f3()  #由于f()函数在定义时使用的时变化的i,因此前两次循环 fs列表中对应的元素--函数保存的并不是原来的1 和2 而是最后被更新到3
    print(result1,result2,result3)

main()

需要说明一下,上面的代码运行之后返回的都是9 。
首先调用count()函数,返回的是fs,一个list 只不过这个list函数存放的元素不是普通的整数或者字符,在这里是函数f,主函数里f1,f2,f3=count() 后就会把三次循环结束的函数依次赋值给 f1,f2,f3,也就是现在他们三个仍是函数,并不是某个具体的值,而且这三个函数里保存着需要返回的参数i ,只有当f1() f2() f3()这样被调用时,才会依次返回值。
而且返回的值都是9并不是期望的1,4,9 原因是前一次循环的i 被后一次给覆盖了,所以最后返回的都是i=3 即3*3=9的值

那如果想要返回1,4,9呢,下面提供两种方法:

#当然如果你想输出1 4 9的话 一种方法是返回的时候直接就调用这个函数,当然这种方法返回的就不是具体的函数了

def count():
    fs=[]
    for i in range(1,4):
        def f():
            return i*i
        fs.append(f())  #原本使用的是fs.append(f) 原来列表中存的是函数,现在列表中存放的是具体的值,因为f()就会调用上买你的函数,直接就会计算出来
    return fs

def main():
    r1,r2,r3=count()
    print(r1,r2,r3)

main()

另外一种仍然采用返沪函数的代码实现如下:

#如果还想返回的是一个函数,而不是具体的值,然后向输出1,4,9,怎么办呢,只需要在返回函数的地方,让他不再使用变化的参数即可

def count():
    fs=[]

    def f(i):  #定义一个函数,返回值仍然是一个函数
        def g():
            return i*i
        return g

    for i in range(1,4):
        fs.append(f(i))   #这里调用函数之后会保存这个参数的值,而不是再下一次循环中把上一次的参数值给冲掉
    return fs

def main():
    f1,f2,f3=count()  #count()函数返回的仍然是列表fs,里边的值仍然是函数,只不过函数里保存的参数i依次是1,2,3即下一次循环的值不会吧上一次循环的值给冲掉
    print(f1(),f2(),f3())  #只有对fs列表中存放的三个函数都进行调用时才会返回值

main()

”利用闭包返回一个计数器函数,每次调用它返回递增整数:“
我在编写的时候把要调用的次数用户输入了,直接输出每次调用的结果
代码如下:

#利用闭包返回一个计数器函数,每次调用它都会返回一个递增的整数

def count():           #count()函数就是会返回一个计数器函数 increase()

    def increase(n):   #increase()函数里面的参数是第几次调用它 
        number=0
        for i in range(n):   #根据调用的次数返回number的值,相当于就是计数累加
            number+=1
        return number

    return increase

def main():
    n=eval(input('please input a number:'))    #输入想调用计数器的次数n ,也就是说明想累加几次
    for i in range(n):
        f=count()   #现在f就是count()函数的返回值 是一个函数 increase()
        result=f(i) #increase(i) 就会返回第i次调用increase()函数累加的值
        print(result,end=' ')

main()

上面的代码其实逻辑上不对,修改如下:

#利用闭包返回一个计数器函数,每次调用它都会返回一个递增的整数
#20180206里面写的不对啊,逻辑不对
def count(n):   #count(n)函数就是会返回一个计数器函数increase(n),为什么这里要加一个参数,里面又重新定义了一个新的函数g呢是为了存储当前的变量值,防止下一次赋值把原来的变量值给冲掉

    def increase(i):    #这里i其实就是第几次调用的意思
        def g():
            sum=0
            for j in range(i):
                sum+=1
            return sum
        return g

    return increase(n)


def main():
    n=eval(input("please input a number:"))
    for i in range(n):
        f=count(i)
        result=f()
        print(result)

main()

哎,实现一个功能得想半天,,,难过

“请用匿名函数改造一下函数:”

#请用匿名函数改造下面的代码:
def is_odd(x):     #判断是否为奇数
    return x%2==1

def main():
    print(list(filter(is_odd,range(1,20))))

main()

使用匿名函数改写为:
list(filter(lambda x:x%2==1,range(1,20))) 即可。
匿名函数中:号前面的是函数的参数,匿名函数的返回值是后面的表达式的值

装饰器

“请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:”
这个代码是参考的这位大神

import time 
import functools
def log_time(func):
    @functools.wraps(func)
    def wrapper(*args,**kw):
        start=time.time()
        res=func(*args,**kw)
        end=time.time()
        print("%s runned in %s seconds"%(func.__name__,(end-start)*1000))
        return res
    return wrapper

@log_time
def f1(x,y):
    time.sleep(1)
    return x+y

def main():
    result=f1(1,2)
    print(result)

main()

下面的代码是我的一点点拓展:

#this code is to creat another feature

import functools,time

def log_time(text):  #给装饰器log_time()传入一个参数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args,**kw):
            start=time.time()    
            fun=func(*args,**kw)
            end=time.time()
            print("the progame %s runned in %s ms"%(func.__name__,(end-start)*1000))
            return fun
        return wrapper
    return decorator

#log_time(text)(f1)    
#先log_time(text) 返回一个decorator 函数,然后再decorator(f1) 在返回一个wrapper函数  至此就是@log_time("xuanxuan,,,") 和接下俩def f1()
@log_time("xuanxuan,you are a beautiful girl!")   
def f1(x,y,z):
    time.sleep(2) #作用是让函数暂停2s在执行,就是计算函数执行的时间的
    return x+y+z


def main():
    result=f1(2,3,4)
    print("the result and the name of this function is {} and {} ".format(result,f1.__name__))

main()

以下两个小题的答案参考自这位大神
“请编写一个decorator,能在函数调用的前后打印出’begin call’和’end call’的日志。”

相对比较简单,直接上代码:

#在函数运行的前后输出begin call和end call:

import functools
def log(func):
    @functools.wraps(func)
    def wrapper(*args,**kw):
        print("begin call %s():"%func.__name__)
        res=func(*args,**kw)
        print("the result of the program is {}".format(res))
        print("end call %s():"%func.__name__)
        #resturn res
    return wrapper

@log
def f2(x,y):
    return x+y

def main():
    f2(4,6)
    print("the name of the function is :"+f2.__name__)

main()

“再思考一下能否写出一个@log的decorator,使它既支持:
@log
def f():
pass
又支持:

@log(‘execute’)
def f():
pass”

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args,**kw):
            if text!=None:
                print("the text is %s and the call %s(): "%(text,func.__name__))
                res=func(*args,**kw)
                return res
            else:
                print("call %s ():"%func.__name__)
                res=func(*args,**kw)
                return res
        return wrapper

    if isinstance(text,str):  #首先如果有参数 就跟原来一样直接返回decorator即可
        return decorator
    else:    #如果没有参数 其实log(func)就是log里边其实直接传的参数就是func 返回的应该是wrapper  
        func=text
        text=None
        return decorator(func)  #所以这里的应该是直接decorator(func) 返回wrapper

@log("there is a parameter in this edition")
def f1(x,y):
    return x*y

def main1():
    result=f1(2,3)
    print("the result is {}".format(result))
    print("the name of this function(no_parameter) is "+f1.__name__)

@log
def f2(x,y):
    return x+y

def main2():
    result=f2(5,8)
    print("the result of this function(with parameter) is {}".format(result))
    print("the name of this function is "+f2.__name__)

def main():
    number=eval(input("please input a number to decide which the function to run:"))
    if number==1:
        main1()
        print("run successfully!")
    else:
        main2()
        print("Run successfully!")

main()

偏函数

简单的说 引入functools.partial 之后 就可以把原来函数的参数给固定住,从而创建一个新的函数,当然对于新的函数我们仍然是可以传入新的参数值的。

import functools

def main1():
    int2=functools.partial(int,base=4)
    result=int2('1000000')
    print(result)

def main2():
    max2=functools.partial(max,100)
    result=max(1,2,4,7,99)
    result1=max(1,2,3,102)
    print((result,result1))

#main1()   
main2()

你可能感兴趣的:(python_practice)