一 迭代器

  迭代:通过for循环遍历对象的每一个元素的过程;可通过collections中的Iterable类型来判断一个对象是否可迭代;

  迭代器:一种可被遍历的对象,并且能作用于next()函数。从集合的第一个元素开始访问,知道所有元素访问结束。只能往后遍历不能回溯。要实现iter()和next()两个基本方法。如果类成为迭代器,需实现__iter__()和__next__()方法。不可预知序列长度。

  两者区别:

    

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

  • 凡是可作用于next()函数的对象都是迭代器类型;

  • list、dict、str等是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转换成迭代器。

  • Python的for循环本质上就是通过不断调用next()函数实现的。

  • 通过内置的enumerate实现下标循环,同事迭代索引和元素本身。
    for i, value in enumerate(['A', 'B', 'C']):
    ...     print(i, value)

     

      

>>> from collections import Iterable
>>> isinstance('abc',Iterable)
True
>>> isinstance([1,2,3],Iterable)
True
>>> isinstance(123,Iterable)
False

二 生成器;generator;一边循环一边极速出元素的机制。

  使用圆括号编写生成器推导式;

  使用yield关键字。返回一个生成器generator,调用时,每次遇到yield会暂停并保存当前所有运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。

 

>>> def fibonacci(n):
...     a,b,counter = 0,1,0
...     while True:
...             if counter > n:
...                     return
...             yield a
...             print(a)
...             a,b = b,a+b
...             counter += 1
...
>>> fib = fibonacci(10)
>>> print(type(fib))
<class 'generator'>
>>> for i in fib:
...     print(i,end=" ")
...
0 0
1 1
1 1
2 2
3 3
5 5
8 8
13 13
21 21
34 34
55 55

>>> fib.__next__()
0
>>> fib.__next__()
0
1
>>> fib.__next__()
1
1
>>> fib.__next__()
1
2
>>> fib.__next__()
2
3
>>> fib.__next__()
3
5
>>> fib.__next__()
5
8
>>> fib.__next__()
8
13
>>> fib.__next__()
13
21
>>> fib.__next__()
21
34
>>> fib.__next__()
34
55
>>> fib.__next__()
55
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

 

>>> next(fib)
0
>>> next(fib)
1
>>> next(fib)
1
>>> next(fib)
2
>>> next(fib)
3
>>> next(fib)
5
>>> next(fib)
8
>>> next(fib)
13
>>> next(fib)
21

 

>>> from inspect import isgeneratorfunction
>>> isgeneratorfunction(fab)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'fab' is not defined
>>> isgeneratorfunction(fib)
False
>>> isgeneratorfunction(fibonacci)
True

 

>>> from collections import Iterable
>>> isinstance(fib(10),Iterable)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not callable
>>> isinstance(fib,Iterable)
True
>>> isinstance(fibonacci,Iterable)
False
>>> isinstance(fibonacci(10),Iterable)
True

 

斐波那契函数:
def fib(max):
    n,a,b = 0,1,1
    while n < max:
        yield b
        a,b = b,a+b
        n = n+1
    return 'done'

>>> f = fib(6)
>>> f
<generator object fib at 0x0000028909469990>
>>> while True:
...     try:
...             x = next(f)
...             print('f',x)
...     except StopIteration as e:
...             print ('Generator return value:',e.value)
...             break

杨辉三角:
def triangles():
    L = [1]
    while True:
        yield L
        k = [L[i] + L[i+1] for i in range(len(L)-1)]
        L = [1] + k + [1]

 

三 装饰器 decorator;在不修改源代码的情况下,为装饰的对象增加新的功能或者附加限制条件或者帮助输出。开放封闭原则。

  函数名:outer,inner,foo

  函数体:

  返回值:return后的表达式

  函数的内存地址:id(foo)等。

  函数名加括号:对函数进行调用。如foo(),outer(foo),inner()

  函数名被当做参数:outer(foo)中的foo本身是函数,但作为参数传递给了outer函数

  函数名加括号被当做参数:就是先调用函数,再将返回值当做别的函数的参数,outer(foo())

  返回函数名:return inner

  返回函数名加括号:就是先执行函数,再将其返回值作为别的函数的返回值;return inner()

def outer(func):
    def inner():
        print("我是内层函数!")
    return inner

def foo():
    print("我是原始函数!")

outer(foo)
outer(foo())


  装饰器运行机制:被装饰的函数的名字会被当做参数传递给装饰函数。装饰函数执行它自己的内部代码后,会将其返回值赋值给被装饰的函数。

    装饰器的返回值也是一个函数。

  

def outer(func):
    def inner():
        print("认证成功!")
        result = func()
        print("日志添加成功")
        return result
    return inner

@outer    #@outer和@outer()有区别,无括号时,outer仍被执行
def f1():
    print("业务部门1数据接口......")

f1(函数名)作为参数传递给func,也即func=f1,@outer等于outer(f1),传递的是f1的函数体(函数的整个代码结构),而非执行f1的返回值。
返回值inner;之后inner赋值给f1。也即f1函数名之后会指向inner函数。f1=inner
return inner返回的是inner整个函数名,而非inner()被调用后的返回值。

注意:f1.__name__的值变为inner
  

>>> test1.foo.__name__
'inner'

为防止某些依赖函数签名的代码出错,需要把f1的__name__属性赋值到inner中,使用内置的functools.wraps。

def outer(func):
    @functools.wraps(func)
    def inner():
        print("认证成功!")
        result = func()
        print("日志添加成功")
        return result
    return inner

>>> test1.foo.__name__
'foo'
>>>

  

  多个装饰器执行顺序:

  

def outer1(func):
  print ('1')
  def inner(*args,**kwargs):
    print("认证成功!")
    result = func(*args,**kwargs)
    print("日志添加成功")
    return result
  return inner


def outer2(func):
  print ('2')
  def inner(*args,**kwargs):
    print("一条欢迎信息。。。")
    result = func(*args,**kwargs)
    print("一条欢送信息。。。")
    return result
  return inner


@outer1
@outer2
def f1(name,age):
  print("%s 正在连接业务部门1数据接口......"%name)

# 调用方法
f1("jack",18)

 



2
1
认证成功!
一条欢迎信息。。。
jack 正在连接业务部门1数据接口......
一条欢送信息。。。
日志添加成功

 

函数定义阶段:装饰器已经执行;也即未调用f1()时。

函数执行阶段:也即函数调用f1(“jack”,18),执行函数块

@outer1
@outer2
def f1(name,age):
    print("%s 正在连接业务部门1数据接口......"%name)
以上代码相当于outer1(outer2(f1))(),outer1和outer2返回值都是一个函数,所以outer1(outer2(f1))也是一个函数,outer1包含了outer2;f1 = outer1(outer2(f1))。
f1()相当于outer1(outer2(f1))().
执行顺序为:outer2-outer1-outer1-outer2-f1-outer2-outer1

     @property装饰器.可以把类的方法伪装成属性调用的方式。也即Foo.func()的调用方法,变为Foo.func的方式。

      将三个方法定义为对同一个属性的获取、修改和删除。也可以定义只读属性,即getter方法,不定义setter就是只读属性。

  第一种方法:伪装属性

class People:
    
    def __init__(self,name,age):
        self.__name = name
        self.__age = age
        
    @property
    def age(self):    #相当于get方法,result=obj.age
        return self.__age
    
    @age.setter
    def age(self,age):    #相当于set方法,obj.age = 。。。
        if isinstance(age,int):
            self.__age = age
        else:
            raise ValueError
            
    @age.deleter
    def age(self):
        print("删除年龄数据")
        
obj = People('jack',18)
print(obj.age)
obj.age = 19
print('obj.age',obj.age)
del obj.age

18
obj.age 19
删除年龄数据

  第二种方法:builtins内置property()函数。

    

property()函数的参数:

  • 第一个参数是方法名,调用 实例.属性 时自动执行的方法
  • 第二个参数是方法名,调用 实例.属性 = XXX时自动执行的方法
  • 第三个参数是方法名,调用 del 实例.属性 时自动执行的方法
  • 第四个参数是字符串,调用 实例.属性.__doc__时的描述信息。
class People:
    
    def __init__(self,name,age):
        self.__name = name
        self.__age = age
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        if isinstance(age,int):
            self.__age = age
        else:
            raise ValueError
            
    def del_age(self):
        print('删除年龄数据')
        
    age = property(get_age,set_age,del_age,'年龄')
    
obj = People('jack',18)
print(obj.age)
obj.age = 19
print('obj.age',obj.age)
del obj.age


18
obj.age 19
删除年龄数据

 

posted on 2018-08-20 11:02  voldermorter  阅读(109)  评论(0)    收藏  举报