zoukankan      html  css  js  c++  java
  • python函数

    本章内容

      1、函数

      2、形参、实参

      3、全局与局部变量

      4、默认、位置、关键字参数

      5、函数的递归

      6、函数的嵌套

      7、闭包函数

      8、可变参数

      9、函数的用法

      10、匿名函数lambda

      11、闭包函数

      12、装饰器

      13、高阶函数

      14、列表生成式

      15、生成器

      16、迭代器

      17、python内置函数

      

    函数

        使用函数的三大优点:

        1、代码重用

        2、保持一致性

        3、可扩展性

      return返回值:

        1、当一个函数没有使用return显示定义的返回值时,python解释器会隐式的返回None

        2、return一个值时,返回的是个object

        3、ruturn多个值时,返回的是个tuple,里面的值可以是int、tuple、list、dict

      函数是第一类对象的概念

        1、函数可以被引用

          f1 = func

          f1()    #f1可以被执行

         2、函数可以为参数,

               3、函数的返回值可以是参数

               4、函数可以作为容器类型元素,

                    cmd = {‘n’:func1,'b':func2}

    形参、实参 

          def hello(a,b):       #这里的a,b属于形参

          print 'hello,a,b'

      a= 'python

      b = 'jim'

      hello(a,b)     #这里的的a,b属于实参

      形参:只有在被调用的时候才会分配内存,调用结束后,立即释放内存,值仅在函数内部有效(局部变量)

      实参:有确定的值的参数,所有的数据类型都可以被当做参数传递给函数。可以向函数内传递任意的数据类型。

      python解释器有自己的内存回收机制,a='hello' ,在内存中开辟了一个内存空间,a 变量去引用这个内存的空间,相当于a是这快地址的门牌号,如果解释器看到这个内存空间没有门牌号的话,这个内存空间则会被释放。

    全局与局部变量

      在子程序中定义的变量成为局部变量,在程序的一开始定义的变量成为全局变量。全局变量的作用于整个程序,局部变量的作用于是定义该变量的子程序,当全局变量与局部变量同名时,在定义局部变量的子程序内,局部变量起作用,在其他地方全局变量起作用。

      局部变量:作用域只在当前的函数内部,外部变量默认不能被函数内部修改的,只能引用,如果想在函数内部修改全区变量,必须golbal,但是强烈建议不要这么用,调试不方便。

      上面说的不能修改的的变量类型是int str ,但是函数内部是可以修改列表,字典,集合,实例(class) 

      下列说明,变量为列表类型时不引用golbal就可以被修改。

    names = ['jim','rose','jack']
    
    def chang_name():
        names[0] = '吉姆'
        print(names)
    
    chang_name()
    print(names)
    
    
    运行结果:
    ['吉姆', 'rose', 'jack']
    ['吉姆', 'rose', 'jack']

      函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:>>> a = abs # 变量a指向abs函数 >>> a(-1) # 所以也可以通过a调用abs函数

    默认、位置、关键字参数

      默认参数

    def hello(name='world',age=19):
        print 'my name is %s,and I am %s years old'%(name,age)
    
    hello(name='Mr.python')
    
    ------------------------------
    
    my name is Mr.python,and I am 19 years old
    
    注:age我没有指定,则使用默认的值,19了,这个age就是设定了默认参数

      位置参数

    def hello(name='NB',age=20):       #参数的默认值,调用时不声明,则使用默认参数
        print 'my name is %s,%s years old'%(name,age)
    print hello()
    print hello('mypython',10)                  #这里面name和age对应的位置是不可以变动的。

       关键字参数

    def hello(name,age):
        print 'my name is %s,%s years old'%(name,age)
    
    print hello(age=1000,name='mypython')      #这里可以通过关键字参数来随意的变更位置。
    位置摆放:
    默认参数,必须放在位置参数的后面
    关键字参数,同上

    小练习:
    输入一个数,计算阶乘
    def jiecheng(number):
        for i in range(1,(number+1)):
            sum = i * sum
        return sum    
    
    number = raw_input('please input a number')
    请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数 内部通过条件判断和循环可以实现非常复杂的逻辑。如果没有return语句,函数执行完毕后也会返回结果,只是结果为Nonereturn 只返回一个值,如果有多个结果的话那会已(a,b.......)元组的形式返回

    函数的递归

    尾递归是指,在函数返回的时候,调用自身本身
    利用递归的方式来计算阶乘。 就是函数自己调用自己。
    def jiecheng(number):
        if number ==1:
            return 1
        return number*jiecheng(number-1)  #其原理就是自己乘以自己上一个数的阶乘。
    
    print jiecheng(4)
    小点:当明确的结束条件时,循环到999次时就会报错,不然一直跑下去会吃死内存。

       递归特性:

      1.必须有个明确的结束条件:

      2.每次进入更深一层递归时,问题规模相比上次递归都应该减少

      3.递归的效率不高

      使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出


    这里有个递归的小练习,二分查找法,详见python小练习:
    http://www.cnblogs.com/nopnog/p/6927870.html

    空函数

      如果想定义一个什么事也不做的空函数,可以用pass语句:

      def nop():
         pass
    

      pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

      pass还可以用在其他语句里,比如:

      if age >= 18:
          pass
    

      缺少了pass,代码运行就会有语法错误。

    函数的嵌套

      分为两种:

      1、嵌套定义:

      小丽:

    x = 1
    def func1():
    def func2():
    def func3():
    print (x)
    return func3
    return func2

    func1()

       嵌套的调用最多不要超过三层,不然的话可读性就会变差。

      2、嵌套调用:一个调用另一个

      小丽:

      def my_max2(x,y): #这是比较两个数的大小,现在相比较四个数,咋办
        if x > y:
    return x
    else:
    return y

    def my_max4(a,b,c,d): #划分为最细的情况其实就是两个数的比较
    res1 = my_max2(a,b)
    res2 = my_max2(res1,c)
    res3 = my_max2(res2,d)
    return res3

    print(my_max4(100,2,-1,5))

    闭包函数

      下面由嵌套函数引出闭包函数

    复制代码
    def func1():
    x=1
    def func2():
    print (x)
    return func2

    f=func1()
    f()
    复制代码

      这就是一个闭包函数,没有看出什么可用之处吧,下面做个总结:

        1.首先是func2中x变量的查找,只会在它的上一层查找,在函数外如果有x的赋值,也不会影响func2中的x这就相当于x与func2打包在一起了。

        2.惰性运算,f=func1()后把func2()给了f,但是f没有运行,只有f+()后才会运行

      根据这两个特性没有看到闭包函数的nb之处是吧,继续看小丽。

      利用一会学到的爬虫来说明

    复制代码
    from urllib.request import urlopen

    def page(url):
    def get():
    return urlopen(url).read
    return get


    baidu = page('http://baidu.com/')

    baidu()
    复制代码

      只要一baidu()就会去爬百度的网页了,走到这还是没看出啥来是吧,那再来个python=page('http://python.org')   直接python就会去爬python的网站了,这就相当于个接口,你把python传给别人,别人直接调用就可以,不用关系再去定义python的网址,因为python的网址已经隐藏到函数中了。

      话说我随用随掉不可以吗?

    def get(url):
    return urlopen(url).read
    get('http://www.baidu.com')

      其实直接get('http://www.baidu.com') 与baidu() 没啥区别,区别在于闭包函数已经把变量(url=www.baidu.com)存在函数中了,什么时候用什么时候加()调用就可以了。

     

    可变参数

      *收集的是位置参数,不能收集关键参数,收集到的是元组---此方法名为可变参数。

      可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple

      ** 收集的是关键字参数,收集到的是字典 ---又名关键字参数

      关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

    def hello(name = 'world',*para,**par):
        print 'my name is %s'%(name)
        print para
        print par
    
    hello('Mr.python',1,2,3,4,5,6,7,8,haha='haha',nihao='nihao')
    
    结果:
    
    my name is Mr.python
    (1, 2, 3, 4, 5, 6, 7, 8)
    {'nihao': 'nihao', 'haha': 'haha'}
    [Finished in 0.1s]

      小用法:向函数中的*args传递列表。

    def foo(x,y,*args):  
    print (x)
    print(y)
    print(args)

    l = ['a','b']
    foo(1,2,*l) #*l的用法,把列表分成单个的项然后传递给函数,相当于*['a','b'] = *args, 然后把*去掉,args = ['a','b'] 然后传递到函数中,函数再已('a','b')的形式输出

      

    函数的用法

      1.函数可以当作参数来使用:

    def operate(fn,name):
        return fn(name)
    def sayhello(name):
        return 'hello %s!'%(name)
    def hehe(name):
        return 'hehe %s !'%(name)
    
    print operate(sayhello,'MR.python')
    print operate(hehe,'mr.python')
    
    
    -----------------------------------
    hello MR.python!
    hehe mr.python !
    [Finished in 0.1s]
     

    2.结合sorted来使用:

    arr2 = [('192.168.1.1',2),('192.168.1.2',1),('192.168.1.3',3)]
    def sort_fn(arg):
        return arg[1]       #取的是列表内元素,各个元组的下表是1的关键字
    
    print sorted(arr2,key=sort_fn)
    
    arr3 = [{'name':'python','age':10},{'name':'C++','age':8},{'name':'java','age':9}]
    
    def sort_dict(arg):
        return arg['age']   #取的是列表内元素,各个字典的下表age的关键字的值
    
    print sorted(arr3,key=sort_dict)
    
    ---------------------------------------------------------------------------
    
    [('192.168.1.2', 1), ('192.168.1.1', 2), ('192.168.1.3', 3)]
    [{'age': 8, 'name': 'C++'}, {'age': 9, 'name': 'java'}, {'age': 10, 'name': 'python'}]
    
     
    
    注释的地方容易理解吗?感觉只能靠记

     下面通过写个简单的sorted,来做个练习。

      

    实现了list的排序,但是列表和字典的怎么实现呢?

      

    这里面设计到函数的引用,请查看过程。

     匿名函数lambda

      下面引入lambda,lambda 只能实现简单的函数

    def qu_key1(arr):
        return arr['age']

    翻译为lambda 就是 lambda arr:arr['age']

    下面用lambda来替代。

      

    下面在利用lambda实现list也可以比较的功能。

      

    利用函数的默认值,key=lambda x:x 来实现对list的比较,实际上就是没有是通过lambda什么都没有操作的。

    贴上代码:

    def my_sort(arr,key=lambda x:x):
        length = len(arr)
        for i in range(length-1):
            for j in range(length-1-i):
                if key(arr[j]) > key(arr[j+1]):
                    arr[j],arr[j+1] = arr[j+1],arr[j]
        return arr
    
    # def qu_key(arr):
    #     return arr[1]
    
    # def qu_key1(arr):
    #     return arr['age']
    
    a = [6,5,4,3,3,2,1]
    print my_sort(a)
    
    arr2 = [('192.168.1.1',2),('192.168.1.2',1),('192.168.1.3',3)]
    print my_sort(arr2,key=lambda x:x[1])
    arr3 = [{'name':'python','age':10},{'name':'C++','age':8},{'name':'java','age':9}]
    print sorted(arr3,key=lambda x:x['age'])
    
    --------------------------------------------------------------------------
    
    [1, 2, 3, 3, 4, 5, 6]
    [('192.168.1.2', 1), ('192.168.1.1', 2), ('192.168.1.3', 3)]
    [{'age': 8, 'name': 'C++'}, {'age': 9, 'name': 'java'}, {'age': 10, 'name': 'python'}]


    看到上面的代码是不是有疑惑,那lambda是什么呢?先来个简单的例子,首先得明确一点lambda其实就是个函数:
     

    g= lambda x:x+1
    
    print g(1)
    
    >>2
    
    当然,你也可以这样使用:
    
    lambda x:x+1(1)
    
    >>>2

      可以这样认为,lambda作为一个表达式,定义了一个匿名函数,上例的代码x为入口参数,x+1为函数体,用函数来表示为:

    1 def g(x):
    2 return x+1

      lambda 也可以多参数:

      lambda x,y:x+y

      非常容易理解,在这里lambda简化了函数定义的书写形式。是代码更为简洁,但是使用函数的定义方式更为直观,易理解。

    lambda if 判断运算:

    for i in map(lambda x:x*2 if x>5 else x-1 [1,2,3,4,5,6,7,8,9]):

    注:lambda支持到最复杂的运算是三元运算,更复杂的运算不支持。

    装饰器 

      装饰器:本质上是个函数,(装饰其他的函数)就是为了其他函数添加附加的功能。

      1.最好不要修改源代码,有课能用的地方很多,错一点,会有连带反应。

      2.不要更改调用的方式。

      这不能动那不能动,想添加功能咋办?用装饰器喽。

      原始装饰器:

    标准格式:

    def zhuangsq(fn):           
        def new_hello(name):
            print 'good morning ' + name
            return 'haha ' + fn(name)
        return new_hello
    
     #装饰起代码必须在上面,用@zhuangsq替代了上面的 hello = zhuangsq(hello)
    @zhuangsq         
    def hello(name):
        return 'nice to meet you ' + name
    
    print hello('MR.python')


      哈哈,到了这里有一个参数或者不传递参数的装饰器都已经搞定了,但是如果有多个参数呢,再如果加上
    加上装饰器后再调用hello() 其实就是调用的new_hello()这个函数了,
    位置参数呢,哪有如何接受呢?别怕在new_hello()中用*args,**kwargs接受,但是接受了是个元组和字典啊,如何才能让内部的fn函数接受呢?哈哈,还是用*args,**kwargs,这里就会他元组和字典里的这些想

    部独立的分开。

    效果如下:

      new_hello(*arge,**kwargs):

          print 'good morning' + name

          return 'haha' + fn(*args,**kwargs)

        如果在hello()函数中有return呢?现在我们知道装饰后其实就是运行的new_hello,这时候咋办new_hello中也需要return,那return什么?return fn这个函数。其实也就是hello()

      装饰器之return 小例:

     1 user,passwd = 'alex','12345'
     2 
     3 def auth(func):
     4     def wrapper(*args,**kwargs):
     5         username = input('username:').strip()
     6         password = input('password:').strip()
     7 
     8         if user == username and passwd == password:
     9             print('33[32;1m User has passed authentication 33[0m')
    10             res = func(*args,**kwargs)
    11             return  res
    12         else:
    13             print('33[31;1m User does not exit! 33[0m')
    14 
    15     return wrapper
    16 
    17 
    18 @auth
    19 def login():
    20     print('This is login,I will login')
    21     return 'I love this web!!'
    22 
    23 @auth
    24 def bbs():
    25     print('This is bbs ')
    26 
    27 def index():
    28     print('this is index')
    29 
    30 print(login())      #函数return有返回值的话需要print,把结果打印出来
    31 bbs()
    32 index()
    33 
    34 
    35 
    36 运行结果:
    37 username:alex
    38 password:12345
    39  User has passed authentication 
    40 This is login,I will login
    41 I love this web!!
    42 username:alex
    43 password:12345
    44  User has passed authentication 
    45 This is bbs 
    46 this is index
    return 使用

       升级一下,如果使用装饰器,一部分页面需要本地验证,另一方面需要另外一套系统来做验证,那又能怎么办呢? --->对装饰器再添加一层!

     1 def auth(auth_type):
     2     print('auth func is ',auth_type)
     3     def outer_wrapper(func):
     4         def wrapper(*args, **kwargs):
     5             username = input('username:').strip()
     6             password = input('password:').strip()
     7 
     8             if user == username and passwd == password:
     9                 print('33[32;1m User has passed authentication 33[0m')
    10                 res = func(*args, **kwargs)
    11                 return res
    12             else:
    13                 print('33[31;1m User does not exit! 33[0m')
    14 
    15         return wrapper
    16     return  outer_wrapper
    17 
    18 @auth(auth_type='local')
    19 def login():
    20     print('This is login,I will login')
    21     return 'I love this web!!'
    22 
    23 @auth(auth_type='ldap')
    24 def bbs():
    25     print('This is bbs ')
    26 
    27 def index():
    28     print('this is index')
    29 
    30 print(login())
    31 bbs()
    32 index()
    33 
    34 
    35 
    36 运行结果:
    37 
    38 auth func is  local
    39 auth func is  ldap
    40 username:alex
    41 password:12345
    42  User has passed authentication 
    43 This is login,I will login
    44 I love this web!!
    45 username:alex
    46 password:12345
    47  User has passed authentication 
    48 This is bbs 
    49 this is index
    装饰器中添加参数

     高阶函数

      

      注:其是调用ads函数的内存地址。

        满足一下两个条件即可称之为高阶函数:

        1、把函数的内存地址当做参数传给另外一个函数

        2、一个函数把另外一个函数当做返回值返回。

      高阶函数  +  嵌套函数  =  装饰器

    列表生成式

      [ i*2  for i in range(10) ] 

      转换为普通的代码:

      a = []

      for i in range(10):

       a.append(i*2)

      列表生成式的作用,就是使代码更简洁

      先来个小练习a= [1,2,3,4,5,6,7,8,9] 里面的每个数值都加1  

      1.可以利用lambda:

    map(lambda x:x+1,a)

      2.第二种方法:根据每个数的索引来对每个数+1运算

    注意:这时候不能用列表的index来去索引,因为如果有重复的,它只会取第一个,需要用enumerate

    复制代码
    a= [1,2,3,4,5,6,7,8,9]

    for index,i in enumerate(a):
    a[index] = i+1

    print(a)
    复制代码

       3.列表生成式

    a= [1,2,3,4,5,6,7,8,9]
    b = [i+1 for i in a]

      列表生成式最大的运算也是三目运算 

    a= [1,2,3,4,5,6,7,8,9]
    b = [i*i if i >5 else i for i in a] 

    生成器

      通过列表生成式,我们可以直接创建一个列表,但是,受到内存的限制,列表容量肯定是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面的几个元素,那后面绝大数元素占用的空间就拜拜浪费了。

      所以,如果列表元素可以按照某种算法来推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,

      在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个 

    >>> L = [x * x for x in range(10)] 
    >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 
    >>> g = (x * x for x in range(10)) 
    >>> g <generator object <genexpr> at 0x104feab40>

      创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?如果要一个一个打印出来,可以通过generator的next()方法:

    >>> g.next() 0
    >>> g.next() 1 
    >>> g.next() 4 
    >>> g.next() 9 
    >>> g.next() 16 
    >>> g.next() 25 
    >>> g.next() 36 
    >>> g.next() 49 
    >>> g.next() 64 
    >>> g.next() 81 
    >>> g.next() 
    Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
       next(a)python2中的方法
      a.__next__()python3中的方法
      

       我们讲过,generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。当然,上面这种不断调用next()方法实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

    >>> g = (x * x for x in range(10)) 
    >>> for n in g: 
        ... print n ... 
    
    0 1 4 9 16 25 36 49 64 81        

      所以,我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。这里我们看到,这个迭代器只支持到三元运算,其实他本事不止这些,复杂的形式用函数的方式来实现:

      

      斐波那契数

    def fib(max):
        n,a,b=0,0,1
        while n < max:
            print (b)
            a,b= b,a+b
            n +=1
        return 'done'
    
    fib(10)

      这里把print (b) 改为yeild就变为生成器了,可以利用for循环去调用,每想调用一个就调用一个,如果想执行其他的,期间也可以执行,这就是他的作用,现用现执行,不浪费内存,这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

      现改之为生成器样式

    def fib(num):
        n,a,b = 0,0,1
        while n < num:
            yield b
            a,b = b,a+b
            n+=1
        return 'done'
    
    d = fib(10)
    
    while True:
        try:
            print(d.__next__())
        except StopIteration as e:
            print(e)
            print('Generator return value',e.value)
            break

      这里为什么要用try去捕获异常呢,因为使用next方法,执行到最后会抛出一个 StopIteration 的异常

      利用yield来模拟单线程并发:

     1 import time
     2 
     3 def consumer(name):
     4     print("%s 准备来吃包子了"%name)
     5 
     6     while True:
     7         baozi = yield
     8 
     9         print('包子[%s]来了,被[%s]吃了'%(baozi,name))
    10 
    11 def producer(name):
    12     c = consumer('A')
    13     c2 = consumer('B')
    14     c.__next__()
    15     c2.__next__()
    16     print('lz开吃吃包子了')
    17     for i in range(10):
    18         time.sleep(1)
    19         print('做一个包子,分成两半')
    20         c.send(i)    #传递给yield一个值,
    21         c2.send(i)
    22 
    23 
    24 producer('Alex')
    25 
    26 执行结果:
    27 会每次两个客户同事输出,效果像并发
    28 
    29 A 准备来吃包子了
    30 B 准备来吃包子了
    31 lz开吃吃包子了
    32 做一个包子,分成两半
    33 包子[0]来了,被[A]吃了
    34 包子[0]来了,被[B]吃了
    35 做一个包子,分成两半
    36 包子[1]来了,被[A]吃了
    37 包子[1]来了,被[B]吃了
    38 做一个包子,分成两半
    39 包子[2]来了,被[A]吃了
    40 包子[2]来了,被[B]吃了
    41 做一个包子,分成两半
    42 包子[3]来了,被[A]吃了
    43 包子[3]来了,被[B]吃了
    44 做一个包子,分成两半
    45 包子[4]来了,被[A]吃了
    46 包子[4]来了,被[B]吃了
    47 做一个包子,分成两半
    48 包子[5]来了,被[A]吃了
    49 包子[5]来了,被[B]吃了
    50 做一个包子,分成两半
    51 包子[6]来了,被[A]吃了
    52 包子[6]来了,被[B]吃了
    53 做一个包子,分成两半
    54 包子[7]来了,被[A]吃了
    55 包子[7]来了,被[B]吃了
    56 做一个包子,分成两半
    57 包子[8]来了,被[A]吃了
    58 包子[8]来了,被[B]吃了
    59 做一个包子,分成两半
    60 包子[9]来了,被[A]吃了
    61 包子[9]来了,被[B]吃了
    View Code

    迭代器

      我们已经知道,可以直接作用于for循环的数据类型有以下几种:

      一类是集合数据类型,如listtupledictsetstr等;

      一类是generator,包括生成器和带yield的generator function。

      这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

      可以使用isinstance()判断一个对象是否是Iterable对象:

    >>> isinstance([], Iterable)
    True
    >>> isinstance({}, Iterable)
    True
    >>> isinstance('abc', Iterable)
    True
    >>> isinstance((x for x in range(10)), Iterable)
    True
    >>> isinstance(100, Iterable)
    False

      而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

      *可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

      可以使用isinstance()判断一个对象是否是Iterator对象:

    >>> from collections import Iterator
    >>> isinstance((x for x in range(10)), Iterator)
    True
    >>> isinstance([], Iterator)
    False
    >>> isinstance({}, Iterator)
    False
    >>> isinstance('abc', Iterator)
    False

      生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

      把listdictstrIterable变成Iterator可以使用iter()函数:

    >>> isinstance(iter([]), Iterator)
    True
    >>> isinstance(iter('abc'), Iterator)
    True

      你可能会问,为什么listdictstr等数据类型不是Iterator

      这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

      Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

      在python3中 range 就是使用的迭代器封装的,而python2中不是,xrange是它的迭代方法,

      

    小结

      凡是可作用于for循环的对象都是Iterable类型;

      凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

      集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

      Python的for循环本质上就是通过不断调用next()函数实现的,例如:

    1
    2
    for in [12345]:
        pass

    实际上完全等价于:

    # 首先获得Iterator对象:
    it = iter([1, 2, 3, 4, 5])
    # 循环:
    while True:
        try:
            # 获得下一个值:
            x = next(it)
        except StopIteration:
            # 遇到StopIteration就退出循环
            break

    python 内置函数

      内置函数  
    abs() divmod() input() open() staticmethod()
    all() enumerate() int() ord() str()
    any() eval() isinstance() pow() sum()
    basestring() execfile() issubclass() print() super()
    bin() file() iter() property() tuple()
    bool() filter() len() range() type()
    bytearray() float() list() raw_input() unichr()
    callable() format() locals() reduce() unicode()
    chr() frozenset() long() reload() vars()
    classmethod() getattr() map() repr() xrange()
    cmp() globals() max() reversed() zip()
    compile() hasattr() memoryview() round() __import__()
    complex() hash() min() set()  
    delattr() help() next() setattr()  
    dict() hex() object() slice()  
    dir() id() oct() sorted() exec 内置表达式

    返回python目录

     

  • 相关阅读:
    一个很实用的css3兼容工具很多属性可以兼容到IE6
    html5 canvas 填充渐变形状
    找到任何形状的中心-总结篇
    html canvas非正方旋转和缩放...写的大多是正方的有人表示一直看正方的看厌了
    把jQuery的类、插件封装成seajs的模块的方法
    那些年实用但被我忘掉javascript属性.onresize
    总有一些实用javascript的元素被人遗忘在角落-slice
    jquery(入门篇)无缝滚动
    html5 canvas旋转+缩放
    今天看到这篇新闻之后,决定休息一下咯
  • 原文地址:https://www.cnblogs.com/nopnog/p/6936568.html
Copyright © 2011-2022 走看看