zoukankan      html  css  js  c++  java
  • python 面向对象九 定制类

    一、定制类,实质就是我们自己重写特殊函数

    看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。

    __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数。

    除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类。

    二、__len__()方法

    >>> class MyStr(str):
          def __init__(self, s):
              self.__s = s
          def __len__(self):
              return len(self.__s) - 1
    
        
    >>> s = MyStr('abc')
    >>> len(s)
    2

    三、__str__()方法

    >>> class Student(object):
    ...     def __init__(self, name):
    ...         self.name = name
    ...     def __str__(self):
    ...         return 'Student object (name: %s)' % self.name
    ...
    >>> print(Student('Michael'))
    Student object (name: Michael)

    四、__repr__()方法

    >>> s = Student('Michael')
    >>> s
    <__main__.Student object at 0x109afb310>

    这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。

    解决办法是再定义一个__repr__()。但是通常__str__()__repr__()代码都是一样的,所以,有个偷懒的写法:

    class Student(object):
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return 'Student object (name=%s)' % self.name
        __repr__ = __str__

    五、__iter__()方法

    如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

    我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:

    class Fib(object):
        def __init__(self):
            self.a, self.b = 0, 1 # 初始化两个计数器a,b
    
        def __iter__(self):
            return self # 实例本身就是迭代对象,故返回自己
    
        def __next__(self):
            self.a, self.b = self.b, self.a + self.b # 计算下一个值
            if self.a > 100000: # 退出循环的条件
                raise StopIteration()
            return self.a # 返回下一个值
    >>> for n in Fib():
    ...     print(n)
    ...
    1
    1
    2
    3
    5
    ...
    46368
    75025

    六、__getitem__()方法

    class Fib(object):
        def __getitem__(self, n):
            if isinstance(n, int): # n是索引
                a, b = 1, 1
                for x in range(n):
                    a, b = b, a + b
                return a
            if isinstance(n, slice): # n是切片
                start = n.start
                stop = n.stop
                if start is None:
                    start = 0
                a, b = 1, 1
                L = []
                for x in range(stop):
                    if x >= start:
                        L.append(a)
                    a, b = b, a + b
                return L

    但是没有对step参数作处理,

    也没有对负数作处理,所以,要正确实现一个__getitem__()还是有很多工作要做的。

    此外,如果把对象看成dict__getitem__()的参数也可能是一个可以作key的object,例如str

    与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值。最后,还有一个__delitem__()方法,用于删除某个元素。

    总之,通过上面的方法,我们自己定义的类表现得和Python自带的list、tuple、dict没什么区别,这完全归功于动态语言的“鸭子类型”,不需要强制继承某个接口。

  • 相关阅读:
    内存溢出OutOfMemory
    系统问题定位
    final域的内存语义
    volatile内存语义
    锁的内存语义
    happens-before
    python 安装brew(国内的自动安装)
    【Mac】点击dmg文件后无反应,解决方案
    Mac----xmind 8 下载与破解方法
    面试中可向HR 提的问题总结?
  • 原文地址:https://www.cnblogs.com/gundan/p/8058057.html
Copyright © 2011-2022 走看看