说到魔法方法可能和我一样是小白的人没什么印象,但是如果说到Python 类的构建大家都应该能想到下面的函数
class _():
def __init__(self):
.......
其实看似简单的类定义实际上暗藏玄机, 其中就蕴含了一个魔法方法:__ init __ 。关于 __ init __ 干什么用的大家也都知道,是在创建对象的时候在初始化被调用,又叫构造函数。其实除了__ init __ 之外还存在不少我们生活中经常遇到但是会完全忽视掉的方法,比如print(dict) print一个对象的时候为甚么就能正确的以字符串形式打印等等,这些都是魔术方法的功劳. 下面会介绍一些常用的方法
- __ del __ 析构函数:
析构函数是对象在回收的时候所自动调用的函数。说到对象回收会关联到Python的垃圾回收机制,我会在下面的部分写上垃圾回收机制哒。del 函数虽然少见,也很少被显式的写出与调用,却是每个类都有的实实在在存在的重要方法
class _():
def __init__(self):
print('我是一个类,如果你看到我了,说明我对象化了')
@property
def some_fuc(self):
print('我被调用了一些方法')
def __del__(self):
print('再见了Master, 我换化为资源回到内存当中,请,不要,忘记.....')
if __name__ == '__main__':
__ = _()
__.some_fuc
# output
'''
我是一个类,如果你看到我了,说明我对象化了
我被调用了一些方法
再见了Master, 我换化为资源回到内存当中,请,不要,忘记.....
'''
一般来说资源回收这事都是编译器来帮我们做的,但是以后不乏会出现自己需要回收资源的情况:
class _():
def __init__(self):
print('我是一个类,如果你看到我了,说明我对象化了')
@property
def some_fuc(self):
print('我被调用了一些方法')
def __del__(self):
print('再见了Master, 我换化为资源回到内存当中,请,不要,忘记.....')
if __name__ == '__main__':
__ = _()
del __
__.some_fuc
##output
'''
我是一个类,如果你看到我了,说明我对象化了
再见了Master, 我换化为资源回到内存当中,请,不要,忘记.....
Traceback (most recent call last):
File "C:/Users/40629/Desktop/some.py", line 87, in <module>
__.some_fuc
NameError: name '__' is not defined
'''
所以说资源回收函数还是很有用的,因为它,确实帮你回收资源了嘛
-
__ doc __: 代表一个类的文档,主要定义类的说明。怎么用呢,很简单,’’'的注释我之前一直以为不会进入内存中,然而实际上类中的三引号注释会作为说明文档调用
class _(): ''' 我是一个可怜弱小有无助的类,哒吖请不要碰伦家 ''' def __init__(self): print('我是一个类,如果你看到我了,说明我对象化了') if __name__ == '__main__': __ = _() print(__.__doc__) # output: ''' 我是一个类,如果你看到我了,说明我对象化了 我是一个可怜弱小有无助的类,哒吖请不要碰伦家 '''
-
__ call __ 调用函数。函数调用在任何语言中都是超常用的概念
(语言指导:绢旗最爱)。对于Python这种超语法自由的语言,我们甚至可以做到让类像函数一样被调用, 而这正式callable的强大功能class sum(): def __init__(self): print("我是一个Object实例") def __call__(self, *args, **kwargs): count = 0 for i in args: count += i return count if __name__ == "__main__": _ = sum() print(_(1,2,3,4,5,6,7)) # output ''' 我是一个Object实例 28 '''
-
__ dict __ 说实话,看到这个方法,我第一眼就是字典。而且事实也确实是这样:__ dict __ 有打印对象所有参数的能力。对于类,dict更能打印所有的包括方法在内的所有属性
class _(): def __init__(self): print("我是一个Object实例") self.name = 'A' if __name__ == "__main__": __ = sum_ print(__.__dict__) print(_.__dict__) # output ''' 我是一个Object实例 {'name': 'A'} {'__module__': '__main__', '__init__': <function sum.__init__ at 0x000001E6BBE49280>, '__call__': <function sum.__call__ at 0x000001E6BBE493A0>, '__dict__': <attribute '__dict__' of 'sum' objects>, '__weakref__': <attribute '__weakref__' of 'sum' objects>, '__doc__': None} '''
不过这就衍生除了Python的权限问题。事实上, dict 可以打印无论共有或私有所有的变量,原因是Python私有变量(self.__ XX)会将访问的名字变化达到无法访问的结果。懂我意思吧,这玩应是有安全隐患的。(这是真的强大)
class sum(): def __init__(self): print("我是一个Object实例") self.name = 'A' self.__name = 'A' def __call__(self, *args, **kwargs): count = 0 for i in args: count += i return count if __name__ == "__main__": _ = sum() print(_.__dict__) ''' 我是一个Object实例 {'name': 'A', '_sum__name': 'A'} '''
-
__ str __ 强转字符串。没啥好说的,在Django中我们就用过哒。当print调用的时候,如果print的对象不是字符串类型就会调用此函数强转。list, tuple, int等等对象都内置了这个方法。对于我这种
重度print改bug玩家真的超有用class sum(): def __init__(self): print("我是一个Object实例") def __str__(self): return 'class XX this' if __name__ == "__main__": n = sum() print(n) # output ''' 我是一个Object实例 class XX this '''
-
__ len __ 返回长度,在列表,元组,集合,字符串中都有这玩应。len提供我给们的就是调用可以被len调用返回int的能力。好像也没啥用,但是写出来的代码更符合我们人的逻辑。
class student(): def __init__(self): self.name = None self.age = None self.lens = 2 def __len__(self): return self.lens if __name__ == '__main__': print('学生信息一共要填写', len(student()),'个选项') # output ''' 学生信息一共要填写 2 个选项 '''
-
__ iterable __ __ next __ 迭代器,不重复,感兴趣看我前面的Python并发2
-
__ getitem __ 这很明显是字典方法的变种,我们按照字典的逻辑去写就可以啦。与之类似的setitem, delitem不过多重复
class Student(): def __init__(self): self.name = 'A' self.age = 10 def __getitem__(self, item): if item.lower() == 'name': return self.name elif item.lower() == 'age': return self.age else: raise KeyError('This key is not one of class Student attr') if __name__ == '__main__': student = Student() print(student['name'],student['age']) print(student['id']) # output ''' A 10 KeyError: 'This key is not one of class Student attr' '''
剩下的魔法方法其实有点前篇一律,用的时候再说吧