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的阶乘,貌似在这种场景下,递归的可读性比较高。

  • 相关阅读:
    明暗文切换(密码输入框)遇到的坑
    iOS11适配tableView顶部空白
    macOS升级到high Sierra后, Cocoapods不能使用解决办法
    Xcode插件失效以后的处理方法
    iOS正确使用const,static,extern
    centos7安装magento随记 这就是个坑,果断放弃
    关于迅雷试用短租日租会员的一些渠道收集
    json中含有Unicode的处理办法 C#
    c#中奖算法的实现
    2016年最新mac下vscode配置golang开发环境支持debug
  • 原文地址:https://www.cnblogs.com/suancaipaofan/p/11074693.html
Copyright © 2011-2022 走看看