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)

原文地址:https://www.cnblogs.com/liufei1983/p/7223506.html