简体   繁体   English

为什么我对本地作用域中存在的变量的调用在Python中不起作用?

[英]Why is my call to a variable that exists in the local scope not working in Python?

This code is part of a function. 此代码是功能的一部分。 When I run the function line by line with the proper arguments, it runs fine, but when I call the function it doesn't seem to work. 当我使用适当的参数逐行运行该函数时,它运行良好,但是当我调用该函数时,它似乎不起作用。 The following three lines of code and their output are from the function call: 以下三行代码及其输出来自函数调用:

print(locals().keys())
dict_keys(['allpost', 'allpre', 'pre', 'post'])

You can see that 'allpre' exists in my local scope. 您可以看到“ allpre”存在于我的本地范围内。 This line of code, also in the function, works as well: 这行代码,也可以在函数中正常使用:

print(locals()['allpre'])
[15.0, 12.0, 10.0, 6.0, 12.0, 8.0, 5.0, 3.0]

But for some reason this code doesn't work: 但是由于某些原因,此代码无法正常工作:

print([locals()[k] for k in ['allpre']])
Traceback (most recent call last):
File "prepost.py", line 85, in <module>      parentinfantstats=delete.bystats(mod='parentinfant',assessment=".*pii[1-3]plus",dta=sortFiltbyMod.copy())
File "/mnt/m/safecare/prepost/delete.py", line 37, in bystats
print([locals()[k] for k in ['allpre']])
File "/mnt/m/safecare/prepost/delete.py", line 37, in <listcomp>
print([locals()[k] for k in ['allpre']])
KeyError: 'allpre'

Does anyone have a suggestion for what the problem might be? 有人对问题可能有什么建议吗? I would post an example, but can't seem to duplicate the problem. 我会举一个例子,但似乎无法重现问题。

This is the whole function: 这是整个功能:

import re
from statistics import mean,median,stdev

def bystats(*,mod,assessment,dta):
    varz=dta[mod]               
    alab=[i for i in varz if re.match(assessment.lower(),i.lower())]
    alab.insert(0,'prepost')
    alab.insert(0,'cact_familycodenormalized')
    alst=[varz[i] for i in alab] # [ID,prepost,assessment]
    bymodprepost=[list(row) for row in zip(*alst) if row[1] in [1,2]] # [ID,prepost,assessment] if prepost 1 or 2
    bymodpost=[i for i in bymodprepost if i[1]==2] # [ID,prepost,assessment] if prepost was 2 (post)
    bymodpre=[i for i in bymodprepost if i[0] in [ids[0] for ids in bymodpost] and i[1]==1] # [ID,prepost,assessment] if ID had a post test

    allpre,allpost,allch,allpctch=[],[],[],[]
    for pre in bymodpre:
        post=[i for i in bymodpost if i[0].upper().strip()==pre[0].upper().strip()][0] # find matching post test
        if any([True for i in pre[2:]+post[2:] if float(i)<0]): continue # cannot have negative number
        sumpre=sum([float(i) for i in pre[2:]]) # sum of pre test assessments
        allpre.append(sumpre)
        sumpost=sum([float(i) for i in post[2:]]) # sum post test assessments
        allpost.append(sumpost)
        ch=sumpost-sumpre       # change from pre to post
        allch.append(ch)
        pctch=round(ch/sumpre*100,1) # percent change from pre to post
        allpctch.append(pctch)
    print(locals().keys())
    print(locals()['allpre'])
    print(locals()[k] for k in ['allpre'])

And this is the function call: 这是函数调用:

parentinfantstats=delete.bystats(mod='parentinfant',assessment=".*pii[1-3]plus",dta=sortFiltbyMod.copy())

List comprehensions have their local scope since Python 3.0. 自Python 3.0以来,列表推导具有其本地范围。 This was to prevent scope leak . 这是为了防止示波器泄漏

https://docs.python.org/3.0/whatsnew/3.0.html https://docs.python.org/3.0/whatsnew/3.0.html

[...] note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a list() constructor, and in particular the loop control variables are no longer leaked into the surrounding scope. [...]请注意,列表推导具有不同的语义:对于list()构造函数中的生成器表达式,它们更接近语法糖,尤其是循环控制变量不再泄漏到周围的范围中。

Calling locals from within a list comprehension won't work the way you expect it to (in Python 3). 从列表理解内调用locals将无法实现您期望的方式(在Python 3中)。 That's because the main body of the list comprehension gets run within its own local namespace, just like it was a function returning a list. 这是因为列表理解的主体在其自己的本地名称空间中运行,就像它是一个返回列表的函数一样。 You can see this in your traceback, where <listcomp> shows up as one of the stack levels. 您可以在回溯中看到这一点,其中<listcomp>显示为堆栈级别之一。

In Python 2, list comprehensions didn't do this (but generator expressions did). 在Python 2中,列表推导并不能做到这一点(但是生成器表达式可以做到)。 A side effect of their old behavior was that the iteration variable (eg k ) would "leak" out into the surrounding namespace, which was often very unexpected. 他们的旧行为的副作用是迭代变量(例如k )将“泄漏”到周围的名称空间中,这通常是非常意外的。 List comprehensions can also break when they're run at the top level of a class, as the class variables previously defined won't be accessible to the comprehension function (since classes don't have scopes). 当列表理解在类的顶级运行时,它们也可能会中断,因为先前定义的类变量将无法被理解函数访问(因为类没有作用域)。

尝试在打印中使用[[]]

print(locals()[k] for k in ['allpre'])

You're on Python 3, where a list comprehension has its own scope with its own local variables. 您使用的是Python 3,列表推导具有自己的作用域和自己的局部变量。 allpre is not one of the comprehension's local variables. allpre不是理解的局部变量之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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