python语言基础九


十九、 描述符

    描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

    所谓特殊类型, 要求至少实现以下三个方法中的一个(全部实现也可以)

__get__(self, instance, owner)    定义当描述符的值被取得时的行为
    用于访问属性, 他返回属性的值
__set__(self, instance, value)    定义当描述符的值被改变时的行为
    将在属性分配操作中调用, 不返回任何值
__delete__(self, instance)    定义当描述符的值被删除时的行为
    控制删除操作,不返回任何内容

class MyProperty:
    def __init__(self, f_get=None, f_set=None, f_del=None):
        self.f_get = f_get
        self.f_set = f_set
        self.f_del = f_del

    def __get__(self, instance, owner):
        return self.f_get(instance)

    def __set__(self, instance, value):
        return self.f_set(instance,value)

    def __delete__(self, instance):
        self.f_del(instance)


class C:
    def __init__(self):
        self._x = None

    def get_x(self):
        return self._x

    def set_x(self, value):
        self._x = value

    def del_x(self):
        del self._x

    x = MyProperty(get_x, set_x, del_x)


c = C()
c.x = "xiaoming"
print(c.x)                    xiaoming

del c.x
print(c.x)                    AttributeError: 'C' object has no attribute '_x'

二十、 定制序列

    协议是什么?
    协议与其他编程语言中的接口很相似, 它规定你哪些方法必须要定义。 然而, 在python中的协议就显得不那么正式, 
    事实上, 在python中, 协议更像是一种指南。

    鸭子类型 : 当看到一只鸟走起来像鸭子, 游起来像鸭子, 叫起来也像鸭子, 那么这只鸟就可以被称为鸭子。


    如果你希望定制的容器是不可变的话, 你只需要定义 __len__() 和 __getitem__() 方法。

    如果你希望定制的容器是可变的话, 除了 __len__() 和 __getitem__() 方法, 
    你还需要定义 __setitem__() 和 __delitem__() 两个方法。


        __len__() 方法 : 
                定义当被 len() 调用时的行为(返回容器中元素的个数)

        __getitem__() 方法:
                定义获取容器中指定元素的行为, 相当于 self[key]

        __setitem__() 方法:
                定义设置容器中指定元素的行为,  相当于 self[key] = value

        __delitem__() 方法:
                定义删除容器中指定元素的行为。 相当于 del self[key]


不可变容器 : 

class CountList:

    def __init__(self, *args):
        self.values = [x for x in args]
        self.count = {}.fromkeys(range(len(self.values)), 0)

    def __len__(self):
        print('你正在调用 __len__ 方法啊')
        return len(self.values)

    def __getitem__(self, item):
        print('你正在调用 __getitem__ 方法啊')
        self.count[item] += 1
        return self.values[item]


count_list1 = CountList(1, 3, 5, 7, 9)

count_list2 = CountList(2, 4, 6, 8, 10)
print(count_list1[1])
你正在调用 __getitem__ 方法啊
3

print(count_list2[1])
你正在调用 __getitem__ 方法啊
4

print(count_list1[1] + count_list2[1])
你正在调用 __getitem__ 方法啊
你正在调用 __getitem__ 方法啊
7

print(count_list1.count)
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

print(count_list2.count)
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

count_list1[1] = 5
print(count_list1[1])                TypeError: 'CountList' object does not support item assignment


可变容器 : 

class CountList:

    def __init__(self, *args):
        self.values = [x for x in args]
        self.count = {}.fromkeys(range(len(self.values)), 0)

    def __len__(self):
        print('你正在调用 __len__ 方法啊')
        return len(self.values)

    def __getitem__(self, item):
        print('你正在调用 __getitem__ 方法啊')
        self.count[item] += 1
        return self.values[item]

    def __setitem__(self, key, value):
        print('正在调用 __setitem__ 方法啊')
        self.values[key] = value

    def __delitem__(self, key):
        print('正在调用 __delitem__ 方法啊')
        del self.values[key]


count_list1 = CountList(1, 3, 5, 7, 9)

count_list1[1] = 5
正在调用 __setitem__ 方法啊

print(count_list1[1])
你正在调用 __getitem__ 方法啊
5

del count_list1[1]
正在调用 __delitem__ 方法啊

二十一、迭代器
    
    迭代器的特点 : 
    迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样)。迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),
    它是访问可迭代序列的一种方式,通常其从序列的第一个元素开始访问,直到所有的元素都被访问才结束。 
    [注意]:迭代器只能前进不能后退.
    如果迭代到最后超出范围, 则抛出 :     StopIteration 


        迭代器需要可以被 iter() 和 next() 这两个方法调用    。 【 实现两个 __iter__()  和 __next__() 这两个魔法方法 】

    创建迭代器 : 
        a、 使用内建的工厂函数iter(iterable)可以将可迭代序列转换为迭代器

a = [1, 2, 3, 4]

print(type(a))                        <class 'list'>

print(next(a))                        TypeError: 'list' object is not an iterator

print(type(iter(a)))                <class 'list_iterator'>

print(next(iter(a)))                1

    

        b、 自定义迭代器。
            由于Python中没有“迭代器”这个类,因此具有以下两个特性的类都可以称为“迭代器”类:
              1、有__next__()方法,返回容器的下一个元素或抛出StopIteration异常
               2、有__iter__()方法,返回迭代器本身

class Fibs:

    def __init__(self, n):
        self.a = 0
        self.b = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > self.n:
            raise StopIteration
        return self.a

for each in Fibs(30):
    print(each)

输出 :  1    1    2    3    5    8    13    21


二十二、 生成器
    所谓的协调程序就是可以运行的独立的函数调用, 函数可以暂停或者挂起, 并在需要的时候从程序离开的地方继续或者重新开始。

    对于普通的函数, 一般都是从函数的第一行开始执行, 知道所有的行都执行完毕或者遇到 return 函数才结束。
    一旦函数将控制权交还给调用者, 函数里面的一切都结束了。 

    而 【生成器】 是一个特殊的【函数】, 调用可以在中断、停止。 暂停之后, 他把控制权临时交出来, 
    然后下次调用再接着上次离开的地方继续执行。

    生成器关键字 : 【  yield  】

def my_gen():
    print('生成器执行了。。。')
    yield 1                            【 第一次调用在这里结束】
    yield 2                            【 第二次调用从这里开始】


mg = my_gen()
print('-'*50)
print(next(mg))
print('-'*50)
print(next(mg))

输出 : 

--------------------------------------------------
生成器执行了。。。
1
--------------------------------------------------
2


生成器实现 斐波那契 : 

def fibs():
    a = 0
    b = 1
    while True:
        a, b = b, a + b
        yield a


for each in fibs():
    if each > 30:
        break
    print(each)


输出 :  1    1    2    3    5    8    13    21


 

猜你喜欢

转载自blog.csdn.net/qq_26128879/article/details/82820327
今日推荐