函数3



1. 内置函数

1.1 常用的内置函数

>>> cache = {}
>>> type(cache)
<type 'dict'>

Return whether an object is an instance of a class or of a subclass thereof. With a type as second argument, return whether that is the object’s type. The form using a tuple, isinstance(x, (A, B, …)), is a shortcut for isinstance(x, A) or isinstance(x, B) or … (etc.).

>>> isinstance(cache,dict)
True
>>> isinstance(cache,list)
False

Return whether the object is callable (i.e., some kind of function). Note that classes are callable, as are instances with a call() method.

>>> callable(abs)
True

# 类也是callable的
>>> class first_class:
...     '''class test'''
...     i = 123456
...
>>> type(first_class)
<type 'classobj'>
>>> callable(first_class)
True

Get a named attribute from an object; getattr(x, ‘y’) is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn’t exist; without it, an exception is raised in that case.

>>> t = 'good morning'
>>> def check_attr(obj):
...     result = [x for x in dir(obj) if '__' not in x]
...     print result
...
>>> check_attr(t)
['_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> t.split()
['good', 'morning']
>>> split_t = getattr(t, 'split')            #相当于split_t = t.split
>>> split_t
<built-in method split of str object at 0x7f50fdf824c8>
>>> split_t()
['good', 'morning']
# 获取对象的属性,用于自省(反射)
# 常用于自省,用于遍历对象的属性
>>> def check_attr(obj):
...     for i in dir(obj):
...         method  = getattr(obj, i)
...         if not i.startswith('__') and callable(method):
...             print i
...
>>> t = 12
>>> check_attr(t)
bit_length
conjugate
>>> s = 'string'
>>> check_attr(s)
_formatter_field_name_split
_formatter_parser
capitalize
center

upper
zfill

深入学习自省可以先预习一下: Inspect 模块的使用 https://docs.python.org/2/library/inspect.html

Returns the sum of a sequence of numbers (NOT strings) plus the value of parameter ‘start’ (which defaults to 0). When the sequence is empty, returns start.

>>> sum(range(20))
190

With a single iterable argument, return its largest item. With two or more arguments, return the largest argument.

>>> max(range(10))
9

With a single iterable argument, return its smallest item. With two or more arguments, return the smallest argument.

>>> min(range(10))
0

1.2 关键内置函数

Return those items of sequence for which function(item) is true.
If function is None, return the items that are true.
If sequence is a tuple or string, return the same type, else return a list.

## 返回类型
# tuple返回tuple
>>> t = (1, 2, 3, 4, 0)
>>> filter(None,t)
(1, 2, 3, 4)

# string返回string
>>> t = 'test string'
>>> filter(None,t)
'test string'

# 其他均返回list
>>> t = {1, 2, 's', 'b'}
>>> filter(None,t)
[1, 's', 'b', 2]

>>> t = {1:2, 's': 'b'}
>>> filter(None,t)
[1, 's']

## INSTANCE
# function处可以用lambda函数
>>> t = range(15)
>>> filter(lambda x: x < 10, t)                      #获取小于10的
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> filter(lambda x: x % 2 == 0, t)                  #获取偶数
[0, 2, 4, 6, 8, 10, 12, 14]

# url分析
>>> url = ['www.baidu.com', 'http://www.sina.com', 'https://www.apple.com']
>>> filter(lambda x: x.startswith('http'), url)
['http://www.sina.com', 'https://www.apple.com']
>>> filter(lambda x: 'www' in x, url)
['www.baidu.com', 'http://www.sina.com', 'https://www.apple.com']

Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

>>> zip(range(1, 10), range(11, 20), range(21, 30), range(31, 40))
[(1, 11, 21, 31), (2, 12, 22, 32), (3, 13, 23, 33), (4, 14, 24, 34), (5, 15, 25, 35), (6, 16, 26, 36), (7, 17, 27, 37), (8, 18, 28, 38), (9, 19, 29, 39)]

Return a list of the results of applying the function to the items of the argument sequence(s). If more than one sequence is given, the function is called with an argument list consisting of the corresponding item of each sequence, substituting None for missing values when not all sequences have the same length. If the function is None, return a list of the items of the sequence (or a list of tuples if more than one sequence).

# 1个参数
>>> map(lambda x:x*10, range(10))
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

# 多个参数
# 两个sequence的元素数必须一致
>>> map(lambda x,y:x*y, range(10), range(10, 20))
[0, 11, 24, 39, 56, 75, 96, 119, 144, 171]
>>> map(lambda x,y,z:x*y*z, range(10), range(10, 20), range(20, 30))
[0, 231, 528, 897, 1344, 1875, 2496, 3213, 4032, 4959]
>>> map(lambda x,y:(x,y), range(-10,0), range(-5,5))
[(-10, -5), (-9, -4), (-8, -3), (-7, -2), (-6, -1), (-5, 0), (-4, 1), (-3, 2), (-2, 3), (-1, 4)]

可以通过多进行库,实现并行(后续会讲到)

Apply a function of two arguments cumulatively to the items of a sequence, from left to right, so as to reduce the sequence to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). If initial is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty.

>>> reduce(lambda x,y: x+y ,range(5))          # 求累加
10
>>> reduce(lambda x,y: x+y**2 ,range(5))       # 求平方和
30
>>> reduce(lambda x,y: x+y**2 ,[2, 3, 4])      # 平方和不对,因为2没有平方         
27
>>> reduce(lambda x,y: x+y**2 ,[2, 3, 4],0)    # 可以赋初始值给函数
29

参考:https://github.com/StevenSLXie/Tutorials-for-Web-Developers/blob/master/Python%E7%9A%84map%7Cfilter%7Creduce%E5%B8%B8%E8%A7%81%E7%94%A8%E6%B3%95%E4%BE%8B%E4%B8%BE.md

2. 如何实现python语言的威力

  1. 对内置函数的掌握程度
  2. 优秀的库

3. 函数装饰器(DECORATOR)

3.1 准备知识

3.1.1 函数是一个对象,可以赋值给一个变量

>>> def shout(word='yes'):
...     return word.capitalize()+'!'
...
>>> loudly = shout                     # function 是一个object,可以被引用
>>> del shout                          # 删掉原function 'shout'
>>> loudly                             # loudly 依然可以使用
<function shout at 0x7f50fdefdde8>
>>> loudly()
'Yes!'

3.1.2 函数可以在另外一个函数内部被定义,而且可以传参数进去,可以被返回

>>> def wrapper():
...     a = 1
...     def inner(x=1):
...         result = x * a
...         return result
...     return inner
...
>>> var = wrapper()
>>> var
<function inner at 0x7f50fdf058c0>
>>> var(12)
12
>>> inner(5)                      #里面的function不可以直接调用
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'inner' is not defined

3.1.3 function可以作为一个参数传入另外一个function使用

>>> def wrapper(func):
...     def inner(x_new):
...         func(x_new)
...         return x_new * 2
...     return inner
...
>>> def multiplication(x):
...     print "number is :%s" % x
...     print "double it, result is:"
...
>>> multiplication = wrapper(multiplication)
>>> multiplication(20)
number is :20
double it, result is:
40

现在准备知识我们已经回顾完毕;

其实,decorator就是一个wrapper,这意味着,你可以在不改变一个function本身的同时可以在它之前或之后添加代码。

3.2 DECORATOR

## 上面的函数我们可以修改为
>>> def wrapper(func):
...     def inner(x_new):
...         func(x_new)
...         return x_new * 2
...     return inner
...
>>> @wrapper                       #相当于new_multi = wrapper(new_multi)
... def new_multi(x):
...     print "number is :%s" % x
...     print "double it, result is:"
...
>>> new_multi(20)
number is :20
double it, result is:
40

## 为了方便接收参数,innner()的形参可以设定为inner(*args, **kwargs),然后再把*args转给func的参数

课外参考: http://blog.xiayf.cn/2013/01/04/Decorators-and-Functional-Python/

4. 递归和尾递归

4.1 概念

4.2 实例体验

# 斐波那契数列:
# 1, 1, 2, 3, 5, 8, 13, 21 ..
# 当前值等于前两个值的和
def fib(n):
    if n<=2:
        return 1
    else:
        return fib(n-1)+fib(n-2);

扩展阅读: http://www.cnblogs.com/figure9/archive/2010/08/30/1812927.html

5. 课后练习:

  1. 课堂练习:使用装饰器检测函数执行时间

  2. 课后练习:使用装饰器实现对以下函数的缓存,以减少重复内容的重复运算。

def multiple(number):
    result = 1
    for i in range(1, number):
        result = result * i
    return result
# 提示: dict实现缓存
  1. 课堂练习:如何查看该函数执行次数:比如fib(20) 会执行多少次fib函数?

  2. 课后练习:如何使用装饰器缓存来优化代码,减少fib执行的次数。

#!/usr/bin/python


'''decorator and recurision'''

import time

def process_time(func):
    def inner(args):
        start = time.time()
        result = func(args)
        time_spent = time.time() - start
        print "\ttime spent is: %.4f" % time_spent
    return inner

def cache(func):
    cache_dic = dict()
    def inner(args):
        if args not in cache_dic:
            cache_dic.update({args:func(args)})
        else:
            print "\thit cache"
        print '\tthe result is: %d' % cache_dic[args]
        return cache_dic[args]
    return inner

@process_time
@cache
def multiple(number):
    result = 1
    for i in range(1, number):
        result = result * i
    return result

if __name__ == "__main__":
    while True:
        number = raw_input("input a number pls:")
        if number == 'quit':
            break
        try:
            number = int(number)
        except ValueError as e:
            print "pls input a number or quit"
            continue
        multiple(number)
#!/usr/bin/python


'''decorator and recurision'''

def cache(func):
    cache_dic = dict()
    def inner(args):
        if args not in cache_dic:
            cache_dic.update({args:func(args)})
        else:
            print '\thit cache'
        return cache_dic[args]
    return inner

def count(func):
    def inner(new_n):
        global count_fib
        count_fib += 1
        result = func(new_n)
        return result
    return inner

@count
@cache
def fib(n):
    if n <= 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)

if __name__ == "__main__":
    while True:
        number = raw_input("input a number pls:")
        if number == 'quit':
            break
        try:
            number = int(number)
        except ValueError as e:
            print e
        count_fib = 0
        print "\t======================\n\tthe %dth fib is %r" %(number, fib(number))
        print "\tthe process times is %d" % count_fib