zoukankan      html  css  js  c++  java
  • python-09 魔法方法、特性和迭代器

    # 第九章 魔法方法、特性和迭代器
    # 9.1 如果你使用的不是Python 3

    # 9.2 构造函数
    # __init__ 初始化
    # __del__ 析构函数 在对象被销毁之前调用

    # 9.2.1 重写普通方法和特殊的构造函数
    class Bird:
    def __init__(self):
    self.hungry = True
    def eat(self):
    if self.hungry:
    print('Aaaah.....')
    self.hungry = False
    else:
    print('No, thanks')

    class SongBird(Bird):
    def __init__(self):
    #Bird.__init__(self) # 9.2.2 应该加的
    super().__init__()
    self.sound = 'Squawk!'
    def sing(self):
    print(self.sound)
    sb = SongBird()
    print(sb.sing())
    print(sb.eat()) #'SongBird' object has no attribute 'hungry'
    # 9.2.2 调用未关联的超类构造函数 #Bird.__init__(self)

    # 9.2.3 使用函数 super # super().__init__()

    # 9.3 元素访问
    # 9.3.1 基本的序列和映射协议

    def check_index(key):
    '''
    指定的键是否是可接受的索引?

    键必须是非负整数, 才是可接受的。如果不是整数,将引发TypeError 异常; 如果是负数,将引发IndexError异常(因为这个序列的长度是无穷的)

    '''
    if not isinstance(key, int):
    raise TypeError
    if key < 0:
    raise IndexError

    class ArithmeticSequence:
    def __init__(self, start = 0, step = 1):
    '''
    初始化这个算术序列

    :param start: 序列中的第一个值
    :param step: 两个相邻值得差
    '''
    self.start = start
    self.step = step
    self.changed = {}
    def __getitem__(self, key):
    '''
    从算术序列中获取一个元素
    '''
    check_index(key)
    try:
    return self.changed[key]
    except KeyError:
    return self.start + key * self.step

    def __setitem__(self, key, value):
    '''
    修改算术序列中的元素
    '''

    check_index(key)

    self.changed[key] = value

    a = ArithmeticSequence(5, 6)
    print(a[5])

    # 9.3.2 从list、dict 和 str 派生

    class CounterList(list):
    def __init__(self, *args):
    super().__init__(*args)
    self.counter = 0
    def __getitem__(self, index):
    self.counter += 1
    return super(CounterList, self).__getitem__(index)

    cl = CounterList(range(10))
    print(cl)
    print(cl.counter)
    cl[4] + cl[2]
    print(cl.counter)

    # 9.4 其他魔法方法 # 如果需要学习更多请参考 Python Reference Manual”的Special method names一节。

    # 9.5 特性 通过存取方法定义的属性通常称为特性
    '''
    class Rectangle:
    def __init__(self):
    self.width = 0
    self.height = 0
    def set_size(self, size):
    self.width, self.height = size
    def get_size(self):
    return self.width, self.height

    r = Rectangle()
    r.width = 10
    r.height = 5
    print(r.get_size())
    r.set_size((150, 100))
    print(r.width)
    '''
    # 9.5.1 函数property
    class Rectangle:
    def __init__(self):
    self.width = 0
    self.height = 0
    def set_size(self, size):
    self.width, self.height = size
    def get_size(self):
    return self.width, self.height
    size = property(get_size, set_size)

    r = Rectangle()
    r.width = 10
    r.height = 5
    print(r.size)
    r.size = 150, 100
    print(r.width)
    '''
    调用函数property时,还可不指定参数、指定一个参数、指定三个参数或指定四个参数。
    如果没有指定任何参数,创建的特性将既不可读也不可写。
    果只指定一个参数(获取方法),创建的特性将是只读的。
    第三个参数是可选的,指定用于删除属性的方法(这个方法不接受任何参数)。
    第四个参数也是可选的,指定一个文档字符串。这些参数分别名为fget、fset、fdel和doc。
    如果你要创建一个只可写且带文档字符串的特性,可使用它们作为关键字参数来实现。
    Descriptor HowTo Guide(https://docs.python.org/3/howto/descriptor.html
    '''
    # 9.5.2 静态方法和类方法
    #静态方法和类方法是这样创建的:将它们分别包装在staticmethod和classmethod类的对象中。
    # 静态方法的定义中没有参数self,可直接通过类来调用。类
    # 方法的定义中包含类似于self的参数,通常被命名为cls。对于类方法,也可通过对象直接调用,但参数cls将自动关联到类。
    '''
    class MyClass:
    def smeth():
    print('This is a static method')
    smeth = staticmethod(smeth)

    def cmeth(cls):
    print('This is a class method of', cls)
    cmeth = classmethod(cmeth)
    '''
    # 装饰器 指定了多个装饰器时,应用的顺序与列出的顺序相反)
    class MyClass:
    @staticmethod
    def smeth():
    print('This is a static method')
    @classmethod
    def cmeth(cls):
    print('This is a class method of', cls)

    print(MyClass.smeth())
    print(MyClass.cmeth())

    # * 9.5.3 __getattr__、__setattr__等方法
    '''
    1、__getattribute__(self, name):在属性被访问时自动调用(只适用于新式类)。
    2、__getattr__(self, name):在属性被访问而对象没有这样的属性时自动调用。
    3、__setattr__(self, name, value):试图给属性赋值时自动调用。
    4、__delattr__(self, name):试图删除属性时自动调用。
    '''


    # 9.6 迭代器 __iter__
    # 9.6.1 迭代器协议 __iter__返回一个迭代器,它是包含方法__next__的对象 next(it)与 it.__next__()等价
    class Fibs:
    def __init__(self):
    self.a = 0
    self.b = 1
    def __next__(self):
    self.a, self.b = self.b, self.a + self.b
    return self.a
    def __iter__(self):
    return self

    fibs = Fibs()
    for f in fibs:
    print(f)
    if f > 1000:
    break

    # 9.6.2 从迭代器创建序列
    class TestIterator:
    value = 0
    def __next__(self):
    self.value += 1
    if self.value > 10:
    raise StopIteration
    return self.value
    def __iter__(self):
    return self
    ti = TestIterator()
    print(list(ti))

    # 9.7 生成器 包含yield语句的函数都被称为生成器
    # 9.7.1 创建生成器
    '''
    def flatten(nested):
    for sublist in nested:
    for element in sublist:
    yield element
    nested = [[1, 2], [3, 4], [5]]

    print(list(flatten(nested)))
    print(flatten(nested))
    '''
    # 9.7.2 * 递归式生成器
    '''
    def flatten(nested):
    try:
    # 不迭代类似于字符串的对象
    try:
    nested + ''
    except TypeError:
    pass
    else:
    raise TypeError
    for sublist in nested:
    for element in flatten(sublist):
    yield element
    except TypeError:
    yield nested
    print(list(flatten([[[1], 2], 3, 'as', 4, [5, [6, 7, 'sd']], 8])))
    '''
    # 9.7.3 通用生成器 生成器由两个单独的部分组成:生成器的函数和生成器的迭代器。
    # 生成器的函数是由def语句定义的,其中包含yield。生成器的迭代器是这个函数返回的结果

    # 9.7.4 生成器的方法
    #外部世界:外部世界可访问生成器的方法send,这个方法类似于next,但接受一个参数(要发送的“消息”,可以是任何对象)。
    #生成器:在挂起的生成器内部,yield可能用作表达式而不是语句。换而言之,当生成器重新运行时,
    # yield返回一个值——通过send从外部世界发送的值。如果使用的是next,yield将返回None。
    '''
    方法throw:用于在生成器中(yield表达式处)引发异常,调用时可提供一个异常类型、一个可选值和一个traceback对象。
    方法close:用于停止生成器,调用时无需提供任何参数。
    '''

    # 9.7.5 模拟生成器
    def flatten(nested):
    result = []
    try:
    # 不迭代类似于字符串的对象
    try:
    nested + ''
    except TypeError:
    pass
    else:
    raise TypeError
    for sublist in nested:
    for element in flatten(sublist):
    result.append(element)
    except TypeError:
    result.append(nested)
    return result
    print(flatten([[[1], 2], 3, 'as', 4, [5, [6, 7, 'sd']], 8]))

    # 9.8 八皇后问题



    '''
    序列和映射基本上是元素(item)的集合,要实现它们的基本行为(协议),不可变对象需要实现2个方法,而可变对象需要实现4个。
    1、__len__(self):这个方法应返回集合包含的项数,对序列来说为元素个数,对映射来说为键-值对数。如果__len__返回零
    (且没有实现覆盖这种行为的__nonzero__),对象在布尔上下文中将被视为假(就像空的列表、元组、字符串和字典一样)。
    2、__getitem__(self, key):这个方法应返回与指定键相关联的值。对序列来说,键应该是0~n-1的整数(也可以是负数,这将在后面说明),
    其中n为序列的长度。对映射来说,键可以是任何类型。
    3、__setitem__(self, key, value):这个方法应以与键相关联的方式存储值,以便以后能够使用__getitem__来获取。当然,仅当对象可变时才需要实现这个方法。
    4、__delitem__(self, key):这个方法在对对象的组成部分使用__del__语句时被调用,应删除与key相关联的值。同样,仅当对象可变(且允许其项被删除)时,
    才需要实现这个方法。

     对于序列,如果键为负整数,应从末尾往前数。换而言之,x[-n]应与x[len(x)-n]等效。
     如果键的类型不合适(如对序列使用字符串键),可能引发TypeError异常。
     对于序列,如果索引的类型是正确的,但不在允许的范围内,应引发IndexError异常。
    9.9 小结
     新式类和旧式类:Python类的工作方式在不断变化。较新的Python 2版本有两种类,其中旧式类正在快速退出舞台。
    新式类是Python 2.2引入的,提供了一些额外的功能,如支持函数super和property,而旧式类不支持。要创建新式类,必须直接或间接地继承object或设置__metaclass__。
     魔法方法:Python中有很多特殊方法,其名称以两个下划线开头和结尾。这些方法的功能各不相同,但大都由Python在特定情况下自动调用。例如__init__是在对象创建后调用的。
     构造函数:很多面向对象语言中都有构造函数,对于你自己编写的每个类,都可能需要为它实现一个构造函数。构造函数名为__init__,在对象创建后被自动调用。
     重写:类可重写其超类中定义的方法(以及其他任何属性),为此只需实现这些方法即可。要调用被重写的版本,可直接通过超类调用未关联版本(旧式类),也可使用函数super来调用(新式类)。
     序列和映射:要创建自定义的序列或映射,必须实现序列和映射协议指定的所有方法,其中包括__getitem__和__setitem__等魔法方法。通过从list(或UserList)和dict(或UserDict)派生,可减少很多工作量。
     迭代器:简单地说,迭代器是包含方法__next__的对象,可用于迭代一组值。没有更多的值可供迭代时,方法__next__应引发StopIteration异常。可迭代对象包含方法__iter__,
    它返回一个像序列一样可用于for循环中的迭代器。通常,迭代器也是可迭代的,即包含返回迭代器本身的方法__iter__。
     生成器:生成器的函数是包含关键字yield的函数,它在被调用时返回一个生成器,即一种特殊的迭代器。要与活动的生成器交互,可使用方法send、throw和close。
     八皇后问题:八皇后问题是个著名的计算机科学问题,使用生成器可轻松地解决它。这个问题要求在棋盘上放置8个皇后,并确保任何两个皇后都不能相互攻击。

    iter(obj) 从可迭代对象创建一个迭代器
    next(it) 让迭代器前进一步并返回下一个元素
    property(fget, fset, fdel, doc) 返回一个特性;所有参数都是可选的
    super(class, obj) 返回一个超类的关联实例
    '''


  • 相关阅读:
    团队项目冲刺第6天
    冲刺阶段第五天
    冲刺阶段前四天总结
    "博客园"用户体验分析
    测试计划
    scrum敏捷开发
    团队开发_软件项目风险管理
    sprint计划会议
    svn 之 svn的两种开发模式
    redis 之 搭建真实集群
  • 原文地址:https://www.cnblogs.com/fuyouqiang/p/11844650.html
Copyright © 2011-2022 走看看