美文网首页python技术大数据 爬虫Python AI Sql程序员
day21(python高级编程,property属性,生成器,

day21(python高级编程,property属性,生成器,

作者: 冰封心动 | 来源:发表于2017-11-20 20:59 被阅读22次

    属性property

    私有属性添加getter和setter方法

    对于类对象的私有属性,我们不能直接调用,可以添加方法来调用。

    class Person:

        def __init__(self):

            pass

        def setAge(self,age):

            if 0<=age<=100:

                self.__age = age

            else:

                self.__age = 16

                print('输入的年龄不符合')

        def getAge(self):

            return self.__age

    p1 = Person()

    p1.setAge(10)

    print(p1.getAge())

    p1.setAge(200)

    print(p1.getAge())

    结果:

    10

    输入的年龄不符合

    16

    使用property升级getter和setter方法

    class Person:

        def __init__(self):

            pass

        def setAge(self,age):

            if 0<=age<=100:

                self.__age = age

            else:

                self.__age = 16

                print('输入的年龄不符合')

        def getAge(self):

            return self.__age

            age = property(getAge,setAge)

    p1 = Person()

    p1.age = 10

    print(p1.age)

    p1.age = 200

    print(p1.age)

    结果:

    10

    入的年龄不符合

    16

    使用property取代getter和setter方法

    class Person:

        def __init__(self):

            pass

        @property

        def age(self):

            return self.__age

        @age.setter

        def age(self,age):

            if 0<=age<=100:

                self.__age = age

            else:

                self.__age = 16

                print('输入的年龄不符合')

    p1 = Person()

    p1.age = 10

    print(p1.age)

    p1.age = 200

    print(p1.age)

    结果:

    10

    输入的年龄不符合

    16

    生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    创建生成器

    1.把列表生成式的[]改成()

    如:

    [ x*2 for x in range(5)]

    改为:

    ( x*2 for x in range(5))

    如果想要打印,可以通过next()获取生成器的下一个返回值,而且,generator也是可迭代的,所以也可以用循环遍历。

    2.有的比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

    可以用yield

    例如:

    def fib(num):

        a,b = 0,1

        while num>0:

            yield b

            a,b = b,a+b

            num-=1

    f = fib(5)

    print(' ',next(f))

    print(' ',next(f))

    for i in f:

        print(i)

    在上面fib 的例子,我们在循环过程中不断调用 yield ,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用 next() 来获取下一个返回值,而是直接使用 for 循环来迭代。

    但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。

    send:

    执行到yield时,gen函数作用暂时保存,返回i的值;temp接收下次c.send("python"),send发送过来的值,c.next()等价c.send(None)。

    def nums():

        for i in range(10):

            ret = yield i

            if ret == '平方':

                print(i**2)

            elif ret == '立方':

                print(i**3)

    num = nums()

    print(num)

    print(next(num))

    print(next(num))

    print(next(num))

    print(next(num))

    print(next(num))

    print('----------')

    num1 = nums()

    next(num1)

    num1.send('平方')

    num1.send('平方')

    num1.send('平方')

    num1.send('立方')

    num1.send('立方')

    num1.send('立方')

    __next__:作为一个魔法方法,__next__等价于next()

    生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。

    生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

    生成器的特点:

    节约内存

    迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的

    迭代器

    迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

    可迭代对象

    以直接作用于 for 循环的数据类型有以下几种:

    一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;

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

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

    判断是否可以迭代

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

    from collections import Iterable,Iterator

    def f():

        yield 'hello'

    print(isinstance(f(),Iterable))

    print(isinstance(f(),Iterator))

    print(isinstance('abc',Iterable))

    print(isinstance('abc',Iterator))

    迭代器

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

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

    iter()函数

    生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。

    把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数。

    name = 'abc'

    myIter = iter(name)

    print(type(myIter))

    print(isinstance(myIter,Iterator))

    try:

        print(next(myIter))

        print(next(myIter))

        print(next(myIter))

        print(next(myIter))

    except StopIteration as ex:

        print('迭代完了,%s'%ex)

    闭包

    函数引用

    闭包概念:

    在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。

    def test(number):

        '''

        在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,

        那么将这个函数以及用到的一些变量称之为闭包

        '''

        def test_in(number_in):

            print("in test_in 函数, number_in is %d"%number_in)

            return number+number_in

        #其实这里返回的就是闭包的结果

        return test_in

    #给test函数赋值,这个20就是给参数number

    ret = test(20)

    #注意这里的100其实给参数number_in

    print(ret(100))

    #注意这里的200其实给参数number_in

    print(ret(200))

    闭包思考:

    1.闭包似优化了变量,原来需要类对象完成的工作,闭包也可以完成

    2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

    装饰器

    装饰器,功能就是在运行原来功能基础上,加上一些其它功能,比如权限的验证,比如日志的记录等等。不修改原来的代码,进行功能的扩展。

    比如java中的动态代理,python的注解装饰器

    其实python的装饰器,是修改了代码。

    def login(func):

        def inner(a,b):

            user = input('请输入用户名:')

            psd = input('请输入密码:')

            if user == a and psd == b:

                print('Welcome in!')

                func(a,b)

            else:

                print('Passward error!')

        return inner

    @login

    def f1(nowHaveUser,nowHavePsd):

    print('f1')

    def f2():

    print('f2')

    def f3():

    print('f3')

    def f4():

    print('f4')

    f1('haha','123456')

    python解释器就会从上到下解释代码,步骤如下:

    1.def login(func): ==>将login函数加载到内存

    2.@login

    没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。

    从表面上看解释器着实会执行这两句,但是@login这一句代码里却有大文章,@函数名 是python的一种语法糖。

    上例@login内部会执行一下操作:

    执行login函数

    执login1函数 ,并将@login下面的函数作为login函数的参数,即:@login等价于login(f1)所以,内部就会去执行。

    相关文章

      网友评论

        本文标题:day21(python高级编程,property属性,生成器,

        本文链接:https://www.haomeiwen.com/subject/ydlbvxtx.html