zoukankan      html  css  js  c++  java
  • python学习(六) 抽象

    6.1 懒惰即美德

    斐波那契数列:

    >>> fabs = [0, 1]
    >>> for i in range(8):
    fabs.append(fabs[-1] + fabs[-2])

    >>> fabs
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

    6.2 抽象和结构

    6.3 创建函数

    使用def语句创建函数

    >>> def fibs(num):
    result = [0, 1]
    for i in range(num - 2):
    result.append(result[-1] + result[-2])
    return result

    >>> fibs(10)
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

    6.3.1 文档化函数

    6.3.2 并非真正函数的函数

    函数如果没有返回值的时候,默认函数None

    6.4 参数魔法

    6.4.1 值从哪里来

    函数的形参

    6.4.2 我能改变 参数吗

    当在函数内部把参数重绑定的时候,函数外部的变量不受影响。

     字符串(以及数字和元组)是不可变的。即无法修改(只能用新的值覆盖)。

    可是,将可变的数据结构如列表当做参数时会发生什么?

    >>> def change(n):
    n[0] = 'Mr. Gumby'

    >>> names = ['1','2']
    >>> change(names)
    >>> names
    ['Mr. Gumby', '2']

    在上述列子中,列表发生变化,这是和前面的区别:当两个变量引用一个列表的时候,他们确实引用同一个列表。

    如何避免上述情况呢?可以复制一个列表的副本:

    >>> names = ['1','2','3']
    >>> n = names[:]                  // 此时n和names是两个独立的列表,互相之间不影响。
    >>> n == names
    True
    >>> n is names
    False

    (1)为什么要修改参数: 传递的参数是列表的话可以修改值。

    (2)如果是元组,字符串或数字是不可以改变值的。可以采用返回值的方式来改变函数外面的实参的值。或者把实参改成元组。

    6.4.3 关键字参数和默认值

    >>> def hello_l(greeting, name):
    print('%s, %s' % (greeting, name))

    >>> hello_l("hello", 'world')
    hello, world

    >>> def hello_2(greeting = "hello", name = "world"):        // 指定参数的默认值
    print('%s %s' % (greeting, name))

    >>> hello_2(name= "wrold", greeting="hello")                  // 调用的时候可以指定关键字,不怕顺序颠倒
    hello wrold

    6.4.4 收集参数

    让用户提供任意数量的参数。

    >>> def print_pa(*pa):
    print(pa)

    >>> print_pa(1,2,3,4)
    (1, 2, 3, 4)

    /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*

    >>> def print_(title, *pa):               //  星号的意思就是收集剩余的参数
    print(title, pa)

    >>> print_("fdsfsd", "a","b")
    fdsfsd ('a', 'b')                               // 单个星号返回的是元组

    >>> def print_2(**pa):                  // 两个星号表示可以提供关键字参数
    print(pa)

    >>> print_2(x = 1, y = 2, z = 3)
    {'x': 1, 'y': 2, 'z': 3}                         // 双星号返回的是字典

    >>> def print_3(x, y, z=3, *p1, **p2):      // 混合使用各种参数类型
    print(x, y, z)
    print(p1)
    print(p2)

    >>> print_3(1,2,3,5,6,7,foo=1,bar=2)  
    1 2 3
    (5, 6, 7)
    {'foo': 1, 'bar': 2}

    6.4.5 参数收集的逆过程

    >>> def add(x,y):
    return x + y

    >>> params = (1,2)
    >>> add(*params)
    3

    6.4.6 练习使用参数

    有很多提供和接收参数的方法,要勤练习

    总的来说,除去普通的normal args,python中比较特别的函数参数有:关键字参数、默认参数、非关键字可变长参数(元组)、关键字可变长参数(字典),下面将结合例子进行介绍。

    关键字参数:调用时指定参数的名称,且与函数声明时的参数名称一致。使用关键字参数允许函数调用时参数的顺序与声明时不一致,仅根据参数的指定进行赋值。例:

    复制代码
    # 函数定义
    def foo(x, y):
        print 'x is %s' % x
        print 'y is %s' % y
    
    if __name__ == '__main__':
        # 标准调用
        foo(1, 2)
    
        # 关键字调用
        foo(y = 1, x = 2)
    复制代码

    在标准调用中,x和y依次为1和2;在关键字调用中,x和y的值根据名字指定而与顺序无关。

    复制代码
    # 标准调用输出
    x is 1
    y is 2
    
    # 关键字调用输出
    x is 2
    y is 1
    复制代码

    默认参数:在函数声明时,指定形参的默认值,调用时可不传入改参数(使用默认值)。例:

    复制代码
    def tax(cost, rate = 0.17):
        print cost * (1 + rate)
        
    if __name__ == '__main__':
        # rate使用默认值0.17
        tax(1000)
        
        # rate指定为0.05
        tax(1000, 0.05)
    复制代码

    使用默认值时,rate为0.17,结果为1170;在指定参数rate时,rate为0.05,结果为1050。

    # tax(1000)的输出
    1170.0
    
    # tax(1000, 0.05)的输出
    1050.0

    非关键字可变长参数(元组):“非关键字”“可变长”顾名思义是允许在调用时传入多个“非关键字”参数,python会将这些多出来的参数放入一个元组中。例:

    # 定义函数,其中*theRest为非关键字可变长参数
    def tupleVarArgs(arg1, arg2='defaultB', *theRest):
        print 'formal arg 1: ', arg1
        print 'formal arg 2: ', arg2
        for eachXtrArg in theRest:
            print 'another arg: ', eachXtrArg

    我们采用多种调用方式来查看结果,从而理解非关键字可变长参数的使用:

    复制代码
    >>> tupleVarArgs('abc')
    formal arg 1:  abc
    formal arg 2:  defaultB
    >>> tupleVarArgs('abc', 'def') formal arg 1: abc formal arg 2: def
    >>> tupleVarArgs('abc', 'def', 'xyz', 123.4) formal arg 1: abc formal arg 2: def another arg: xyz another arg: 123.4
    复制代码

    关键字可变长参数(字典):“关键字”“可变长”顾名思义是允许在调用时传入多个“关键字”参数,python会将这些多出来的<参数名, 参数值>放入一个字典中。需要注意的是,关键字变量参数应该为函数定义的最后一个参数,带**。例:

    # 定义函数,其中**theRest为关键字可变长参数
    def dictVarArgs(arg1, arg2='defaultB', **theRest):
        print 'formal arg 1: ', arg1
        print 'formal arg 2: ', arg2
        for eachXtrArg in theRest.keys():
            print 'Xtra arg %s: %s' % (eachXtrArg, str(theRest[eachXtrArg]))

    我们采用多种调用方式来查看结果,从而理解关键字可变长参数的使用:

    复制代码
    >>> dictVarArgs('abc')
    formal arg 1:  abc
    formal arg 2:  defaultB
    
    >>> dictVarArgs('abc', 'def')
    formal arg 1:  abc
    formal arg 2:  def
    
    # a=1和b='aha'即为关键字可变参数,他们会被放入theRest字典
    >>> dictVarArgs('abc', 'def', a=1, b='aha')
    formal arg 1:  abc
    formal arg 2:  def
    Xtra arg a: 1
    Xtra arg b: aha
    
    # 全部采用关键字参数,但只有a和b是可变的,会被放入theRest
    >>> dictVarArgs(arg2='def', a=1, b='aha', arg1='put at the last')
    formal arg 1:  put at the last
    formal arg 2:  def
    Xtra arg a: 1
    Xtra arg b: aha
    
    # 这次使用了arg2的默认值
    >>> dictVarArgs('one', a=1, b='aha', name=('yuki', 'lau'))
    formal arg 1:  one
    formal arg 2:  defaultB
    Xtra arg a: 1
    Xtra arg b: aha
    Xtra arg name: ('yuki', 'lau')
    复制代码

    注意

    当非关键字可变长参数和关键字可变长参数出现在同一个函数中时,他们应当遵守如下的顺序约定:

    def newfoo(normal_arg1, normal_arg2, *non-keywords, ** keywords):
        pass

    当然,你也可以直接向函数中传入元组和字典对象,如:

    >>> newfoo(2, 4, *(6, 8), **{'foo': 10, 'bar': 12})

    也可以来个“混搭”,孤立的可变长参数将会被放入对应的tuple或dict中,如:

    >>> newfoo(2, 4, 3, x=4, y=5, *aTuple, **aDict)

    在这个例子中,参数3会被放入aTuple,参数x=4和y=5会被放入aDict

    当然关于Python函数的参数问题还有很多,本文仅仅介绍几种常用的情况,仅做个简单的了解和参考。

    6.5 作用域

     内建的vars()函数可以返回变量和所对应的值的这个字典,这个字典就是命名空间或者作用域

    >>> x = 1
    >>> y = 250
    >>> vars()
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'x': 1, 'y': 250}
    >>> scope = vars()
    >>> scope['x']
    1

    >>> def foo(): x = 42     // 改变的是局部变量,不会改变外部的X

    >>> x = 1
    >>> foo()
    >>> x
    1

    >>> globals()['x']   // 获取全局变量的内建函数
    1

    下面看如何在函数内部重新绑定变量的值:方法是 将其声明为全局变量

    >>> x = 1
    >>> def change_g():
    global x
    x = x + 1


    >>> change_g()
    >>> x
    2

    6.6 递归

    6.6.1 两个经典:阶乘和幂

    >>> def factoria_(n):
    result = n
    for i in range(1, n):
    result *= i
    return result

    >>> factoria_(3)
    6

    改成递归:

    >>> def factorial(n):
    if n == 1:
    return 1;
    else:
    return n * factorial(n-1)

    >>> factorial(4)
    24

    求x的n次幂:

    >>> def power(x, n):
    if n == 0:
    return 1;
    else:
    return x*power(x, n-1)


    >>> power(3, 2)
    9

    6.6.2 另外一个经典:二分法查找

    def search(sequence, number, lower, upper):
    print(lower, upper, seq)
    if lower == upper:
    assert number == sequence[upper]
    return upper
    else:
    middle = (lower + upper) // 2
    if number > sequence[middle]:
    return search(sequence, number, middle + 1, upper)
    else:
    return search(sequence, number, lower, middle)

  • 相关阅读:
    【坑】提答题
    Google Code Jam 2014 Round2
    湖北省队互测Week1
    [xyz模拟题]动态维护树的直径
    音乐会的等待【单调栈】
    51nod1202【DP-树状数组维护】
    51nod1113【矩阵快速幂】
    51nod1255【贪心-栈的应用】
    Lightoj1059【最小生成树】
    SPOJ IAPCR2F 【并查集】
  • 原文地址:https://www.cnblogs.com/liufei1983/p/7223506.html
Copyright © 2011-2022 走看看