[英]list comprehension variable scope with nested ifs in python 3
基于这个答案和事实,列表理解不再在Python 3.x中“泄漏”其变量了,我如何在Python 3中实现/重写此表达式?
>>> import sys
>>> sys.version[:5]
'3.6.5'
>>> import psutil
>>> psutil.__version__
'5.4.7'
>>> [port.laddr.port for proc in psutil.process_iter(attrs=['name']) if 'sshd' in proc.info['name'] if any([port.status == psutil.CONN_LISTEN for port in proc.connections()])]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
NameError: name 'port' is not defined
首先,从风格上说,列表理解是很不容易的。 试图阅读它的人完全无法理解。 缩进是您的朋友,而代码行的数量也不是问题。 更改缩进使其更具可读性:
ports = [
port.laddr.port
for proc in psutil.process_iter(attrs=['name'])
if 'sshd' in proc.info['name']
if any([port.status == psutil.CONN_LISTEN for port in proc.connections()])
]
现在,问题变得很明显。 列表推导不会泄漏其在Python 3中的作用域。在ports
列表推导之外(如果它不会因NameError
而失败),将没有名为proc
对象。
就是说,您确实会收到名称错误,因为对any
的调用中的列表理解也不会泄漏其范围。 没有任何port
变量会在父列表理解之外进行转义,并且会出现NameError
。
其次,要解决您的问题,您可能应该完全避免列表理解。 您试图在一个语句中做太多事情 。 创建ports
列表。 在for
循环中遍历您的进程,并根据所需的逻辑进行append
。
展示:
ports = []
def validate_proc(proc):
return any(
port.status == psutil.CONN_LISTEN
for port in proc.connections()
)
for proc in in psutil.process_iter(attrs=['name']):
if not 'sshd' in proc.info['name']:
continue
if not validate_proc(proc):
continue
for port in proc.connections():
ports.append(port.laddr.port)
在这里,我假设如果任何端口都符合给定条件,则您需要给定进程的所有端口,否则就不希望它们。 这就是我阅读您的理解的方式。 如果这不是您想要的,那么我可以更改它。 (这是为什么应避免使用大列表理解的具体示例。)
您可以使用适当限定的理解来查找相关端口,而不是使用any
期望列表理解变量泄漏出去的方法。
我将其分为两个理解层,因此适合我的大脑。
procs = [proc for proc in psutil.process_iter(attrs=['name'])
if 'sshd' in proc.info['name']]
ports = [port.latter.port for proc in procs
for port in proc.connections() if port.status==psutil.CONN_LISTEN]
print(ports)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.