zoukankan      html  css  js  c++  java
  • Python学习7——抽象

    将语句组合成函数,可以告诉计算机如何完成任务,且只需说一次,而不用反复向计算机传达详细指令。

    斐波那契数(一种数列,其中每个数都是前两个数的和):

    >>> fibs = [0,1]
    >>> for i in range(10):
        fibs.append(fibs[-2]+fibs[-1])
    
        
    >>> fibs
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

    优化一下代码,使其指定动态的范围:

    >>> fibs = [0,1]
    >>> num = input('enter:')
    enter:10
    >>> for i in range(int(num)-2):
        fibs.append(fibs[-2]+fibs[-1])
    
        
    >>> fibs
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

    如果不从用户那里读取数字,而是通过参数来获取,可以继续优化代码:

    >>> def fibs(num):
        re = [0,1]
        for i in range(num-2):
            re.append(re[-2]+re[-1])
        return re
    
    >>> fibs(10)
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

    def语句定义函数,return语句用于从函数返回值。num是一个形参,可以在其他地方多次调用fibs(),而不用每次都要将代码再敲一遍。

    除了#注释之外,还有一种编写注释的方式,就是添加独立的字符串。放在函数开头的字符串称为文档字符串。

    >>> def square(x):
        'Calculates the square of the number x.'
        return x * x
    
    >>> square.__doc__     #访问文档字符串
    'Calculates the square of the number x.'

    __doc__是函数的属性。

    >>> help(square)    #内置函数help可以获取有关函数的信息
    Help on function square in module __main__:
    
    square(x)
        Calculates the square of the number x.

    修改参数

    当参数为可变的数据结构(列表)时,在函数内修改参数,在外面调用函数。

    >>> def change(n):
        n[0] = 'Mr.Gumby'
    
        
    >>> names = ['Mrs.Entity','Mrs.Thing']
    >>> change(names)
    >>> names
    ['Mr.Gumby', 'Mrs.Thing']

    上面栗子也可以这么写:

    >>> names = ['Mrs.Entity','Mrs.Thing']
    >>> n = names      #假装传递名字作为参数
    >>> n[0] = 'Mr.Gumby'     #修改列表,这步上面是在函数内进行的
    >>> names
    ['Mr.Gumby', 'Mrs.Thing']    

    将同一个列表赋给两个变量时,这两个变量将同时指向这个列表。想避免这种结果,必须创建列表的副本。

    >>> names = ['Mrs.Entity','Mrs.Thing']
    >>> n = names[:]    #对序列进行切片操作时,返回的切片是副本。现在n和names包含2个相等但不同的列表。这里也可以用names.copy()来创建副本。
    >>> n[0] = 'Mr.Gumby'
    >>> names
    ['Mrs.Entity', 'Mrs.Thing']
    >>> n
    ['Mr.Gumby', 'Mrs.Thing']

    将切片参数传给函数,也不会影响:

    >>> def change(n):
        n[0] = 'Mr.Gumby'
    
        
    >>> names = ['Mrs.Entity','Mrs.Thing']
    >>> change(names[:])
    >>> names
    ['Mrs.Entity', 'Mrs.Thing']

    栗子:假设编写一个程序,让它储存姓名,并让用户能够根据名字,中间名或姓找人。

    创建初始化数据结构的函数:

    >>> def init(data):
        data['first'] = {}
        data['middle'] = {}
        data['last'] = {}
    
        
    >>> storage = {}
    >>> init(storage)   #这个函数承担了初始化职责,提高了代码的可读性。
    >>> storage
    {'first': {}, 'middle': {}, 'last': {}}

    然后需要一个函数来获取人员姓名:

    >>> def lookup(data,label,name):
        return data[label].get(name)

    接着要将人员存储到数据结构中:

    >>> def store(data,full_name):    #将参数data和full_name提供给这个函数。
        names = full_name.split()   #通过拆分full_name创建1个名为names的列表。
        if len(names) == 2 : names.insert(1,'')  #如果只有名字和姓,没有中间名,就将中间名设为空字符串
        labels = 'first','middle','last'    #将label存储到元组中(也可以是列表)
        for name,label in zip(names,labels):   #zip函数将label和name合并,可以对label-name对执行一些操作
            people = lookup(data,label,name) 
            if people:
                people.append(full_name)  #将full_name插入一个新列表
            else:
                data[label][name]=[full_name]

    现在运行看看:

    >>> me = {}
    >>> init(me)
    >>> me
    {'first': {}, 'middle': {}, 'last': {}}
    >>> store(me,'Magnus Lie Hetland')
    >>> me
    {'first': {'Magnus': ['Magnus Lie Hetland']}, 'middle': {'Lie': ['Magnus Lie Hetland']}, 'last': {'Hetland': ['Magnus Lie Hetland']}}
    >>> lookup(me,'middle','Lie')
    ['Magnus Lie Hetland']
    >>> store(me,'Robin Hood')
    >>> store(me,'Robin Locksley')
    >>> store(me,'Mr. Gumby')
    >>> lookup(me,'first','Robin')
    ['Robin Hood', 'Robin Locksley']
    >>> lookup(me,'middle','')
    ['Robin Hood', 'Robin Locksley', 'Mr. Gumby']

    关键字参数

    当函数需要传多个参数时,参数的位置就变的非常重要,比名字还重要。

    >>> def hello_1(greeting,name):
        print('{},{}!'.format(greeting,name))
    
        
    >>> def hello_2(name,greeting):
        print('{},{}!'.format(name,greeting))
    
        
    >>> hello_1('hello','world')
    hello,world!
    >>> hello_2('hello','world')
    hello,world!

    为了避免遗忘参数的位置,可以用关键字参数(用名称指定参数):

    >>> hello_1(greeting='hello',name='world')
    hello,world!
    >>> hello_2(greeting='hello',name = 'world')
    world,hello!

    给参数指定默认值:

    >>> def hello_3(greeting = 'hello',name='world'):   #给参数指定默认值后,调用函数时可不提供它。
        print('{},{}!'.format(greeting,name))
    
        
    >>> hello_3()   #不提供参数
    hello,world!
    >>> hello_3('Greetings','universe')    #提供全部参数值
    Greetings,universe!
    >>> hello_3(name='Gumby')    #提供部分参数值

    收集参数

    >>> def print_params(*params):  #参数前面的星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。
        print(params)
    
        
    >>> print_params('Testing')
    ('Testing',)
    >>> print_params(1,2,3)
    (1, 2, 3)
    >>> x,*y,z = 1,2,3,4,5,6   #上面的情况与赋值时的星号有点相似,不过赋值时带星号的变量收集多余的值
    >>> x,y,z
    (1, [2, 3, 4, 5], 6)    #并且是将收集的值放在列表中
    >>> def print_params_2(title,*params):
        print(title)
        print(params)
    
        
    >>> print_params_2('Params:',1,2,3)   #星号意味着收集余下的位置参数
    Params:
    (1, 2, 3)
    >>> print_params_2('Nothing:')   #如果没有可收集的参数,params将是一个空元组
    Nothing:
    ()

    当带星号的参数位置不在末尾:

    >>> def in_the_middle(x,*y,z,f):
        print(x,y,z,f)
    
        
    >>> in_the_middle(1,2,3,4,5,z=6,f=7)   #需要使用名称来指定后续参数
    1 (2, 3, 4, 5) 6 7
    >>> in_the_middle(1,2,3,4,5,6,7)
    Traceback (most recent call last):
      File "<pyshell#26>", line 1, in <module>
        in_the_middle(1,2,3,4,5,6,7)
    TypeError: in_the_middle() missing 2 required keyword-only arguments: 'z' and 'f'

    单个星号不会收集关键字参数,要收集关键字参数,可使用两个星号:

    >>> def print_params_3(**params):
        print(params)
    
        
    >>> print_params_3(x=1,y=2,z=3)    #两个星号得到的是一个字典
    {'x': 1, 'y': 2, 'z': 3}
    >>> def print_params_4(x,y,z=3,*pospar,**keypar):
        print(x,y,z)
        print(pospar)
        print(keypar)
    
        
    >>> print_params_4(1,2,3,4,5,6,foo=1,bar=2)
    1 2 3
    (4, 5, 6)
    {'foo': 1, 'bar': 2}

    结合这些技术,可以将上面存储姓名的栗子再次优化:

    >>> def store(data,*full_names):
        for full_name in full_names:
            names = full_name.split()
            if len(names)==2:names.insert(1,'')
            labels = 'first','middle','last'
            for name,label in zip(names,labels):
                people = lookup(data,label,name)
                if people:
                    people.append(full_name)
                else:
                    data[label][name] = [full_name]
    
                    
    >>> init(me)
    >>> store(me,'Luke Skywalker','Anakin Skywalker')
    >>> lookup(me,'first','Luke')
    ['Luke Skywalker']

    优化之后,store里可以一次存储多个名字。

    分配参数

    >>> def hello(greeting='hello',name='Toney'):
        print('{},{}!'.format(greeting,name))
    
        
    >>> params = {'name':'Mary','greeting':'Greet'}
    >>> hello(**params)
    Greet,Mary!

    通过使用运算符**可将字典中的值分配给关键字参数。

    只有在定义函数(允许可变数量的参数)或调用函数时(拆分字典或序列)使用,星号才能发挥作用。

    综合的栗子:

    >>> def story(**kwds):
        return 'Once upon a time,there was a '
               '{job} called {name}'.format_map(kwds)
    
    >>> def power(x,y,*others):
        if others:
            print('Received redundant parameters:',others)
        return pow(x,y)
            
    >>> def interval(start,stop=None,step=1):
        'Imitates range() for step > 0'
        if stop is None:   #如果没有给参数stop指定值
            start,stop = 0,start    #就调整参数start和stop的值
    
        result = [] 
        i = start                #从start开始往上数
        while i < stop:        #数到stop位置
            result.append(i)     #将当前数的数加到result列表末
            i += step              # i=i+1
        return result
    
    >>> print(story(job='king',name='Gumby'))
    Once upon a time,there was a king called Gumby
    >>> print(story(name='Sir Robin',job='brave knight'))
    Once upon a time,there was a brave knight called Sir Robin
    >>> params = {'job':'language','name':'Python'}            
    >>> print(story(**params))
    Once upon a time,there was a language called Python
    >>> power(2,3)
    8
    >>> power(y=3,x=2)
    8
    >>> params = (5,)*2
    >>> power(*params)
    3125
    >>> power(3,3,'hello,world')
    Received redundant parameters: ('hello,world',)
    27
    >>> interval(10)
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    作用域

    当局部变量中有一个与全局变量命名相同的变量时,可用函数globals来访问全局变量。

    >>> def combine(paramter):
        print(paramter + globals()['paramter'])
    
        
    >>> paramter = 'berry'
    >>> combine('Shrub')
    Shrubberry

    在函数内给变量赋值时,该变量默认是局部变量,但可以指定该变量是全局变量。

    >>> x = 1
    >>> def change():
        global x
        x = x+1
    
        
    >>> change()
    >>> x
    2

    递归

    函数可调用自身,称为递归。可使用递归完成的任何任务都可使用循环来完成,但有时使用递归函数的可读性更高。

    >>> def fac(n):
        result = n   #将result设置为n
        for i in range(1,n):
            result *= i    #依次乘以1到n-1的每个数字
        return result    #返回result
    
    >>> fac(5)
    120
    >>> def fac(n):
        if n == 1:
            return 1
        else:
            return n * fac(n-1)
    
        
    >>> fac(5)
    120

    上面两个函数的功能一致,都是计算数字n的阶乘,貌似在这种场景下,递归的可读性比较高。

  • 相关阅读:
    【转】win8.1下安装ubuntu
    Codeforces 1025G Company Acquisitions (概率期望)
    Codeforces 997D Cycles in Product (点分治、DP计数)
    Codeforces 997E Good Subsegments (线段树)
    Codeforces 1188E Problem from Red Panda (计数)
    Codeforces 1284E New Year and Castle Building (计算几何)
    Codeforces 1322D Reality Show (DP)
    AtCoder AGC043C Giant Graph (图论、SG函数、FWT)
    Codeforces 1305F Kuroni and the Punishment (随机化)
    AtCoder AGC022E Median Replace (字符串、自动机、贪心、计数)
  • 原文地址:https://www.cnblogs.com/suancaipaofan/p/11074693.html
Copyright © 2011-2022 走看看