简体   繁体   English

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

[英]list comprehension variable scope with nested ifs in python 3

Based on this answer and the fact that list comprehensions no longer "leak" their variable in Python 3.x how I can implement/rewrite this expression 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

First, that list comprehension is pretty whack stylistically. 首先,从风格上说,列表理解是很不容易的。 Totally incomprehensible for anyone trying to read it. 试图阅读它的人完全无法理解。 Indentation is your friend, and numbers of lines of code are not a premium. 缩进是您的朋友,而代码行的数量也不是问题。 Changing the indentation to make it more readable: 更改缩进使其更具可读性:

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()])
]

The problem now becomes clear. 现在,问题变得很明显。 List comprehensions do not leak their scope in Python 3. Outside of the ports list comprehension (if it didn't fail due to a NameError ), there would be no object called proc . 列表推导不会泄漏其在Python 3中的作用域。在ports列表推导之外(如果它不会因NameError而失败),将没有名为proc对象。

That said, you do get a name error because the list comprehension inside your call to any also doesn't leak its scope. 就是说,您确实会收到名称错误,因为对any的调用中的列表理解不会泄漏其范围。 No port variable escapes outside to the parent list comprehension, and you get a NameError . 没有任何port变量会在父列表理解之外进行转义,并且会出现NameError

Second, to address your question, you should probably avoid a list comprehension altogether. 其次,要解决您的问题,您可能应该完全避免列表理解。 You're trying to do too much in a single statement. 您试图在一个语句中做太多事情 Create a ports list. 创建ports列表。 Iterate through your processes in a for loop, and append according to your required logic. for循环中遍历您的进程,并根据所需的逻辑进行append

To demonstrate: 展示:

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)

Here, I've assumed that you wanted all ports for a given process if any of the ports match your given criterion, and you otherwise want none of them. 在这里,我假设如果任何端口都符合给定条件,则您需要给定进程的所有端口,否则就不希望它们。 This is how I read your comprehension. 这就是我阅读您的理解的方式。 If that's not what you're looking for, then I can change it. 如果这不是您想要的,那么我可以更改它。 (This is a concrete example of why using large list comprehensions should be avoided.) (这是为什么应避免使用大列表理解的具体示例。)

Rather than using any and expecting the list comprehension variable to leak out, you can find the relevant ports using properly qualified comprehensions. 您可以使用适当限定的理解来查找相关端口,而不是使用any期望列表理解变量泄漏出去的方法。

I've separated it into two comprehensions so it would fit in my brain. 我将其分为两个理解层,因此适合我的大脑。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM