您的位置:首页 > 编程语言 > Python开发

python基础之抽象

2016-01-24 11:12 741 查看
1.创建函数

函数是可以调用的,它执行某种行为并且返回值。一般来说,内建的callable函数用户判断函数是否可以调用:

>>> import math

>>> x = 1

>>> y = math.sqrt(1)

>>> callable(x)

False

>>> callable(y)

False

使用del语句(函数创建语句)创建函数:

del hello(name):

    return 'hello,'+name+'!'

这样就得到了一个名为hello的新函数,它可以返回一个将输入的参数作为名字的问候语。可以像使用内建函数一样使用。

print hello('sun')

2.文档化函数

如果想要给函数写文档,让函数的使用者可以理解的话,可以加入注释(以#开头)。另外一种方式就是直接写上字符串。这类字符串在其他地方可能会非常有用,比如de语句后面即在函数的开头写下字符串,它就会作为函数的一部分进行存储,这称为文档字符串.

del square(x):

    'Calculates the square of the number x.'

    return x*x

内建函数help是非常有用的,在交互解释器中使用它,就可以得到关于函数的详细信息。

3.并非真正函数的函数

python中的函数有时候可能并不返回任何东西,没有return语句或者有return语句但是return语句后面没有跟任何值得函数不返回值:

del test():

    print "hello word"

4.参数魔法

函数的创建很简单,但是参数的用法有时候就变得比较神奇了,还是先从最基础的介绍起。

(1)值从哪里来

一般来说,编写函数只是给程序需要的部分提供服务,能保证函数在被提供给可接受参数的时候正常工作就行,参数错误的话会导致失败。通常,在def语句中函数后面的变量叫做函数的形参(形式参数),而实际调用的时候提供的参数称为实参(实际参数).

(2)我们改变参数吗

记住,在函数内为参数赋予新值不会改变外部任何变量的值:

>>> def change(x):\

... n='123'

...

>>> name = 'aaa'

>>> change(name)

>>> name

'aaa'

结果是显而易见的,当变量n改变的时候,变量name不变。同样,当在函数内部把参数赋值时候,外部的变量不会受到影响。

字符串(以及数字和元素)是不可变的,所以作为参数时候就不用多说了。但是考虑一下可变的数据结构作为参数的时候会发生什么:

>>>def change(n):

    n[0]='e'

>>>names=['a','b','c']

>>>change(names)

>>>names

['e','b','c']

可以看到,在本局中,参数变量,这就是本例子和前面的例子的重要的区别。其实这里会产生变化并不奇怪,下面不用函数调用在做一次:

>>> name=[1,2,3]

>>> n=name

>>> n[0]='123'

>>> name

['123', 2, 3]

这类情况在前面已经出现过很多次了,当两个变量同时引用一个列表的时候,它们的确是同一个变量。如果想要避免这种情况,可以复制出一个列表的副本。当在序列中做切片的时候,总是一个副本。因此,如果你复制了整个列表的切片,就会得到一个副本:

>>> name=[1,2,3]

>>> n=name[:]

>>> n

[1, 2, 3]

>>> name

[1, 2, 3]

>>> name == n

True

>>> name is n

False

现在如果改变了n的值就不在会影响name的值了。

(3)关键字参数和默认值

到现在位置,我们使用的参数都叫位置参数。其实,在传入参数的时候,我们可以提供参数的名字:

del hello(greeting,name):

    print "%s,%s!" % (name,greeting)

>>>hello(greeting='Hello',name='sun')

Hello,sun!

>>>hello(name='sun',greeting='Hello')

Hello,sun!

这样的话,顺序也就没有影响了,但是参数名和值一定要对应。

这类提供参数名的参数叫做关键字参数,它的主要作用在于可以明确每个参数的作用。

关键字参数最厉害的地方在于可以给函数提供默认值:

del hello_2(greeting='Hello',name='sun'):

    print '%s,%s!' % (greeting,name)

>>>hello_2()

>>>'Hello,sun!'

(4)参数收集

有时候需要让用户提供任意数量的参数是很有用的,试试定义下面的函数:

>>> def print_params(*param):\

...     print param

...

>>> print_params('test')

('test',)

可以看到,结果作为元组打印出来了,里面还有个逗号,那么我们试试使用多个参数会发生什么:

>>> print_params(1,2,3)

(1, 2, 3)

参数前面的星号让所有值放置在同一个元组中打印出来了,可以说是将这些值收集起来,然后使用。试试看与普通参数联合使用行不行:

def print_params_2(title,*param):

    print title

    print param

print_params_2('Params:',1,2,3,4,4)

[root@localhost python]# ./test.py

Params:

(1, 2, 3, 4, 4)

没问题,所以星号的意思就是“收集其余的位置参数”。如果不提供任何元素,那么param就是个空元组。

那么如果能不能处理关键字参数呢?

print_params_2('Params:',something=1)

Traceback (most recent call last):

  File "./test.py", line 5, in <module>

    print_params_2('Params:',something=1)

TypeError: print_params_2() got an unexpected keyword argument 'something'

看来不行。所以我们需要另外一个能处理关键字参数的“收集”操作。那么语法应该怎么写呢?我们试试“**”:

def print_params_2(title,**param):

    print title

    print param

print_params_2('Params:',x=1,y='a',z=3)

[root@localhost python]# ./test.py

Params:

{'y': 'a', 'x': 1, 'z': 3}

返回的是字典而不是元组,我们放到一起看看:

#!/usr/bin/python2.6

def print_params_2(x,y,z=3,*pospar,**keypar):

    print x,y,z

    print pospar

    print keypar

print_params_2(1,2,3,5,6,7,foo=1,bar=2)

和我们期望的别无二致:

[root@localhost python]# ./test.py

1 2 3

(5, 6, 7)

{'foo': 1, 'bar': 2}

联合使用这些功能,就可以做很多事情了。

(5)参数收集的逆过程

其实,使用*和**可以执行收集相反的操作,假设有如下函数:

def add(x,y):

    return x+y

比如包含两个需要相加的数组组成的元组:

param=(1,2)

这个过程或多或少有点类似于收集参数的逆过程,不是要收集参数,而是要把它们分配到“另一端”。使用*运算符就简单了——不过是在调用中使用不是在定义时使用:

add(*param)

3

我们可以使用同样的技术来处理字典——使用双星**运算符:

#!/usr/bin/python2.6

def hello(name='hello',greeting='word'):

    print '%s,%s!' % (name,greeting)

param={'name':'sun','greeting':'hello'}

hello(**param)

[root@localhost python]# ./test.py

sun,hello!

(6)练习使用参数

首先,我们定义一些函数:

def story(**kwds):

    return 'there was a %(job)s called %(name)s.' % kwds

def power(x,y,*others):

    if others:

        print 'Recived redundant paramters:'.others

    return pow(x,y)

del interval(start,stop=None,step=1):

    if stop is None:

        start,stop=0,start

    result = []

    i=start

    while(i<stop):

        result.append(i)

        i+=step

    return result

下面我们尝试下第一个函数的不同参数的输出:

print story(job='king',name='sun')

print story(name='Mr zhang',job='doctor')

param={'job':'lanugage','name':'python'}

print story(**param)

del param['job']

print story(job='stroke of genius',**param)

下面是运行结果,和我们想象的一模一样:

there was a king called sun.

there was a doctor called Mr zhang.

there was a lanugage called python.

there was a stroke of genius called python.

然后我们尝试下第二个函数的不同参数的输出:

print power(2,3)

print power(3,2)

print power(y=3,x=2)

param=(5,)*2

power(*param)

print power(3,3,'hello')

结果也和我们预想的一样:

8

9

8

Recived redundant paramters: ('hello',)

27

下面我们尝试第三个函数的不同参数输出:

print interval(10)

print interval(1,5)

print interval(3,12,4)

结果和我们预想的也是一样:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

[1, 2, 3, 4]

[3, 7, 11]

这些函数应该多加练习,加以掌握。

5.作用域

到底什么是变量?你可以把它们当成是值得名字,在执行x=1的赋值语句后,名称x引用到值1.就像用字典一样,键引用值,当然,变量和所对应的值用的是个”不可见的字典“。这类不可变的字典叫做命名空间或者作用域。每个函数的调用都会创建一个新的作用域:

>>> def foo():a=45

...

>>> x=1

>>> foo

<function foo at 0x7f9f980ae938>

>>> x

1

这里的x没有被是因为调用foo()函数的时候创建了一个新的作用域,而函数里的x则是在新的作用域中,并不是原先的命名空间下的x。所以,赋值语句只在内部作用域(局部命名空间)起作用,所以它并不影响外部(全局)作用域中的x。函数内的变量称为局部变量。参数的工作原理类似与局部变量,所以用全局变量的名字作为参数名并没有问题:

>>> x=1

>>> y=2

>>> def output(x):print x

...

>>> output(y)

2

如果需要在函数内部访问全局变量怎么呢?而且只想读取变量的值一般来说是没有问题的:

>>> x=1

>>> def test():print x

...

>>> test()

1

接下来讨论如果需要重绑定全局变量(使变量引用其他新的值)。如果在函数内部赋予一个变量,它就会自动成为全局变量,如果使用全局变量,需要在变量前加global告知python:

6.递归

递归的定义就是函数调用自己本身包括它们自身定义的内容的引用。有用的递归函数包含以下几个部分:

当函数直接返回值得时候有基本的实例(最小可能性问题);
递归实力,包含一个或者多个问题较小部分的递归调用。
(1)两个经典:阶乘和幂

我们可以是用循环计算n的阶乘:

>>> def factorial(n):

...     result=n

...     for i in range(1,n):

...         result *= i

...     return result

...

>>> factorial(5)

120

现在我们来看看递归版本:

>>> def factorial(n):

...     if n==1:return 1

...     return n*factorial(n-1)

...

>>> factorial(5)

120

同样,我们看一下递归版本的幂次方的实现:

>>> def power(x,n):

...     if n==1:return x

...     return x*power(x,n-1)

...

>>> power(2,3)

8

(2)另一个经典:二分查找算法

下面是递归实现的二分查找算法:

def search(sequence,num,lower=0,upper=None):

    if upper==None:

        upper=len(sequence)-1

    middle=(lower+upper)//2

    if num>sequence[middle]:

        return search(sequence,num,middle+1,upper)

    if num<sequence[middle]:

        return search(sequence,num,lower,middle)

    if num==sequence[middle]:

        return middle

a=[11,12,13,14,15,16,17,18,19]

num=11

print search(a,num)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python