python使用装饰器来统计函数被调用次数、格式化dict以及Python-smtplib邮件发送的IP name possibly forged问题解决

发布于:2024-10-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、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