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)

  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/liufei1983/p/7223506.html
Copyright © 2011-2022 走看看