一、python调试:使用装饰器来统计函数被调用次数及格式化dict
喜欢调试的时候显示数据并显示一些其它的信息,比如区分是哪次调用的调试信息,比如友好的显示dict等相对复杂的数据类型,所以这里涉及到两个方面。一是统计函数被调用次数;二是格式化展示dict数据。
在类中对一个函数的调用次数进行统计比较方便,直接定义一个类属性来计数即可,但对于一个普通函数这样的方法就不能实现了,于是我们可以通过装饰器来实现。
装饰器(Decorators)是Python的一个重要功能,它是一个可以修改其他函数的功能的函数。简单地说,装饰器可以让你在一个已经定义的函数的前后去执行其它代码,这有点像JAVA中的AOP切面编程。我们先写一个装饰器类,然后在调用的方法上注明这是一个装饰器,此时再调用方法就会执行显示一个分隔行,同时记录了当前是第几次调用这个调试显示函数,然后再打印要debug的数据。代码如下:
#定义装饰器
class CountClass(object):
def __init__ (self, func):
self.func = func
self.count = 0
def __call__ (self, *args, **kwargs):
self.count += 1
print("*"*20 + str(self.func.__name__) + ":" +str(self.count) + "*"*20)
return self.func(*args, **kwargs)
#再来写一个被装饰的函数:
@CountClass
def show(data:any):
print(data)
#调用
show(data = "123abc")
针对第二个方面,格式化展示复杂数据,主要是dict类型数据。可以使用官方模块 pprint 格式化打印 dict 数据,python推出pprint正是因为print在显示复杂数据方面的不美观,比如打印一个dict,使用print显示一长串会看花眼。
import pprint
@CountClass
def show(data:any):
if isinstance(data, dict):
#使用pprint打印显示
pp = pprint.PrettyPrinter(indent=4)
pp.print(data)
#打印json
print(json.dumps(data, indent=4, separators=(', ', ': '), ensure_ascii=False))
else:
print(data)
但在测试时发现pprint并没有生效,后来发现只有要显示的内容比较长时,pprint才会美观化显示内容,否则会直接展示。不过在使用中通过对比,pprint还是不如直接使用json.dumps来展示美观,一是pprint只对第一层级进行美化展示,对于dict嵌套dict,内部的dict不会被美化;二是pprint在显示的时候{与内容在一行,效果不咋样。
二、Python-smtplib邮件发送Relaying denied. IP name possibly forged[IP地址]
使用PYTHON-smtplib需要先安装sendmail,使用apt install sendmail命令安装vcb即可,安装完成后sendmail的配置文件在/etc/mail/中,日志文件位于/var/log/目录中,mail.log、mail.err,查看这两个文件信息来定位问题。可以通过命令mail、mailq查看接收到的邮件和待发送的邮件。
$ whereis sendmail
sendmail: /usr/sbin/sendmail /usr/lib/sendmail /usr/share/sendmail
进行邮件发送代码很少,引入模块定义几个参数执行就行了。代码示例如下:
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import traceback
sender = 'my@cc.com'
receivers = ['user1@cc.com', 'user2@cc.com']
#四个参数
message = MIMEText('邮件信息主体', 'plain', 'utf-8')
message['Subject'] = Header('Python smtplib邮件发送测试', 'utf-8')
message['From'] = Header('测试邮件', 'utf-8')
message['To'] = Header('自己', 'utf-8')
try:
smtpObj = smtplib.SMTP('localhost')
smtpObj.sendmail(sender, receivers, message.as_string())
print('发送成功...')
except:
traceback.print_exc()
print('Error: 发送失败')
在执行过程中遇到报错:smtplib.SMTPRecipientsRefused: {'test@e.com': (550, b'5.7.1... Relaying denied. IP name possibly forged [172.17.0.3]')}。之前我已在服务器中进行了调试并且成功运行,但后面部署到docker容器中运行后就出现了上面的错误。从提示也很清楚看到IP地址不合法,此需要修改mail中的配置,进到mail服务器,在/etc/mail/access文件中添加如下一行:
Connect: IP地址 RELAY
然后使用如下命令使上述编辑过的配置生效即可成功.
makemap hash /etc/mail/access.db < /etc/mail/access