列出在Python 3中具有嵌套ifs的理解变量范围

时间:2018-10-12 21:47:54

标签: python python-3.x psutil

基于this的答案以及列表理解不再在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

2 个答案:

答案 0 :(得分:2)

首先,从风格上讲,列表理解很不明智。试图阅读它的人完全无法理解。缩进是您的朋友,而代码行的数量也不是问题。更改缩进使其更具可读性:

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)

在这里,我假设如果任何个端口符合给定条件,则您想要给定进程的所有个端口,否则就不希望它们。这就是我阅读您的理解的方式。如果这不是您想要的,那么我可以更改它。 (这是为什么应避免使用大列表理解的具体示例。)

答案 1 :(得分:0)

您可以使用适当限定的理解来找到相关的端口,而不是使用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)