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) 返回一个超类的关联实例
    '''


  • 相关阅读:
    Centos 7 zabbix 实战应用
    Centos7 Zabbix添加主机、图形、触发器
    Centos7 Zabbix监控部署
    Centos7 Ntp 时间服务器
    Linux 150命令之查看文件及内容处理命令 cat tac less head tail cut
    Kickstart 安装centos7
    Centos7与Centos6的区别
    Linux 150命令之 文件和目录操作命令 chattr lsattr find
    Linux 发展史与vm安装linux centos 6.9
    Linux介绍
  • 原文地址:https://www.cnblogs.com/fuyouqiang/p/11844650.html
Copyright © 2011-2022 走看看