• Python面向对象-特殊成员


    我们知道类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。

    Python的类成员还存在着一些具有特殊含义的成员,其中有一些比较重要的,我们一一来看:

    (1) __init__

    构造方法,通过类创建对象时,自动触发执行。

    1 class Student(object):
    2     def __init__(self, name):
    3         self.name = name
    4     
    5     ...

    (2) __del__

    析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

    1 class Student(object):
    2     ...
    3 
    4     def __del__(self):
    5         pass

    (3) __call__

    我们已经知道了类名后面加()是调用__init__方法,那对象后面加()呢?请看下面的代码:

     1 class Student(object):
     2     def __init__(self, name):
     3         self.name = name
     4 
     5     def __call__(self):
     6         print(self.name)
     7 
     8     ...
     9 
    10 mike = Student("Mike")
    11 mike()

    程序输出是: Mike ,我们可以看到对象()会调用__call__方法,我们可以通过callable()函数判断对象是否可以调用

    (4) __dict__

    有没有办法获取对象里所有普通字段及其值呢?Python为我们提供了__dict__:

     1 class Student(object):
     2     Nation = "China"
     3 
     4     def __init__(self, name):
     5         self.name = name
     6         self.score = 0
     7 
     8     ...
     9 
    10 mike = Student("Mike")
    11 print(mike.__dict__)

    程序输出: {'score': 0, 'name': 'Mike'} ,对于静态字段Nation = "China",__dict__内并不包含

    (5) __str__ , __repr__ 

    对于一个对象,我们对其使用print时,默认程序输出的是对象的内存地址:

    1 class Student(object):
    2     def __init__(self, name):
    3         self.name = name
    4         self.score = 0
    5 
    6     ...
    7 
    8 mike = Student("Mike")
    9 print(mike)

    程序输出: <__main__.Student object at 0x0050F7B0> 

    怎么才能打印得好看呢?只需要定义好__str__()方法,返回一个好看的字符串就可以了:

     1 class Student(object):
     2     def __init__(self, name):
     3         self.name = name
     4         self.score = 0
     5 
     6     def __str__(self):
     7         return self.name
     8     ...
     9 
    10 mike = Student("Mike")
    11 print(mike)

    程序输出就是__str__方法的返回值: Mike 

    如果我们把上面的代码在idle里运行,并敲下mike时(>>>mike),打印出来的还是对象的地址,

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

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

    1 class Student(object):
    2     def __init__(self, name):
    3         self.name = name
    4         self.score = 0
    5 
    6     def __str__(self):
    7         return self.name
    8     __repr__ = __str__

    (6) __iter__

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

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

     1 class Fib(object):
     2     def __init__(self, maximum):
     3         self.a = 0
     4         self.b = 1  # 初始化两个计数器a,b
     5         self.maximum = maximum # 定义停止循环的条件
     6 
     7     def __iter__(self):
     8         return self  # 实例本身就是迭代对象,故返回自己
     9 
    10     # Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到
    11     # StopIteration错误时退出循环
    12     def __next__(self):
    13         self.a, self.b = self.b, self.a + self.b
    14         if self.a > self.maximum:
    15             raise StopIteration()
    16         return self.a
    17 
    18 for item in Fab(100):
    19     print(item)

    (7) __getitem__、__setitem__、__delitem__

    上面的Fib类的对象虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第4个元素:

    1 Fib(100)[4]
    2 TypeError: 'Fib' object does not support indexing

    要表现得像list那样按照下标取出元素,需要实现__getitem__()方法

    1     def __getitem__(self, i):
    2         a, b = 0, 1
    3         for x in range(i):
    4             a, b = b, a + b
    5         if a <= self.maximum:
    6             return a
    7         else:
    8             raise ValueError("Out of range")

    现在,就可以按下标访问数列的任意一项了: print("Fib(100)[4]:", Fib(100)[4]) ,输出是: Fib(100)[4]: 3 

    list还有个神奇的切片方法,Fib该如何实现呢?__getitem__()传入的参数可能是一个int,也可能是一个切片对象slice,所以要做判断:

     1     def __getitem__(self, i):
     2         if isinstance(i, int):
     3             a, b = 0, 1
     4             for x in range(i):
     5                 a, b = b, a + b
     6             if a <= self.maximum:
     7                 return a
     8             else:
     9                 raise ValueError("Out of range")
    10         elif isinstance(i, slice):
    11             if isinstance(i, slice):  # i是切片
    12                 start = i.start
    13                 stop = i.stop
    14                 if start is None:
    15                     start = 0
    16                 a, b = 1, 1
    17                 L = []
    18                 for x in range(stop):
    19                     if x >= start:
    20                         L.append(a)
    21                     a, b = b, a + b
    22                 return L

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

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

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

     1     def __getitem__(self, i):
     2         if isinstance(i, int): # 对应于list, tuple的索引
     3             a, b = 0, 1
     4             for x in range(i):
     5                 a, b = b, a + b
     6             if a <= self.maximum:
     7                 return a
     8             else:
     9                 raise ValueError("Out of range")
    10         elif isinstance(i, slice): # 对应于list,tuple的切片
    11             if isinstance(i, slice):  # i是切片
    12                 start = i.start
    13                 stop = i.stop
    14                 if start is None:
    15                     start = 0
    16                 a, b = 1, 1
    17                 L = []
    18                 for x in range(stop):
    19                     if x >= start:
    20                         L.append(a)
    21                     a, b = b, a + b
    22                 return L
    23         elif isinstance(i, str): # 对应于字典的dic[key]或dic.get[key]
    24             print(type(i))
    25         else:
    26             print("wrong type")
    27 
    28     def __setitem__(self, key, value): # 对应于字典的dic[key] = value
    29         print("key:value", key, value)
    30 
    31     def __delitem__(self, key): # 对应于del dic[key]
    32         print("del", key)
  • 相关阅读:
    解决一道leetcode算法题的曲折过程及引发的思考
    算法研究:一维多项式求值(秦九韶算法)
    通过HWND获得CWnd指针
    将标题空格替换为 '_' , 并自动复制到剪切板上
    稀疏矩阵操作算法
    微信好友分析之展示好友信息
    微信好友分析之获取好友信息
    爬取当当网的图书信息之结尾
    爬取当当网的图书信息之封装一个工具类
    爬取当当网的图书信息之实体设计
  • 原文地址:https://www.cnblogs.com/z-joshua/p/6398231.html
Copyright © 2020-2023  润新知