python笔记14介绍几个魔法方法
先声明一下
各位大佬,这是我的笔记。
如有错误,恳请指正。
另外,感谢您的观看,谢谢啦!
(1).__doc__
输出对应的函数,类的说明文档
print(print.__doc__)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
自己写的也可以
class Student(object):
'''
类: 学生
字段:普通:学科一成绩,学科二成绩,学科三成绩
静态:班主任,学生信息一,学生信息二,学科一,学科二,学科三 (可更改内容)
方法:普通:以列表形式输出各学科成绩
静态:无
'''
stu_msg1 = "学号"
stu_msg2 = "姓名"
stu_lesson1 = "数学成绩"
stu_lesson2 = "英语成绩"
stu_lesson3 = "语文成绩"
def __init__(self,nm):
self.msg1 = nm[0]
self.msg2 = nm[1]
self.lesson1 = nm[2]
self.lesson2 = nm[3]
self.lesson3 = nm[4]
def show_grade(self):
return [self.msg2,self.lesson1,self.lesson2,self.lesson3]
print(Student.__doc__)
类: 学生
字段:普通:学科一成绩,学科二成绩,学科三成绩
静态:班主任,学生信息一,学生信息二,学科一,学科二,学科三 (可更改内容)
方法:普通:以列表形式输出各学科成绩
静态:无
(2).__dict__
输出对象(或者类)的字段
当这个魔法方法前面是对象变量时,它只是输出普通字段,因为普通字段只能能被对象使用,
当魔法方法前面是类时,它会输出其他全部的字段和方法。
还是用上面我写的代码举例
ac = Student(['1024','张三','80','90','89'])
print(ac.__dict__)
print(Student.__dict__)
{'msg1': '1024', 'msg2': '张三', 'lesson1': '80', 'lesson2': '90', 'lesson3': '89'}
{'__module__': '__main__', '__doc__': '\n 类: 学生\n 字段:普通:学科一成绩,学科二成绩,学科三成绩\n 静态:班主任,学生信息一,学生信息二,学科一,学科二,学科三 (可更改内容)\n 方法:普通:以列表形式输出各学科成绩\n 静态:无\n ', 'class_teacher': '点点', 'stu_msg1': '学号', 'stu_msg2': '姓名', 'stu_lesson1': '数学成绩', 'stu_lesson2': '英语成绩', 'stu_lesson3': '语文成绩', '__init__': <function Student.__init__ at 0x000001A22C079840>, 'show_grade': <function Student.show_grade at 0x000001A22C593D90>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>}
这里完美验证了前面学的知识,普通字段只有对象能用,
除此之外其他的静态字段,普通方法,静态方法,类方法都是共有的。
此外还要注意它返回的是一个字典
####(3).__del__以及删除机制
先讲删除机制结论;
如果在对象一直没有被调用,那么会在所有代码执行完后自动删除这个对象
如果在代码执行期间对象被你用代码删除,哪先要看这个对象是否被其他的对象引用,如果有就还是在代码执行完删除对象,如果没有则当场删除它。
__del__是在对象被删除是自动调用的函数,(由删除机制来删除,你手动写了删除代码,也是由删除机制判断到底什么时候来删除)当然,我们可以在类中重写这个函数来达到我们想要的目的
- 声明后一直没用会在全部代码执行结束会被删除
class Student(object):
def __del__(self):
print("我被删除机制删除了")
ac = Student()
print('----*----')
----*----
我被删除机制删除了
- 没被其他对象引用,又被你用代码删除,那就是当场删除
class Student(object):
def __del__(self):
print("我被删除机制删除了")
ac = Student()
print('----*----')
del ac
print('----*----')
----*----
我被删除机制删除了
----*----
- 被其他对象引用,但被你用代码删除,那会是在代码全部执行结束后删除
class Student(object):
def __del__(self):
print("我被删除机制删除了")
ac = Student()
ac = Student()
ab = ac
print('----*----')
del ac
print('----*----')
----*----
----*----
我被删除机制删除了
(4).__call__
我们知道将类实例化后的对象变量,它里面存的是一个功能地址,而当我们不想让他返回功能地址时,我们可以用__str__魔法方法返回字符串,而我们在对象变量后面加上()想以函数形式调用这个对象,本来是会报错的 。
而用了__call__就允许这样做了,来我们来看代码。
class test:
pass
ac = test()
print(ac)
ac()
最后一句正常是会报错的,因为是不允许这样用的
TypeError: 'Student' object is not callable
class test:
def __call__(self, *args, **kwargs):
print("你好")
pass
ac = test()
print(ac)
ac()
<__main__.test object at 0x0000021C63948518>
你好
使用魔法方法后对象就变得可调用了。
(4).__new__
new方法是用来创建并返回给init一个对象
init方法是用来在对象创建时,自身初始化的
所以在实例化一个对象时 new先于init被执行
class test(object):
def __new__(cls):
print("--1--")
def __init__(self):
print('--2--')
ac = test()
--1--
这段代码为什么只执行了new,init不应当会初始化吗?
实际上,这里我们重写了new,它不再有创建对象并返回的功能,对象没有被创建自然不会去初始化
所以我们要super,object类的new
class test(object):
def __new__(cls):
print("--1--")
return super().__new__(cls)
def __init__(self):
print('--2--')
ac = test()
--1--
--2--
我们也可以验证一下new的返回值
class test(object):
def __new__(cls):
print("--1--")
d = super().__new__(cls)
print(d)
return d
def __init__(self):
print('--2--')
ac = test()
--1--
<__main__.test object at 0x0000017858EA8E48>
--2--
就是对象变量啊
(5).单例模式
在一些特定情况下,我们需要某个类只能有一个对象,比如日志记录,这就是单例模式。
class sing(object):
__flag = 0
def __new__(cls, *args, **kwargs):
if cls.__flag == 0:
cls.__flag = super().__new__(cls)
return cls.__flag
else:
return cls.__flag
a = sing()
b = sing()
c = sing()
print(id(a))
print(id(b))
print(id(c))
2368668927536
2368668927536
2368668927536
可见没有新生成的对象,都是最开始哪一个
(6).反射
反射是很重要的用法,尤其是在web中,这里只是简单讲讲
我们首先建立一个模块
def find_stu():
print('查找学生页面')
def ex_stu():
print('修改学生页面')
将这个模块导入另一个文件中(上面的代码存在fs.py中)
import fs
正常的调用是这样的
import fs
ac = input("请选择功能:")
if ac == 'find_stu':
fs.find_stu()
elif ac == 'ex_stu':
fs.ex_stu()
else :
print('未找到')
请选择功能:ex_stu
修改学生页面
接下来看点不正常的
import fs
ac = input("请选择功能:")
if hasattr(fs,ac):
funct = getattr(fs,ac)
funct()
else :
print('未找到')
请选择功能:ex_stu
修改学生页面
这就是反射,很看起来一头雾水,但是也是有规律的,
hasattr,用来判断和搜素,getsttr用来获取
他们的第一个参数是要去搜索或获取的模块,第二个是对应的函数名字
如果我改一下fs里的函数的名字。它就找不到了
def find_st():
print('查找学生页面')
stu变成st,它就找不到了
请选择功能:find_stu
未找到
这时假设我还要对其他的模块应用反射,最简单的办法是
import 新的模块,然后两个反射函数第一个参数改一下就可以了,
但是当模块非常多时哪,还一条一条加,当然不是,下面看更好的办法
再写一个模块命名为fc.py
def add_stu():
print('添加学生页面')
def test_stu():
print('学生成绩页面')
然后主页面这样写
ac = input("请选择路径:")
modules,func = ac.split('/')
module_now = __import__(modules)
if hasattr(module_now,func):
funct = getattr(module_now,func)
funct()
else :
print('未找到')
请选择路径:fc/add_stu
添加学生页面
多试几次
请选择路径:fs/ex_stu
修改学生页面
请选择路径:fc/test_stu
学生成绩页面
请选择路径:fc/ex_stu
未找到