0

我在Windows Server 2012上运行多个Python安装。我可能找到一种方法解决这个问题,但我很好奇正在发生什么。我对从根本上改变安装情况保持警惕,以防我破坏我可能不知道的其他人的Python计划任务。从另一个Python安装导入的模块

(以下所有代码框均为PowerShell)。

PS C:\> C:\Python34\Scripts\pip.exe list 
jdcal (1.0) 
pip (7.1.2) 
setuptools (12.0.5) 
virtualenv (13.1.2) 

尽管这个Python 3.4安装没有安装Django,但它似乎会从Python 33x86安装中获取版本。这是正常的吗?

PS C:\> C:\Python34\python.exe -c "import django; print(django.get_version())" 
1.6.5 
PS C:\> C:\Python33x86\python.exe -c "import django; print(django.get_version())" 
1.6.5 

我创建了一个基于Python 3.4的Python virtualenv,并在其中安装了Django 1.8.4。做一个“点子清单”证实,它已正确安装: -

PS C:\> D:\PyVirtualEnvs\example_py34\Scripts\activate.bat 
PS C:\> D:\PyVirtualEnvs\example_py34\Scripts\pip.exe list | Select-String "Django " 
Django (1.8.4) 

然而,当我导入的virtualenv中,我得到的Django版本1.6.5: -

PS C:\> D:\PyVirtualEnvs\example_py34\Scripts\python.exe -c "import django; print(django.get_version())" 
1.6.5 

这是一个错误在virtualenv还是我错过了什么?

编辑:它可能与this question

编辑2:使用pyvenv时,发生同样的事情,正如火腿三明治所建议的。

+0

也许一个愚蠢的问题,但你确定你已经激活venv? 'venv \ Scripts \ activate.bat' –

+0

是的,位于上面第三个代码框的顶部。说,这样做时,没有视觉反馈来验证它的工作。 –

+0

是否有使用virtualenv而不是pyvenv的理由? https://docs.python.org/3/library/venv.html#module-venv –

回答

0

我发现了这种行为的原因。 PYTHONPATH环境变量被设置为在机器上异常位置的Python安装。

根据the documentation,当在当前目录中找不到模块时,将PYTHONPATH用作导入位置。

当导入一个名为spam的模块时,解释器首先搜索具有该名称的内置模块。如果找不到,它会在变量sys.path给出的目录列表中搜索名为spam.py的文件。 sys.path从这些位置初始化:

  • 包含输入脚本(或当前目录)的目录。
  • PYTHONPATH(目录名称列表,其语法与shell变量PATH相同)。
  • 安装依赖的默认值。

出于某种原因PYTHONPATH没有设置/取消由激活/关闭脚本。它确实设置了PYTHONHOME,但这似乎不影响进口。这感觉就像在virtualenv和pyvenv中的一个错误(我尝试了两个)。

原始的activate.bat脚本更改了一个“set”变量,它不影响$ env:PYTHONPATH。 Activate.ps1尝试将原始PYTHONPATH保存在变量中,将其设置为虚拟环境目录,然后在取消激活时恢复原始PYTHONPATH。这些都不能工作,可能是由于Powershell或Python更新。

我们的解决方案是修改激活和停用脚本(PoSh或bat)来在两个硬编码值之间切换PYTHONPATH。

1

看起来很奇怪,我的唯一的事情是,你在PowerShell中运行

D:\PyVirtualEnvs\example_py34\Scripts\activate.bat 

当有一个activate.ps1。我不知道是否存在兼容性问题。

+0

谢谢,好点,但我只是试了一下,得到了同样的结果。 –

1

如果运行PowerShell的(批处理文件)一个cmd.exe shell脚本,PowerShell的派生的cmd.exe实例运行脚本(批处理文件)。如果批处理文件设置了环境变量,则它们仅存在于衍生的cmd.exe实例中。一旦该实例终止(即脚本结束时),环境变量就不会传播到调用进程(本例中为PowerShell)。这是设计。

如果你想传播的环境变量,你可以在PowerShell中使用以下Invoke-CmdScript功能:

function Invoke-CmdScript { 
    param(
    [String] $scriptName 
) 
    $cmdLine = """$scriptName"" $args & set" 
    & $Env:SystemRoot\system32\cmd.exe /c $cmdLine | 
    Select-String '^([^=]*)=(.*)$' | ForEach-Object { 
    $varName = $_.Matches[0].Groups[1].Value 
    $varValue = $_.Matches[0].Groups[2].Value 
    Set-Item Env:$varName $varValue 
    } 
} 

下面的文章中有关这方面的一些详细信息:

Windows IT Pro: Take Charge of Environment Variables in PowerShell

在你例如,您将运行:

PS C:\> Invoke-CmdScript D:\PyVirtualEnvs\example_py34\Scripts\activate.bat 

这将产生activate.bat并传播环境变量更改。

+0

谢谢,我不知道。但是,Invoke-CmdScript函数似乎吞噬了python的所有输出,即使在交互式shell中也是如此。如果我按照建议运行activate,那么调用python命令它仍然是django的错误版本,如果我尝试使用Invoke-CmdScript python.exe -c导入失败。 –

+0

大概我需要通过单个批处理文件调用来运行我想要的所有内容,以在激活和python调用之间保留这些环境变量。 –

+0

你不会使用该函数来运行python;你只会用它来执行'activate.bat'脚本并传播它设置的环境变量。请注意,另一个答案中提到了专门针对PowerShell的'activate.ps1'。 –