标签归档:python-3.x

错误:“’dict’对象没有属性’iteritems’”

问题:错误:“’dict’对象没有属性’iteritems’”

我正在尝试使用NetworkX读取Shapefile并使用该函数write_shp()生成将包含节点和边的Shapefile,但是当我尝试运行代码时,出现以下错误:

Traceback (most recent call last):   File
"C:/Users/Felipe/PycharmProjects/untitled/asdf.py", line 4, in
<module>
    nx.write_shp(redVial, "shapefiles")   File "C:\Python34\lib\site-packages\networkx\readwrite\nx_shp.py", line
192, in write_shp
    for key, data in e[2].iteritems(): AttributeError: 'dict' object has no attribute 'iteritems'

我正在使用Python 3.4,并通过pip install安装了NetworkX。

在发生此错误之前,它已经给我另一个提示“ xrange不存在”或类似名称,因此我进行了查找,然后将其更改xrangerangenx_shp.py文件,似乎可以解决该问题。

根据我的阅读,它可能与Python版本(Python2 vs Python3)有关。

I’m trying to use NetworkX to read a Shapefile and use the function write_shp() to generate the Shapefiles that will contain the nodes and edges, but when I try to run the code it gives me the following error:

Traceback (most recent call last):   File
"C:/Users/Felipe/PycharmProjects/untitled/asdf.py", line 4, in
<module>
    nx.write_shp(redVial, "shapefiles")   File "C:\Python34\lib\site-packages\networkx\readwrite\nx_shp.py", line
192, in write_shp
    for key, data in e[2].iteritems(): AttributeError: 'dict' object has no attribute 'iteritems'

I’m using Python 3.4 and installed NetworkX via pip install.

Before this error it had already given me another one that said “xrange does not exist” or something like that, so I looked it up and just changed xrange to range in the nx_shp.py file, which seemed to solve it.

From what I’ve read it could be related to the Python version (Python2 vs Python3).


回答 0

正如您在python3中一样,请使用dict.items()代替dict.iteritems()

iteritems() 已在python3中删除,因此您无法再使用此方法。

看一下Python 3.0 Wiki的“ 内置更改”部分,其中指出:

删除dict.iteritems()dict.iterkeys()dict.itervalues()

相反:使用dict.items()dict.keys()dict.values() 分别。

As you are in python3 , use dict.items() instead of dict.iteritems()

iteritems() was removed in python3, so you can’t use this method anymore.

Take a look at Python 3.0 Wiki Built-in Changes section, where it is stated:

Removed dict.iteritems(), dict.iterkeys(), and dict.itervalues().

Instead: use dict.items(), dict.keys(), and dict.values() respectively.


回答 1

Python2中,我们有.items().iteritems()在字典中。dict.items()返回字典中的元组列表[(k1,v1),(k2,v2),...]。它复制了字典中的所有元组并创建了新列表。如果字典很大,则对内存的影响很大。

因此,他们dict.iteritems()在更高版本的Python2中创建了代码。此返回的迭代器对象。未复制整个词典,因此内存消耗较少。使用人Python2被教导要使用dict.iteritems()的,而不是.items()如下面的代码解释了效率。

import timeit

d = {i:i*2 for i in xrange(10000000)}  
start = timeit.default_timer()
for key,value in d.items():
    tmp = key + value #do something like print
t1 = timeit.default_timer() - start

start = timeit.default_timer()
for key,value in d.iteritems():
    tmp = key + value
t2 = timeit.default_timer() - start

输出:

Time with d.items(): 9.04773592949
Time with d.iteritems(): 2.17707300186

Python3,他们想使之更有效率,所以感动dictionary.iteritems()dict.items(),并删除.iteritems(),因为它不再需要。

您已经使用过dict.iteritems()Python3所以失败了。尝试使用dict.items()具有与相同功能dict.iteritems()Python2。这是从Python2到的一点点迁移问题Python3

In Python2, we had .items() and .iteritems() in dictionaries. dict.items() returned list of tuples in dictionary [(k1,v1),(k2,v2),...]. It copied all tuples in dictionary and created new list. If dictionary is very big, there is very big memory impact.

So they created dict.iteritems() in later versions of Python2. This returned iterator object. Whole dictionary was not copied so there is lesser memory consumption. People using Python2 are taught to use dict.iteritems() instead of .items() for efficiency as explained in following code.

import timeit

d = {i:i*2 for i in xrange(10000000)}  
start = timeit.default_timer()
for key,value in d.items():
    tmp = key + value #do something like print
t1 = timeit.default_timer() - start

start = timeit.default_timer()
for key,value in d.iteritems():
    tmp = key + value
t2 = timeit.default_timer() - start

Output:

Time with d.items(): 9.04773592949
Time with d.iteritems(): 2.17707300186

In Python3, they wanted to make it more efficient, so moved dictionary.iteritems() to dict.items(), and removed .iteritems() as it was no longer needed.

You have used dict.iteritems() in Python3 so it has failed. Try using dict.items() which has the same functionality as dict.iteritems() of Python2. This is a tiny bit migration issue from Python2 to Python3.


回答 2

我有一个类似的问题(使用3.5),每天损失1/2,但这是可行的-我退休了,只是学习Python,所以我可以帮助我的孙子(12)。

mydict2={'Atlanta':78,'Macon':85,'Savannah':72}
maxval=(max(mydict2.values()))
print(maxval)
mykey=[key for key,value in mydict2.items()if value==maxval][0]
print(mykey)
YEILDS; 
85
Macon

I had a similar problem (using 3.5) and lost 1/2 a day to it but here is a something that works – I am retired and just learning Python so I can help my grandson (12) with it.

mydict2={'Atlanta':78,'Macon':85,'Savannah':72}
maxval=(max(mydict2.values()))
print(maxval)
mykey=[key for key,value in mydict2.items()if value==maxval][0]
print(mykey)
YEILDS; 
85
Macon

回答 3

在Python2 中,该功能dictionary.iteritems()dictionary.items()Python3中的效率更高,该功能dictionary.iteritems()已迁移到dictionary.items()iteritems()已删除。因此,您将收到此错误。

dict.items()在Python3中使用,与Python2相同dict.iteritems()

In Python2, dictionary.iteritems() is more efficient than dictionary.items() so in Python3, the functionality of dictionary.iteritems() has been migrated to dictionary.items() and iteritems() is removed. So you are getting this error.

Use dict.items() in Python3 which is same as dict.iteritems() of Python2.


回答 4

这样做的目的.iteritems()是通过在循环时一次产生一个结果来使用较少的存储空间。我不确定为什么Python 3版本不支持,iteritems()尽管事实证明它比.items()

如果要包含同时支持PY版本2和3的代码,

try:
    iteritems
except NameError:
    iteritems = items

如果您在其他系统上部署项目并且不确定PY版本,这将有所帮助。

The purpose of .iteritems() was to use less memory space by yielding one result at a time while looping. I am not sure why Python 3 version does not support iteritems()though it’s been proved to be efficient than .items()

If you want to include a code that supports both the PY version 2 and 3,

try:
    iteritems
except NameError:
    iteritems = items

This can help if you deploy your project in some other system and you aren’t sure about the PY version.


回答 5

正如RafaelC回答的那样,Python 3重命名了dict.iteritems-> dict.items。尝试使用其他软件包版本。这将列出可用的软件包:

python -m pip install yourOwnPackageHere==

然后重新运行您要在==之后尝试安装/切换版本的版本

As answered by RafaelC, Python 3 renamed dict.iteritems -> dict.items. Try a different package version. This will list available packages:

python -m pip install yourOwnPackageHere==

Then rerun with the version you will try after == to install/switch version


如何在Ubuntu上通过pip安装python3版本的软件包?

问题:如何在Ubuntu上通过pip安装python3版本的软件包?

我都python2.7python3.2安装Ubuntu 12.04
符号链接python链接到python2.7

当我输入:

sudo pip install package-name

它将默认安装的python2版本package-name

一些软件包同时支持python2python3
如何安装via python3版本?package-namepip

I have both python2.7 and python3.2 installed in Ubuntu 12.04.
The symbolic link python links to python2.7.

When I type:

sudo pip install package-name

It will default install python2 version of package-name.

Some package supports both python2 and python3.
How to install python3 version of package-name via pip?


回答 0

您可能需要构建virtualenvpython3的,然后在激活virtualenv之后安装python3的软件包。这样您的系统就不会混乱了:)

可能是这样的:

virtualenv -p /usr/bin/python3 py3env
source py3env/bin/activate
pip install package-name

You may want to build a virtualenv of python3, then install packages of python3 after activating the virtualenv. So your system won’t be messed up :)

This could be something like:

virtualenv -p /usr/bin/python3 py3env
source py3env/bin/activate
pip install package-name

回答 1

Ubuntu 12.10+和Fedora 13+都有一个名为的软件包python3-pip,它将安装pip-3.2(或pip-3.3pip-3.4或者pip3对于较新的版本),而无需花钱。


我碰到了这一点,并在不需要like wget或virtualenvs的情况下解决了这个问题(假设Ubuntu 12.04):

  1. 安装软件包python3-setuptools:运行sudo aptitude install python3-setuptools,这将给您命令easy_install3
  2. 使用Python 3的setuptools安装run pip:run sudo easy_install3 pip,这将为您提供pip-3.2类似于kev解决方案的命令。
  3. 安装您的PyPI软件包:运行sudo pip-3.2 install <package>(将python软件包安装到基本系统中当然需要root)。
  4. 利润!

Ubuntu 12.10+ and Fedora 13+ have a package called python3-pip which will install pip-3.2 (or pip-3.3, pip-3.4 or pip3 for newer versions) without needing this jumping through hoops.


I came across this and fixed this without needing the likes of wget or virtualenvs (assuming Ubuntu 12.04):

  1. Install package python3-setuptools: run sudo aptitude install python3-setuptools, this will give you the command easy_install3.
  2. Install pip using Python 3’s setuptools: run sudo easy_install3 pip, this will give you the command pip-3.2 like kev’s solution.
  3. Install your PyPI packages: run sudo pip-3.2 install <package> (installing python packages into your base system requires root, of course).
  4. Profit!

回答 2

简短答案

sudo apt-get install python3-pip
sudo pip3 install MODULE_NAME

资料来源:Shashank Bharadwaj的评论

长答案

简短的答案仅适用于较新的系统。在某些版本的Ubuntu上,命令为pip-3.2

sudo pip-3.2 install MODULE_NAME

如果不起作用,则此方法适用于任何Linux发行版和受支持的版本

sudo apt-get install curl
curl https://bootstrap.pypa.io/get-pip.py | sudo python3
sudo pip3 install MODULE_NAME

如果没有curl,请使用wget。如果没有sudo,请切换到root。如果pip3symlink不存在,请检查类似pip-3的内容。X

许多python软件包也需要dev软件包,因此也要安装它:

sudo apt-get install python3-dev

来源:
python使用pip安装软件包
Pip最新安装

如果您想要更高版本的Python,也请查看Tobu的答案

我想补充一点,使用虚拟环境通常是开发python应用程序的首选方法,因此@felixyan答案可能是理想世界中的最佳选择。但是,如果您真的想在全球范围内安装该软件包,或者需要在不激活虚拟环境的情况下频繁测试/使用该软件包,那么我认为将其作为全局软件包安装是可行的方法。

Short Answer

sudo apt-get install python3-pip
sudo pip3 install MODULE_NAME

Source: Shashank Bharadwaj’s comment

Long Answer

The short answer applies only on newer systems. On some versions of Ubuntu the command is pip-3.2:

sudo pip-3.2 install MODULE_NAME

If it doesn’t work, this method should work for any Linux distro and supported version:

sudo apt-get install curl
curl https://bootstrap.pypa.io/get-pip.py | sudo python3
sudo pip3 install MODULE_NAME

If you don’t have curl, use wget. If you don’t have sudo, switch to root. If pip3 symlink does not exists, check for something like pip-3.X

Much python packages require also the dev package, so install it too:

sudo apt-get install python3-dev

Sources:
python installing packages with pip
Pip latest install

Check also Tobu’s answer if you want an even more upgraded version of Python.

I want to add that using a virtual environment is usually the preferred way to develop a python application, so @felixyan answer is probably the best in an ideal world. But if you really want to install that package globally, or if need to test / use it frequently without activating a virtual environment, I suppose installing it as a global package is the way to go.


回答 3

好吧,在ubuntu 13.10 / 14.04上,情况有所不同。

安装

$ sudo apt-get install python3-pip

安装套件

$ sudo pip3 install packagename

pip-3.3 install

Well, on ubuntu 13.10/14.04, things are a little different.

Install

$ sudo apt-get install python3-pip

Install packages

$ sudo pip3 install packagename

NOT pip-3.3 install


回答 4

安装最新pip2/ pip3和相应软件包的最简单方法:

curl https://bootstrap.pypa.io/get-pip.py | python2
pip2 install package-name    

curl https://bootstrap.pypa.io/get-pip.py | python3
pip3 install package-name

注意:请按以下方式运行这些命令root

The easiest way to install latest pip2/pip3 and corresponding packages:

curl https://bootstrap.pypa.io/get-pip.py | python2
pip2 install package-name    

curl https://bootstrap.pypa.io/get-pip.py | python3
pip3 install package-name

Note: please run these commands as root


回答 5

尝试安装pylab时遇到了同样的问题,并且找到了此链接

因此,我在Python 3中安装pylab所做的工作是:

python3 -m pip install SomePackage

它运行正常,并且如您在链接中所见,您可以为每个Python版本执行此操作,因此我想这可以解决您的问题。

I had the same problem while trying to install pylab, and I have found this link

So what I have done to install pylab within Python 3 is:

python3 -m pip install SomePackage

It has worked properly, and as you can see in the link you can do this for every Python version you have, so I guess this solves your problem.


回答 6

旧的问题,但没有一个答案令我满意。我的系统之一正在运行Ubuntu 12.04 LTS,由于某种原因,没有软件包python3-pippython-pipPython3。所以这就是我所做的(所有命令均以root用户身份执行):

  • setuptools如果没有,请安装Python3。

    apt-get install python3-setuptools

    要么

    aptitude install python3-setuptools
  • 在Python 2.4+中,您可以使用调用easy_install特定的Python版本python -m easy_install。因此,pip对于Python 3,可以通过以下方式安装:

    python3 -m easy_install pip
  • 就是这样,您使用的是pipPython3。现在只需调用pip特定版本的Python即可安装Python 3的软件包。例如,在系统上安装了Python 3.2的情况下,我使用了:

    pip-3.2 install [package]

Old question, but none of the answers satisfies me. One of my systems is running Ubuntu 12.04 LTS and for some reason there’s no package python3-pip or python-pip for Python 3. So here is what I’ve done (all commands were executed as root):

  • Install setuptools for Python3 in case you haven’t.

    apt-get install python3-setuptools
    

    or

    aptitude install python3-setuptools
    
  • With Python 2.4+ you can invoke easy_install with specific Python version by using python -m easy_install. So pip for Python 3 could be installed by:

    python3 -m easy_install pip
    
  • That’s it, you got pip for Python 3. Now just invoke pip with the specific version of Python to install package for Python 3. For example, with Python 3.2 installed on my system, I used:

    pip-3.2 install [package]
    

回答 7

如果您在两个python中都安装了pip,并且都在路径中,则只需使用:

$ pip-2.7 install PACKAGENAME
$ pip-3.2 install PACKAGENAME

参考文献:

这是问题的重复#2812520

If you have pip installed in both pythons, and both are in your path, just use:

$ pip-2.7 install PACKAGENAME
$ pip-3.2 install PACKAGENAME

References:

This is a duplicate of question #2812520


回答 8

如果您的系统python2是默认设置,请使用以下命令将软件包安装到python3

$ python3 -m pip install <package-name>

If your system has python2 as default, use below command to install packages to python3

$ python3 -m pip install <package-name>


回答 9

很简单:

sudo aptitude install python3-pip
pip-3.2 install --user pkg

如果要使用Python 3.3(自Ubuntu 12.10起不是默认设置):

sudo aptitude install python3-pip python3.3
python3.3 -m pip.runner install --user pkg

Easy enough:

sudo aptitude install python3-pip
pip-3.2 install --user pkg

If you want Python 3.3, which isn’t the default as of Ubuntu 12.10:

sudo aptitude install python3-pip python3.3
python3.3 -m pip.runner install --user pkg

回答 10

您也可以直接运行pip3 install packagename,而不是pip

You can alternatively just run pip3 install packagename instead of pip,


回答 11

首先,您需要为想要的Python 3安装安装pip。然后,您运行该pip为该Python版本安装软件包。

由于您在/ usr / bin中同时拥有pip和python 3,因此我假定它们都已通过某种程序包管理器安装。该软件包管理器还应具有Python 3点。那是您应该安装的那个。

Felix对virtualenv的推荐是一个很好的建议。如果您只是测试,或者正在开发,则不应将软件包安装在系统python中。在这些情况下,使用virtualenv甚至构建自己的Python进行开发会更好。

但如果你真的希望在系统Python安装该软件包,为Python 3安装PIP是要走的路。

Firstly, you need to install pip for the Python 3 installation that you want. Then you run that pip to install packages for that Python version.

Since you have both pip and python 3 in /usr/bin, I assume they are both installed with a package manager of some sort. That package manager should also have a Python 3 pip. That’s the one you should install.

Felix’ recommendation of virtualenv is a good one. If you are only testing, or you are doing development, then you shouldn’t install the package in the system python. Using virtualenv, or even building your own Pythons for development, is better in those cases.

But if you actually do want to install this package in the system python, installing pip for Python 3 is the way to go.


回答 12

尽管该问题与Ubuntu有关,但我还是要说我在Mac上,而我的python命令默认为Python 2.7.5。我也有Python 3,可通过进行访问python3,因此知道了pip包的起源,我就下载了pip包并sudo python3 setup.py install针对它发布了,当然,只有Python 3现在在其站点包中包含了此模块。希望这有助于流浪的Mac陌生人。

Although the question relates to Ubuntu, let me contribute by saying that I’m on Mac and my python command defaults to Python 2.7.5. I have Python 3 as well, accessible via python3, so knowing the pip package origin, I just downloaded it and issued sudo python3 setup.py install against it and, surely enough, only Python 3 has now this module inside its site packages. Hope this helps a wandering Mac-stranger.


回答 13

直接执行pip二进制文件。

首先找到所需的PIP版本。

jon-mint python3.3 # whereis ip
ip: /bin/ip /sbin/ip /usr/share/man/man8/ip.8.gz /usr/share/man/man7/ip.7.gz

然后执行。

jon-mint python3.3 # pip3.3 install pexpect
Downloading/unpacking pexpect
  Downloading pexpect-3.2.tar.gz (131kB): 131kB downloaded
  Running setup.py (path:/tmp/pip_build_root/pexpect/setup.py) egg_info for package pexpect

Installing collected packages: pexpect
  Running setup.py install for pexpect

Successfully installed pexpect
Cleaning up...

Execute the pip binary directly.

First locate the version of PIP you want.

jon-mint python3.3 # whereis ip
ip: /bin/ip /sbin/ip /usr/share/man/man8/ip.8.gz /usr/share/man/man7/ip.7.gz

Then execute.

jon-mint python3.3 # pip3.3 install pexpect
Downloading/unpacking pexpect
  Downloading pexpect-3.2.tar.gz (131kB): 131kB downloaded
  Running setup.py (path:/tmp/pip_build_root/pexpect/setup.py) egg_info for package pexpect

Installing collected packages: pexpect
  Running setup.py install for pexpect

Successfully installed pexpect
Cleaning up...

回答 14

  1. 您应该安装所有依赖项:

    sudo apt-get install build-essential python3-dev python3-setuptools python3-numpy python3-scipy libatlas-dev libatlas3gf-base

  2. 安装pip3(如果已安装,请查看步骤3):

    sudo apt-get install python3-pip

  3. 我通过pip3安装scikit-learn

    pip3 install -U scikit-learn

  4. 打开您的终端并输入python3环境,键入import sklearn以进行检查。

祝你好运!

  1. You should install ALL dependencies:

    sudo apt-get install build-essential python3-dev python3-setuptools python3-numpy python3-scipy libatlas-dev libatlas3gf-base

  2. Install pip3(if you have installed, please look step 3):

    sudo apt-get install python3-pip

  3. Iinstall scikit-learn by pip3

    pip3 install -U scikit-learn

  4. Open your terminal and entry python3 environment, type import sklearn to check it.

Gook Luck!


回答 15

要为python3安装pip,请使用pip3而不是pip。在Ubuntu 18.08 Bionic中安装python

须藤apt-get install python3.7

在ubuntu中安装所需的pip软件包

须藤apt-get install python3-pip

To install pip for python3 use should use pip3 instead of pip. To install python in ubuntu 18.08 bionic

sudo apt-get install python3.7

To install the required pip package in ubuntu

sudo apt-get install python3-pip


回答 16

安装python3的另一种方法是使用wget。以下是安装步骤。

wget http://www.python.org/ftp/python/3.3.5/Python-3.3.5.tar.xz
tar xJf ./Python-3.3.5.tar.xz
cd ./Python-3.3.5
./configure --prefix=/opt/python3.3
make && sudo make install

另外,可以使用

echo 'alias py="/opt/python3.3/bin/python3.3"' >> ~/.bashrc

现在打开一个新终端并输入py并按Enter。

Another way to install python3 is using wget. Below are the steps for installation.

wget http://www.python.org/ftp/python/3.3.5/Python-3.3.5.tar.xz
tar xJf ./Python-3.3.5.tar.xz
cd ./Python-3.3.5
./configure --prefix=/opt/python3.3
make && sudo make install

Also,one can create an alias for the same using

echo 'alias py="/opt/python3.3/bin/python3.3"' >> ~/.bashrc

Now open a new terminal and type py and press Enter.


如何指定方法的返回类型与类本身相同?

问题:如何指定方法的返回类型与类本身相同?

我在python 3中有以下代码:

class Position:

    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

    def __add__(self, other: Position) -> Position:
        return Position(self.x + other.x, self.y + other.y)

但是我的编辑器(PyCharm)说,参考位置无法解析(在__add__方法中)。我应该如何指定期望返回类型为type Position

编辑:我认为这实际上是一个PyCharm问题。它实际上在警告和代码完成中使用该信息

但如果我错了,请纠正我,并需要使用其他语法。

I have the following code in python 3:

class Position:

    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

    def __add__(self, other: Position) -> Position:
        return Position(self.x + other.x, self.y + other.y)

But my editor (PyCharm) says that the reference Position can not be resolved (in the __add__ method). How should I specify that I expect the return type to be of type Position?

Edit: I think this is actually a PyCharm issue. It actually uses the information in its warnings, and code completion

But correct me if I’m wrong, and need to use some other syntax.


回答 0

TL; DR:如果您使用的是Python 4.0,它将正常工作。从今天(2019年)开始,在3.7+中,您必须使用将来的语句(from __future__ import annotations)启用此功能-对于Python 3.6或更低版本,请使用字符串。

我猜你有这个exceptions:

NameError: name 'Position' is not defined

这是因为Position必须先定义,然后才能在批注中使用它,除非您正在使用Python 4。

Python 3.7+: from __future__ import annotations

Python 3.7引入了PEP 563:推迟对注释的评估。使用future语句的模块from __future__ import annotations将自动将注释存储为字符串:

from __future__ import annotations

class Position:
    def __add__(self, other: Position) -> Position:
        ...

按计划,它将成为Python 4.0中的默认设置。由于Python仍然是一种动态类型化的语言,因此在运行时不进行类型检查,因此键入注释应该不会对性能产生影响,对吗?错误!在python 3.7之前,键入模块曾经是内核中最慢的python模块之一,因此,如果升级到3.7,import typing您将看到性能提高多达7倍

Python <3.7:使用字符串

根据PEP 484,您应该使用字符串而不是类本身:

class Position:
    ...
    def __add__(self, other: 'Position') -> 'Position':
       ...

如果您使用Django框架,可能会很熟悉,因为Django模型还将字符串用于正向引用(外键模型已self声明或尚未声明的外键定义)。这应该与Pycharm和其他工具一起使用。

资料来源

PEP 484PEP 563的相关部分,为您节省行程:

转发参考

当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,稍后再解析。

通常会发生这种情况的情况是容器类的定义,其中定义的类出现在某些方法的签名中。例如,以下代码(简单的二叉树实现的开始)不起作用:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right

为了解决这个问题,我们写:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

字符串文字应包含有效的Python表达式(即,compile(lit,”,’eval’)应为有效的代码对象),并且在模块完全加载后,其值应无错误。在其中评估本地和全局命名空间的命名空间应与在其中评估同一函数的默认参数的命名空间相同。

和PEP 563:

在Python 4.0中,将不再在定义时评估函数和变量注释。而是将字符串形式保留在相应的__annotations__字典中。静态类型检查器在行为上不会有任何区别,而在运行时使用批注的工具将必须执行推迟的评估。

可以使用以下特殊导入从Python 3.7开始启用上述功能:

from __future__ import annotations

您可能会想做的事情

A.定义一个假人 Position

在类定义之前,放置一个虚拟定义:

class Position(object):
    pass


class Position(object):
    ...

这样可以摆脱NameError甚至看起来还可以:

>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}

但是吗?

>>> for k, v in Position.__add__.__annotations__.items():
...     print(k, 'is Position:', v is Position)                                                                                                                                                                                                                  
return is Position: False
other is Position: False

B. Monkey-patch为了添加注释:

您可能想尝试一些Python元编程魔术,并编写装饰器以Monkey修补类定义,以便添加注释:

class Position:
    ...
    def __add__(self, other):
        return self.__class__(self.x + other.x, self.y + other.y)

装饰者应对此负责:

Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position

至少看起来是正确的:

>>> for k, v in Position.__add__.__annotations__.items():
...     print(k, 'is Position:', v is Position)                                                                                                                                                                                                                  
return is Position: True
other is Position: True

可能麻烦太多了。

结论

如果您使用的是3.6或更低版本,请使用包含类名的字符串文字,在3.7中使用from __future__ import annotations它就可以了。

TL;DR: if you are using Python 4.0 it just works. As of today (2019) in 3.7+ you must turn this feature on using a future statement (from __future__ import annotations) – for Python 3.6 or below use a string.

I guess you got this exception:

NameError: name 'Position' is not defined

This is because Position must be defined before you can use it in an annotation unless you are using Python 4.

Python 3.7+: from __future__ import annotations

Python 3.7 introduces PEP 563: postponed evaluation of annotations. A module that uses the future statement from __future__ import annotations will store annotations as strings automatically:

from __future__ import annotations

class Position:
    def __add__(self, other: Position) -> Position:
        ...

This is scheduled to become the default in Python 4.0. Since Python still is a dynamically typed language so no type checking is done at runtime, typing annotations should have no performance impact, right? Wrong! Before python 3.7 the typing module used to be one of the slowest python modules in core so if you import typing you will see up to 7 times increase in performance when you upgrade to 3.7.

Python <3.7: use a string

According to PEP 484, you should use a string instead of the class itself:

class Position:
    ...
    def __add__(self, other: 'Position') -> 'Position':
       ...

If you use the Django framework this may be familiar as Django models also use strings for forward references (foreign key definitions where the foreign model is self or is not declared yet). This should work with Pycharm and other tools.

Sources

The relevant parts of PEP 484 and PEP 563, to spare you the trip:

Forward references

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.

A situation where this occurs commonly is the definition of a container class, where the class being defined occurs in the signature of some of the methods. For example, the following code (the start of a simple binary tree implementation) does not work:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right

To address this, we write:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

The string literal should contain a valid Python expression (i.e., compile(lit, ”, ‘eval’) should be a valid code object) and it should evaluate without errors once the module has been fully loaded. The local and global namespace in which it is evaluated should be the same namespaces in which default arguments to the same function would be evaluated.

and PEP 563:

In Python 4.0, function and variable annotations will no longer be evaluated at definition time. Instead, a string form will be preserved in the respective __annotations__ dictionary. Static type checkers will see no difference in behavior, whereas tools using annotations at runtime will have to perform postponed evaluation.

The functionality described above can be enabled starting from Python 3.7 using the following special import:

from __future__ import annotations

Things that you may be tempted to do instead

A. Define a dummy Position

Before the class definition, place a dummy definition:

class Position(object):
    pass


class Position(object):
    ...

This will get rid of the NameError and may even look OK:

>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}

But is it?

>>> for k, v in Position.__add__.__annotations__.items():
...     print(k, 'is Position:', v is Position)                                                                                                                                                                                                                  
return is Position: False
other is Position: False

B. Monkey-patch in order to add the annotations:

You may want to try some Python meta programming magic and write a decorator to monkey-patch the class definition in order to add annotations:

class Position:
    ...
    def __add__(self, other):
        return self.__class__(self.x + other.x, self.y + other.y)

The decorator should be responsible for the equivalent of this:

Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position

At least it seems right:

>>> for k, v in Position.__add__.__annotations__.items():
...     print(k, 'is Position:', v is Position)                                                                                                                                                                                                                  
return is Position: True
other is Position: True

Probably too much trouble.

Conclusion

If you are using 3.6 or below use a string literal containing the class name, in 3.7 use from __future__ import annotations and it will just work.


回答 1

将类型指定为字符串是可以的,但总是让我有些讨厌,因为我们基本上是在绕过解析器。因此,您最好不要拼写以下任何文字字符串:

def __add__(self, other: 'Position') -> 'Position':
    return Position(self.x + other.x, self.y + other.y)

有一个细微的变化是使用绑定的typevar,至少在声明typevar时,您只需编写一次字符串即可:

from typing import TypeVar

T = TypeVar('T', bound='Position')

class Position:

    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

    def __add__(self, other: T) -> T:
        return Position(self.x + other.x, self.y + other.y)

Specifying the type as string is fine, but always grates me a bit that we are basically circumventing the parser. So you better not misspell any one of these literal strings:

def __add__(self, other: 'Position') -> 'Position':
    return Position(self.x + other.x, self.y + other.y)

A slight variation is to use a bound typevar, at least then you have to write the string only once when declaring the typevar:

from typing import TypeVar

T = TypeVar('T', bound='Position')

class Position:

    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

    def __add__(self, other: T) -> T:
        return Position(self.x + other.x, self.y + other.y)

回答 2

在解析类主体本身时,名称“ Position”不可用。我不知道您如何使用类型声明,但是Python的PEP 484-如果使用这些键入提示表示您可以在此时将名称简单地作为字符串,这是大多数模式应使用的方式:

def __add__(self, other: 'Position') -> 'Position':
    return Position(self.x + other.x, self.y + other.y)

检查https://www.python.org/dev/peps/pep-0484/#forward-references-符合该要求的工具将知道从那里解包并使用类名。(请记住,Python语言本身不执行任何这些注释-它们通常用于静态代码分析,或者可以具有一个库/框架以在运行时进行类型检查-但您必须明确地进行设置。

更新此外,从Python 3.8开始,请检查pep-563-从Python 3.8开始,可以编写from __future__ import annotations以推迟对批注的求值-前向引用类应简单易用。

The name ‘Position’ is not avalilable at the time the class body itself is parsed. I don’t know how you are using the type declarations, but Python’s PEP 484 – which is what most mode should use if using these typing hints say that you can simply put the name as a string at this point:

def __add__(self, other: 'Position') -> 'Position':
    return Position(self.x + other.x, self.y + other.y)

Check https://www.python.org/dev/peps/pep-0484/#forward-references – tools conforming to that will know to unwrap the class name from there and make use of it.(It is always important to have in mind that the Python language itself does nothing of these annotations – they are usually meant for static-code analysis, or one could have a library/framework for type checking in run-time – but you have to explicitly set that).

update Also, as of Python 3.8, check pep-563 – as of Python 3.8 it is possible to write from __future__ import annotations to defer the evaluation of annotations – forward referencing classes should work straightforward.


回答 3

当基于字符串的类型提示可接受时,__qualname__也可以使用该项目。它包含类的名称,并且在类定义的主体中可用。

class MyClass:
    @classmethod
    def make_new(cls) -> __qualname__:
        return cls()

这样,重命名类并不意味着修改类型提示。但是我个人并不希望智能代码编辑器能够很好地处理这种形式。

When a string-based type hint is acceptable, the __qualname__ item can also be used. It holds the name of the class, and it is available in the body of the class definition.

class MyClass:
    @classmethod
    def make_new(cls) -> __qualname__:
        return cls()

By doing this, renaming the class does not imply modifying the type hints. But I personally would not expect smart code editors to handle this form well.


在Python 3中将字符串转换为字节的最佳方法?

问题:在Python 3中将字符串转换为字节的最佳方法?

TypeError的答案中可以看出,有两种不同的方法可以将字符串转换为字节:’str’不支持缓冲区接口

以下哪种方法更好或更Pythonic?还是仅仅是个人喜好问题?

b = bytes(mystring, 'utf-8')

b = mystring.encode('utf-8')

There appear to be two different ways to convert a string to bytes, as seen in the answers to TypeError: ‘str’ does not support the buffer interface

Which of these methods would be better or more Pythonic? Or is it just a matter of personal preference?

b = bytes(mystring, 'utf-8')

b = mystring.encode('utf-8')

回答 0

如果您查看的文档bytes,它将指向bytearray

bytearray([源[,编码[,错误]]])

返回一个新的字节数组。字节数组类型是一个可变的整数序列,范围为0 <= x <256。它具有可变序列类型中介绍的大多数可变序列的常用方法,以及字节类型具有的大多数方法,请参见字节和。字节数组方法。

可选的source参数可以通过几种不同的方式用于初始化数组:

如果是字符串,则还必须提供编码(以及可选的错误)参数;然后,bytearray()使用str.encode()将字符串转换为字节。

如果它是整数,则数组将具有该大小,并将使用空字节初始化。

如果它是符合缓冲区接口的对象,则该对象的只读缓冲区将用于初始化bytes数组。

如果是可迭代的,则它必须是0 <= x <256范围内的整数的可迭代对象,这些整数用作数组的初始内容。

没有参数,将创建大小为0的数组。

所以 bytes除了编码字符串以外,还可以做更多的事情。这是Pythonic的用法,它允许您使用有意义的任何类型的源参数来调用构造函数。

对于编码字符串,我认为它some_string.encode(encoding)比使用构造函数更具Pythonic性,因为它是最易于记录的文档-“使用此字符串并使用此编码对其进行编码”比bytes(some_string, encoding) – -当您使用构造函数。

编辑:我检查了Python源。如果您将unicode字符串传递给bytes使用CPython,它将调用PyUnicode_AsEncodedString,它是encode; 的实现。因此,如果您自称,则只是跳过了间接级别encode

另外,请参见Serdalis的评论- unicode_string.encode(encoding)也是Python 风格的,因为它的反函数为byte_string.decode(encoding),对称性很好。

If you look at the docs for bytes, it points you to bytearray:

bytearray([source[, encoding[, errors]]])

Return a new array of bytes. The bytearray type is a mutable sequence of integers in the range 0 <= x < 256. It has most of the usual methods of mutable sequences, described in Mutable Sequence Types, as well as most methods that the bytes type has, see Bytes and Byte Array Methods.

The optional source parameter can be used to initialize the array in a few different ways:

If it is a string, you must also give the encoding (and optionally, errors) parameters; bytearray() then converts the string to bytes using str.encode().

If it is an integer, the array will have that size and will be initialized with null bytes.

If it is an object conforming to the buffer interface, a read-only buffer of the object will be used to initialize the bytes array.

If it is an iterable, it must be an iterable of integers in the range 0 <= x < 256, which are used as the initial contents of the array.

Without an argument, an array of size 0 is created.

So bytes can do much more than just encode a string. It’s Pythonic that it would allow you to call the constructor with any type of source parameter that makes sense.

For encoding a string, I think that some_string.encode(encoding) is more Pythonic than using the constructor, because it is the most self documenting — “take this string and encode it with this encoding” is clearer than bytes(some_string, encoding) — there is no explicit verb when you use the constructor.

Edit: I checked the Python source. If you pass a unicode string to bytes using CPython, it calls PyUnicode_AsEncodedString, which is the implementation of encode; so you’re just skipping a level of indirection if you call encode yourself.

Also, see Serdalis’ comment — unicode_string.encode(encoding) is also more Pythonic because its inverse is byte_string.decode(encoding) and symmetry is nice.


回答 1

比想像的要容易:

my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation

It’s easier than it is thought:

my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation

回答 2

绝对最好的办法既不是2,但第3位。自Python 3.0以来,第一个参数默认默认值。因此,最好的方法是encode 'utf-8'

b = mystring.encode()

这也将更快,因为默认参数的结果不是"utf-8"C代码中的字符串,而是NULL,它的检查快得多!

以下是一些时间安排:

In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop

In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop

尽管发出警告,但重复运行后时间仍然非常稳定-偏差仅为〜2%。


encode()不带参数使用不兼容Python 2,因为在Python 2中,默认字符编码为ASCII

>>> 'äöä'.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

The absolutely best way is neither of the 2, but the 3rd. The first parameter to encode defaults to 'utf-8' ever since Python 3.0. Thus the best way is

b = mystring.encode()

This will also be faster, because the default argument results not in the string "utf-8" in the C code, but NULL, which is much faster to check!

Here be some timings:

In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop

In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop

Despite the warning the times were very stable after repeated runs – the deviation was just ~2 per cent.


Using encode() without an argument is not Python 2 compatible, as in Python 2 the default character encoding is ASCII.

>>> 'äöä'.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

如何复制字典并仅编辑副本

问题:如何复制字典并仅编辑副本

有人可以向我解释一下吗?这对我来说毫无意义。

我将字典复制到另一个字典中,然后编辑第二个字典,并且两者都已更改。为什么会这样呢?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

Can someone please explain this to me? This doesn’t make any sense to me.

I copy a dictionary into another and edit the second and both are changed. Why is this happening?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

回答 0

Python 绝不会隐式复制对象。设置时dict2 = dict1,将使它们引用同一精确的dict对象,因此,在对它进行突变时,对其的所有引用都将始终引用该对象的当前状态。

如果要复制字典(这种情况很少见),则必须使用

dict2 = dict(dict1)

要么

dict2 = dict1.copy()

Python never implicitly copies objects. When you set dict2 = dict1, you are making them refer to the same exact dict object, so when you mutate it, all references to it keep referring to the object in its current state.

If you want to copy the dict (which is rare), you have to do so explicitly with

dict2 = dict(dict1)

or

dict2 = dict1.copy()

回答 1

分配时dict2 = dict1,您并没有复制该文件的副本dict1,导致dict2它只是它的另一个名称dict1

要复制字典等可变类型,请使用copy/ deepcopycopy模块。

import copy

dict2 = copy.deepcopy(dict1)

When you assign dict2 = dict1, you are not making a copy of dict1, it results in dict2 being just another name for dict1.

To copy the mutable types like dictionaries, use copy / deepcopy of the copy module.

import copy

dict2 = copy.deepcopy(dict1)

回答 2

虽然dict.copy()dict(dict1)生成副本,但它们只是浅表副本。如果要拷贝,copy.deepcopy(dict1)则是必需的。一个例子:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

关于浅层副本与深层副本,来自Python copy模块docs

浅表复制和深度复制之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)有关:

  • 浅表副本构造一个新的复合对象,然后(在可能的范围内)将对原始对象中找到的对象的引用插入其中。
  • 深层副本将构造一个新的复合对象,然后递归地将原始对象中发现的对象的副本插入其中。

While dict.copy() and dict(dict1) generates a copy, they are only shallow copies. If you want a deep copy, copy.deepcopy(dict1) is required. An example:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

Regarding shallow vs deep copies, from the Python copy module docs:

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

回答 3

在python 3.5+上,有一种更简单的方法可以通过使用**解包运算符来实现浅表副本。由Pep 448定义。

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

**将字典解包为新字典,然后将其分配给dict2。

我们还可以确认每个词典都有不同的ID。

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

如果需要深层副本,那么仍然可以使用copy.deepcopy()

On python 3.5+ there is an easier way to achieve a shallow copy by using the ** unpackaging operator. Defined by Pep 448.

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

** unpackages the dictionary into a new dictionary that is then assigned to dict2.

We can also confirm that each dictionary has a distinct id.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

If a deep copy is needed then copy.deepcopy() is still the way to go.


回答 4

最好的和最简单的方法创建一个副本一个的字典中都Python的2.7和3是…

要创建简单(单级)字典的副本:

1.使用dict()方法,而不是生成指向现有dict的引用。

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2.使用python字典的内置update()方法。

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

要创建嵌套或复杂字典的副本:

使用内置的复制模块,该模块提供通用的浅层和深层复制操作。Python 2.7和3中都提供了此模块。*

import copy

my_dict2 = copy.deepcopy(my_dict1)

The best and the easiest ways to create a copy of a dict in both Python 2.7 and 3 are…

To create a copy of simple(single-level) dictionary:

1. Using dict() method, instead of generating a reference that points to the existing dict.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. Using the built-in update() method of python dictionary.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

To create a copy of nested or complex dictionary:

Use the built-in copy module, which provides a generic shallow and deep copy operations. This module is present in both Python 2.7 and 3.*

import copy

my_dict2 = copy.deepcopy(my_dict1)

回答 5

您也可以使用字典理解功能来制作新字典。这样可以避免导入副本。

dout = dict((k,v) for k,v in mydict.items())

当然,在python> = 2.7中,您可以执行以下操作:

dout = {k:v for k,v in mydict.items()}

但是对于向后兼容,顶级方法更好。

You can also just make a new dictionary with a dictionary comprehension. This avoids importing copy.

dout = dict((k,v) for k,v in mydict.items())

Of course in python >= 2.7 you can do:

dout = {k:v for k,v in mydict.items()}

But for backwards compat., the top method is better.


回答 6

除了提供的其他解决方案外,您还可以**将字典集成到一个空字典中,例如,

shallow_copy_of_other_dict = {**other_dict}

现在,您将拥有的“浅”副本other_dict

应用于您的示例:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>

指针:浅拷贝和深拷贝之间的区别

In addition to the other provided solutions, you can use ** to integrate the dictionary into an empty dictionary, e.g.,

shallow_copy_of_other_dict = {**other_dict}.

Now you will have a “shallow” copy of other_dict.

Applied to your example:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>

Pointer: Difference between shallow and deep copys


回答 7

Python中的赋值语句不复制对象,它们在目标和对象之间创建绑定。

因此,dict2 = dict1它会在dict2dict1引用的对象之间产生另一个绑定。

如果要复制字典,可以使用copy module。复制模块有两个接口:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

浅表复制和深度复制之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)有关:

浅拷贝构造新化合物对象,然后(在可能的范围)插入到它的对象引用原始发现。

深层副本构造新化合物的对象,然后,递归地,插入拷贝到它的目的在原始发现。

例如,在python 2.7.9中:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

结果是:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]

Assignment statements in Python do not copy objects, they create bindings between a target and an object.

so, dict2 = dict1, it results another binding between dict2and the object that dict1 refer to.

if you want to copy a dict, you can use the copy module. The copy module has two interface:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

For example, in python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

and the result is:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]

回答 8

您可以通过dict使用其他关键字参数调用构造函数来一次性复制和编辑新构造的副本:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

You can copy and edit the newly constructed copy in one go by calling the dict constructor with additional keyword arguments:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

回答 9

最初,这也使我感到困惑,因为我来自C语言。

在C语言中,变量是内存中定义类型的位置。分配给变量会将数据复制到变量的存储位置。

但是在Python中,变量的作用更像是指向对象的指针。因此,将一个变量分配给另一个变量不会产生副本,只会使该变量名称指向同一对象。

This confused me too, initially, because I was coming from a C background.

In C, a variable is a location in memory with a defined type. Assigning to a variable copies the data into the variable’s memory location.

But in Python, variables act more like pointers to objects. So assigning one variable to another doesn’t make a copy, it just makes that variable name point to the same object.


回答 10

python中的每个变量(类似于dict1str或的东西__builtins__都是指向机器内部某些隐藏的柏拉图“对象”的指针。

如果设置dict1 = dict2,则只需指向dict1与相同的对象(或内存位置,或类似的对象)dict2。现在,所引用的对象与所引用的对象dict1相同dict2

您可以检查:dict1 is dict2应该是True。另外,id(dict1)应与相同id(dict2)

您想要dict1 = copy(dict2)dict1 = deepcopy(dict2)

copy和之间的区别deepcopydeepcopy将确保dict2(您是否将其指向列表?)的元素也是副本。

我用的不是deepcopy很多-在我看来,编写需要它的代码通常是不明智的做法。

Every variable in python (stuff like dict1 or str or __builtins__ is a pointer to some hidden platonic “object” inside the machine.

If you set dict1 = dict2,you just point dict1 to the same object (or memory location, or whatever analogy you like) as dict2. Now, the object referenced by dict1 is the same object referenced by dict2.

You can check: dict1 is dict2 should be True. Also, id(dict1) should be the same as id(dict2).

You want dict1 = copy(dict2), or dict1 = deepcopy(dict2).

The difference between copy and deepcopy? deepcopy will make sure that the elements of dict2 (did you point it at a list?) are also copies.

I don’t use deepcopy much – it’s usually poor practice to write code that needs it (in my opinion).


回答 11

dict1是引用基础字典对象的符号。分配dict1dict2仅分配相同的参考。通过dict2符号更改键的值会更改基础对象,这也会影响dict1。这很混乱。

关于不可变值的推理要比引用容易得多,因此请尽可能制作副本:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

在语法上与以下内容相同:

one_year_later = dict(person, age=26)

dict1 is a symbol that references an underlying dictionary object. Assigning dict1 to dict2 merely assigns the same reference. Changing a key’s value via the dict2 symbol changes the underlying object, which also affects dict1. This is confusing.

It is far easier to reason about immutable values than references, so make copies whenever possible:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

This is syntactically the same as:

one_year_later = dict(person, age=26)

回答 12

dict2 = dict1不复制字典。它只是为程序员提供了第二种方法(dict2)来引用同一词典。

dict2 = dict1 does not copy the dictionary. It simply gives you the programmer a second way (dict2) to refer to the same dictionary.


回答 13

>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

复制Dict对象的方法很多,我只是简单地使用

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

There are many ways to copy Dict object, I simply use

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)

回答 14

正如其他人所解释的,内置dict功能无法满足您的需求。但是在Python2中(可能还有3个),您可以轻松地创建一个ValueDict用于复制的类,=因此可以确保原始版本不会更改。

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

请参考此处讨论的左值修改模式:Python 2.7-左值修改的纯语法。关键的观察是,strint表现为在Python值(即使它们实际上是引擎盖下的不可变对象)。当您观察到这一点时,也请注意,关于str或,没有什么神奇的特别之处intdict可以以几乎相同的方式使用,我可以想到很多ValueDict有意义的情况。

As others have explained, the built-in dict does not do what you want. But in Python2 (and probably 3 too) you can easily create a ValueDict class that copies with = so you can be sure that the original will not change.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

Please refer to the lvalue modification pattern discussed here: Python 2.7 – clean syntax for lvalue modification. The key observation is that str and int behave as values in Python (even though they’re actually immutable objects under the hood). While you’re observing that, please also observe that nothing is magically special about str or int. dict can be used in much the same ways, and I can think of many cases where ValueDict makes sense.


回答 15

以下代码,是遵循json语法的字典的,比deepcopy快3倍以上

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)

the following code, which is on dicts which follows json syntax more than 3 times faster than deepcopy

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)

回答 16

尝试深复制类w / o将其分配给变量的字典属性时,遇到了一种特殊的行为

new = copy.deepcopy(my_class.a)不起作用,即修改new修改my_class.a

但是,如果您这样做old = my_class.a,那么new = copy.deepcopy(old)它会完美运行,即修改new不会影响my_class.a

我不确定为什么会发生这种情况,但希望它可以节省一些时间!:)

i ran into a peculiar behavior when trying to deep copy dictionary property of class w/o assigning it to variable

new = copy.deepcopy(my_class.a) doesn’t work i.e. modifying new modifies my_class.a

but if you do old = my_class.a and then new = copy.deepcopy(old) it works perfectly i.e. modifying new does not affect my_class.a

I am not sure why this happens, but hope it helps save some hours! :)


回答 17

因为dict2 = dict1,dict2保存了对dict1的引用。dict1和dict2都指向内存中的同一位置。这是在python中使用可变对象时的正常情况。使用python中的可变对象时,必须小心,因为它很难调试。如下面的例子。

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

此示例意图是获取所有用户ID,包括被阻止的ID。我们是从ids变量获得的,但是我们也无意间更新了my_users的值。当你扩展的IDSblocked_ids my_users得到了更新,因为IDS参考my_users

because, dict2 = dict1, dict2 holds the reference to dict1. Both dict1 and dict2 points to the same location in the memory. This is just a normal case while working with mutable objects in python. When you are working with mutable objects in python you must be careful as it is hard to debug. Such as the following example.

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

This example intention is to get all the user ids including blocked ids. That we got from ids variable but we also updated the value of my_users unintentionally. when you extended the ids with blocked_ids my_users got updated because ids refer to my_users.


回答 18

使用for循环进行复制:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

Copying by using a for loop:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

回答 19

您可以直接使用:

dict2 = eval(repr(dict1))

其中对象dict2是dict1的独立副本,因此您可以修改dict2而不会影响dict1。

这适用于任何类型的对象。

You can use directly:

dict2 = eval(repr(dict1))

where object dict2 is an independent copy of dict1, so you can modify dict2 without affecting dict1.

This works for any kind of object.


我应该放#!(shebang)在Python脚本中,它应该采用什么形式?

问题:我应该放#!(shebang)在Python脚本中,它应该采用什么形式?

我应该把shebang放到我的Python脚本中吗?以什么形式?

#!/usr/bin/env python 

要么

#!/usr/local/bin/python

这些同样便携吗?最常用哪种形式?

注:龙卷风项目采用的家当。另一方面, Django项目没有。

Should I put the shebang in my Python scripts? In what form?

#!/usr/bin/env python 

or

#!/usr/local/bin/python

Are these equally portable? Which form is used most?

Note: the tornado project uses the shebang. On the other hand the Django project doesn’t.


回答 0

任何脚本中的shebang行都决定了脚本的执行能力,就像独立的可执行文件一样,无需python事先在终端中键入或在文件管理器中双击(正确配置时)。不必要,但通常放在那里,因此当有人看到在编辑器中打开文件时,他们会立即知道他们在看什么。但是,您使用的家当线IS重要。

Python 3脚本的正确用法是:

#!/usr/bin/env python3

默认为版本3.latest。对于Python 2.7.latest python2代替python3

不应使用以下内容(除了极少数情况下,您正在编写与Python 2.x和3.x兼容的代码):

#!/usr/bin/env python

中给出的原因是这些建议,PEP 394,是python可以指到python2python3在不同的系统。目前,它python2在大多数发行版中都涉及,但是在某些时候可能会改变。

另外,请勿使用:

#!/usr/local/bin/python

“在这种情况下,python可能安装在/ usr / bin / python或/ bin / python上,上述#!将失败。”

“#!/ usr / bin / env python”与“#!/ usr / local / bin / python”

The shebang line in any script determines the script’s ability to be executed like a standalone executable without typing python beforehand in the terminal or when double clicking it in a file manager (when configured properly). It isn’t necessary but generally put there so when someone sees the file opened in an editor, they immediately know what they’re looking at. However, which shebang line you use IS important.

Correct usage for Python 3 scripts is:

#!/usr/bin/env python3

This defaults to version 3.latest. For Python 2.7.latest use python2 in place of python3.

The following should NOT be used (except for the rare case that you are writing code which is compatible with both Python 2.x and 3.x):

#!/usr/bin/env python

The reason for these recommendations, given in PEP 394, is that python can refer either to python2 or python3 on different systems. It currently refers to python2 on most distributions, but that is likely to change at some point.

Also, DO NOT Use:

#!/usr/local/bin/python

“python may be installed at /usr/bin/python or /bin/python in those cases, the above #! will fail.”

“#!/usr/bin/env python” vs “#!/usr/local/bin/python”


回答 1

这实际上只是一个品味问题。添加shebang意味着人们可以根据需要直接调用脚本(假设它被标记为可执行文件);省略它只是意味着python必须手动调用。

无论哪种方式,运行该程序的最终结果都不会受到影响。这只是手段的选择。

It’s really just a matter of taste. Adding the shebang means people can invoke the script directly if they want (assuming it’s marked as executable); omitting it just means python has to be invoked manually.

The end result of running the program isn’t affected either way; it’s just options of the means.


回答 2

我应该把shebang放到我的Python脚本中吗?

将shebang放入Python脚本中以指示:

  • 该模块可以作为脚本运行
  • 它只能在python2,python3上运行还是与Python 2/3兼容?
  • 在POSIX上,如果要直接运行脚本而不python显式调用可执行文件,则很有必要

这些同样便携吗?最常用哪种形式?

如果您手动编写shebang ,请始终使用,#!/usr/bin/env python除非有特殊原因不使用它。即使在Windows(Python启动器)上也可以理解这种形式。

注意:已安装的脚本应使用特定的python可执行文件,例如/usr/bin/python/home/me/.virtualenvs/project/bin/python。如果您在Shell中激活virtualenv,如果某些工具损坏了,那就很糟糕。幸运的是,在大多数情况下,正确的shebang是由setuptools您或您的分发包工具自动创建的(在Windows上,setuptools可以.exe自动生成包装器脚本)。

换句话说,如果脚本在源签出中,则可能会看到#!/usr/bin/env python。如果已安装,则shebang是特定python可执行文件的路径,例如#!/usr/local/bin/python (注意:您不应手动编写来自后一类别的路径)。

要选择是否应该使用pythonpython2python3在家当,见PEP 394 -在类Unix系统中的“Python”命令

  • python应该仅在shebang行中用于与Python 2和3源兼容的脚本。

  • 为了最终更改Python的默认版本,应仅将Python 2脚本更新为与Python 3源兼容,或者python2在shebang行中使用。

Should I put the shebang in my Python scripts?

Put a shebang into a Python script to indicate:

  • this module can be run as a script
  • whether it can be run only on python2, python3 or is it Python 2/3 compatible
  • on POSIX, it is necessary if you want to run the script directly without invoking python executable explicitly

Are these equally portable? Which form is used most?

If you write a shebang manually then always use #!/usr/bin/env python unless you have a specific reason not to use it. This form is understood even on Windows (Python launcher).

Note: installed scripts should use a specific python executable e.g., /usr/bin/python or /home/me/.virtualenvs/project/bin/python. It is bad if some tool breaks if you activate a virtualenv in your shell. Luckily, the correct shebang is created automatically in most cases by setuptools or your distribution package tools (on Windows, setuptools can generate wrapper .exe scripts automatically).

In other words, if the script is in a source checkout then you will probably see #!/usr/bin/env python. If it is installed then the shebang is a path to a specific python executable such as #!/usr/local/bin/python (NOTE: you should not write the paths from the latter category manually).

To choose whether you should use python, python2, or python3 in the shebang, see PEP 394 – The “python” Command on Unix-Like Systems:

  • python should be used in the shebang line only for scripts that are source compatible with both Python 2 and 3.

  • in preparation for an eventual change in the default version of Python, Python 2 only scripts should either be updated to be source compatible with Python 3 or else to use python2 in the shebang line.


回答 3

如果您有多个版本的Python,并且脚本需要在特定版本下运行,那么在直接执行脚本时,she-bang可以确保使用正确的版本,例如:

#!/usr/bin/python2.7

请注意,脚本仍然可以通过完整的Python命令行或通过import运行,在这种情况下,she-bang会被忽略。但是对于直接运行的脚本,这是使用she-bang的一个不错的理由。

#!/usr/bin/env python 通常是更好的方法,但这在特殊情况下会有所帮助。

通常,最好建立一个Python虚拟环境,在这种情况下,泛型#!/usr/bin/env python将为virtualenv标识正确的Python实例。

If you have more than one version of Python and the script needs to run under a specific version, the she-bang can ensure the right one is used when the script is executed directly, for example:

#!/usr/bin/python2.7

Note the script could still be run via a complete Python command line, or via import, in which case the she-bang is ignored. But for scripts run directly, this is a decent reason to use the she-bang.

#!/usr/bin/env python is generally the better approach, but this helps with special cases.

Usually it would be better to establish a Python virtual environment, in which case the generic #!/usr/bin/env python would identify the correct instance of Python for the virtualenv.


回答 4

如果脚本旨在可执行,则应添加shebang。您还应该使用可将shebang修改为正确的安装软件来安装脚本,以使其可以在目标平台上运行。例如distutils和Distribute。

You should add a shebang if the script is intended to be executable. You should also install the script with an installing software that modifies the shebang to something correct so it will work on the target platform. Examples of this is distutils and Distribute.


回答 5

shebang的目的是让脚本在您要从外壳执行脚本时识别解释器类型。通常,并非总是如此,您可以通过从外部提供解释器来执行脚本。用法示例:python-x.x script.py

即使您没有shebang声明符,这也将起作用。

为什么第一个更“便携”的原因是因为它/usr/bin/env包含了PATH声明,该声明说明了系统可执行文件所在的所有目标。

注意:Tornado严格不使用shebang,而Django严格不使用。它随您执行应用程序主要功能的方式而异。

还:它与Python并没有变化。

The purpose of shebang is for the script to recognize the interpreter type when you want to execute the script from the shell. Mostly, and not always, you execute scripts by supplying the interpreter externally. Example usage: python-x.x script.py

This will work even if you don’t have a shebang declarator.

Why first one is more “portable” is because, /usr/bin/env contains your PATH declaration which accounts for all the destinations where your system executables reside.

NOTE: Tornado doesn’t strictly use shebangs, and Django strictly doesn’t. It varies with how you are executing your application’s main function.

ALSO: It doesn’t vary with Python.


回答 6

有时,如果答案不是很清楚(我的意思是,你不能,如果是或否决定),那么它没有太大的关系,直到答案,你可以忽略的问题清楚的。

#!唯一目的是为了启动脚本。Django会自行加载并使用源。不需要决定使用哪种解释器。这样,#!这里实际上没有任何意义。

通常,如果它是一个模块并且不能用作脚本,则无需使用#!。另一方面,模块源通常包含if __name__ == '__main__': ...至少一些琐碎的功能测试。然后#!再次有意义。

使用的一个好理由#!是当您同时使用Python 2和Python 3脚本时-它们必须由不同版本的Python解释。这样,您必须记住python手动启动脚本时必须使用的内容(无#!内部内容)。如果混合使用这些脚本,则最好使用#!内部脚本,使其成为可执行文件,然后将其作为可执行文件启动(chmod …)。

使用MS-Windows时,#!直到最近才有意义。Python 3.3引入了Windows Python启动器(py.exe和pyw.exe),该启动器读取#!行,检测已安装的Python版本并使用正确或明确需要的Python版本。由于扩展可以与程序相关联,因此在Windows中可以获得与基于Unix的系统中的execute标志类似的行为。

Sometimes, if the answer is not very clear (I mean you cannot decide if yes or no), then it does not matter too much, and you can ignore the problem until the answer is clear.

The #! only purpose is for launching the script. Django loads the sources on its own and uses them. It never needs to decide what interpreter should be used. This way, the #! actually makes no sense here.

Generally, if it is a module and cannot be used as a script, there is no need for using the #!. On the other hand, a module source often contains if __name__ == '__main__': ... with at least some trivial testing of the functionality. Then the #! makes sense again.

One good reason for using #! is when you use both Python 2 and Python 3 scripts — they must be interpreted by different versions of Python. This way, you have to remember what python must be used when launching the script manually (without the #! inside). If you have a mixture of such scripts, it is a good idea to use the #! inside, make them executable, and launch them as executables (chmod …).

When using MS-Windows, the #! had no sense — until recently. Python 3.3 introduces a Windows Python Launcher (py.exe and pyw.exe) that reads the #! line, detects the installed versions of Python, and uses the correct or explicitly wanted version of Python. As the extension can be associated with a program, you can get similar behaviour in Windows as with execute flag in Unix-based systems.


回答 7

当我最近在Windows 7上安装Python 3.6.1时,它还安装了Windows的Python启动器,该应用程序应该可以处理shebang行。但是,我发现Python Launcher并没有做到这一点:shebang行被忽略,并且始终使用Python 2.7.13(除非我使用py -3执行脚本)。

要解决此问题,我必须编辑Windows注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command。这仍然有价值

"C:\Python27\python.exe" "%1" %*

从我以前的Python 2.7安装中获取。我将此注册表项值修改为

"C:\Windows\py.exe" "%1" %*

并且Python Launcher shebang行处理如上所述。

When I installed Python 3.6.1 on Windows 7 recently, it also installed the Python Launcher for Windows, which is supposed to handle the shebang line. However, I found that the Python Launcher did not do this: the shebang line was ignored and Python 2.7.13 was always used (unless I executed the script using py -3).

To fix this, I had to edit the Windows registry key HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command. This still had the value

"C:\Python27\python.exe" "%1" %*

from my earlier Python 2.7 installation. I modified this registry key value to

"C:\Windows\py.exe" "%1" %*

and the Python Launcher shebang line processing worked as described above.


回答 8

如果您安装了不同的模块,并且需要使用特定的python安装,那么shebang似乎一开始受到限制。但是,您可以执行以下操作,使shebang首先作为shell脚本被调用,然后选择python。这是非常灵活的imo:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $PREFERRED_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

或许更好的办法是,促进跨多个python脚本的代码重用:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

然后select.sh具有:

PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi

If you have different modules installed and need to use a specific python install, then shebang appears to be limited at first. However, you can do tricks like the below to allow the shebang to be invoked first as a shell script and then choose python. This is very flexible imo:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $PREFERRED_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

Or better yet, perhaps, to facilitate code reuse across multiple python scripts:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

and then select.sh has:

PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi

回答 9

答:仅当您计划使其成为命令行可执行脚本时。

步骤如下:

首先,验证要使用的适当的shebang字符串:

which python

从中获取输出,并在第一行中将其添加(带有shebang#!)。

在我的系统上,它的响应如下:

$which python
/usr/bin/python

因此,您的shebang将如下所示:

#!/usr/bin/python

保存后,它仍将像以前一样运行,因为python会将第一行视为注释。

python filename.py

要使其成为命令,请将其复制以删除.py扩展名。

cp filename.py filename

告诉文件系统这将是可执行的:

chmod +x filename

要测试它,请使用:

./filename

最佳实践是将其移动到$ PATH中的某个位置,因此只需键入文件名即可。

sudo cp filename /usr/sbin

这样,它将可以在任何地方使用(文件名前没有./)

Answer: Only if you plan to make it a command-line executable script.

Here is the procedure:

Start off by verifying the proper shebang string to use:

which python

Take the output from that and add it (with the shebang #!) in the first line.

On my system it responds like so:

$which python
/usr/bin/python

So your shebang will look like:

#!/usr/bin/python

After saving, it will still run as before since python will see that first line as a comment.

python filename.py

To make it a command, copy it to drop the .py extension.

cp filename.py filename

Tell the file system that this will be executable:

chmod +x filename

To test it, use:

./filename

Best practice is to move it somewhere in your $PATH so all you need to type is the filename itself.

sudo cp filename /usr/sbin

That way it will work everywhere (without the ./ before the filename)


回答 10

绝对路径与逻辑路径:

关于可移植性,这实际上是一个关于Python解释器的路径是绝对路径还是Logical/usr/bin/env)的问题。

遇到这个和谈论这个问题在一般的方式,而不支持其他证明堆栈网站其他的答案,我已经进行了一些真的,真的在上过这个问题,颗粒测试和分析unix.stackexchange.com。与其在此处粘贴答案,不如将那些对比较分析感兴趣的人指向该答案:

https://unix.stackexchange.com/a/566019/334294

作为一名Linux工程师,我的目标始终是为我的开发人员客户端提供最合适的,优化的主机,因此,我确实需要一个可靠的解决方案来解决Python环境问题。测试后,我的观点是,在(2)选项中,she-bang 中的逻辑路径更好。

Absolute vs Logical Path:

This is really a question about whether the path to the Python interpreter should be absolute or Logical (/usr/bin/env) in respect to portability.

Encountering other answers on this and other Stack sites which talked about the issue in a general way without supporting proofs, I’ve performed some really, REALLY, granular testing & analysis on this very question on the unix.stackexchange.com. Rather than paste that answer here, I’ll point those interested to the comparative analysis to that answer:

https://unix.stackexchange.com/a/566019/334294

Being a Linux Engineer, my goal is always to provide the most suitable, optimized hosts for my developer clients, so the issue of Python environments was something I really needed a solid answer to. My view after the testing was that the logical path in the she-bang was the better of the (2) options.


回答 11

首先使用

which python

这将给出输出作为我的python解释器(二进制)所在的位置。

此输出可以是任何这样的

/usr/bin/python

要么

/bin/python

现在,适当选择shebang行并使用它。

概括地说,我们可以使用:

#!/usr/bin/env

要么

#!/bin/env

Use first

which python

This will give the output as the location where my python interpreter (binary) is present.

This output could be any such as

/usr/bin/python

or

/bin/python

Now appropriately select the shebang line and use it.

To generalize we can use:

#!/usr/bin/env

or

#!/bin/env

在virtualenv中使用Python 3

问题:在virtualenv中使用Python 3

使用virtualenv,我使用默认版本的Python(2.7)运行项目。在一个项目中,我需要使用Python 3.4。

我曾经brew install python3将其安装在Mac上。现在,如何创建使用新版本的virtualenv?

例如sudo virtualenv envPython3

如果我尝试:

virtualenv -p python3 test

我得到:

Running virtualenv with interpreter /usr/local/bin/python3
Using base prefix '/usr/local/Cellar/python3/3.4.0_1/Frameworks/Python.framework/Versions/3.4'
New python executable in test/bin/python3.4
Also creating executable in test/bin/python
Failed to import the site module
Traceback (most recent call last):
  File "/Users/user/Documents/workspace/test/test/bin/../lib/python3.4/site.py", line 67, in <module>
    import os
  File "/Users/user/Documents/workspace/test/test/bin/../lib/python3.4/os.py", line 634, in <module>
    from _collections_abc import MutableMapping
ImportError: No module named '_collections_abc'
ERROR: The executable test/bin/python3.4 is not functioning
ERROR: It thinks sys.prefix is '/Users/user/Documents/workspace/test' (should be '/Users/user/Documents/workspace/test/test')
ERROR: virtualenv is not compatible with this system or executable

Using virtualenv, I run my projects with the default version of Python (2.7). On one project, I need to use Python 3.4.

I used brew install python3 to install it on my Mac. Now, how do I create a virtualenv that uses the new version?

e.g. sudo virtualenv envPython3

If I try:

virtualenv -p python3 test

I get:

Running virtualenv with interpreter /usr/local/bin/python3
Using base prefix '/usr/local/Cellar/python3/3.4.0_1/Frameworks/Python.framework/Versions/3.4'
New python executable in test/bin/python3.4
Also creating executable in test/bin/python
Failed to import the site module
Traceback (most recent call last):
  File "/Users/user/Documents/workspace/test/test/bin/../lib/python3.4/site.py", line 67, in <module>
    import os
  File "/Users/user/Documents/workspace/test/test/bin/../lib/python3.4/os.py", line 634, in <module>
    from _collections_abc import MutableMapping
ImportError: No module named '_collections_abc'
ERROR: The executable test/bin/python3.4 is not functioning
ERROR: It thinks sys.prefix is '/Users/user/Documents/workspace/test' (should be '/Users/user/Documents/workspace/test/test')
ERROR: virtualenv is not compatible with this system or executable

回答 0

只需运行

virtualenv -p python3 envname

OP编辑后更新:

有没有在OP的版本virtualenv中的一个bug,如所描述这里。该问题已通过运行解决:

pip install --upgrade virtualenv

simply run

virtualenv -p python3 envname

Update after OP’s edit:

There was a bug in the OP’s version of virtualenv, as described here. The problem was fixed by running:

pip install --upgrade virtualenv

回答 1

Python 3具有对虚拟环境venv的内置支持。最好改用它。参考文档:

通过执行pyvenv脚本来创建虚拟环境:

pyvenv /path/to/new/virtual/environment

适用于Python 3.6及更高版本的更新:

由于pawciobiel正确注释了pyvenv因此从Python 3.6开始不推荐使用,新方法是:

python3 -m venv /path/to/new/virtual/environment

Python 3 has a built-in support for virtual environments – venv. It might be better to use that instead. Referring to the docs:

Creation of virtual environments is done by executing the pyvenv script:

pyvenv /path/to/new/virtual/environment

Update for Python 3.6 and newer:

As pawciobiel correctly comments, pyvenv is deprecated as of Python 3.6 and the new way is:

python3 -m venv /path/to/new/virtual/environment

回答 2

我尝试过pyenv,它对于切换python版本(全局,文件夹或virtualenv中的本地)非常方便:

brew install pyenv

然后安装所需的Python版本:

pyenv install 3.5.0

并只需创建virtualenv并包含所需解释器版本的路径即可:

virtualenv -p /Users/johnny/.pyenv/versions/3.5.0/bin/python3.5 myenv

就是这样,检查版本:

. ./myenv/bin/activate && python -V

也有pyenv的插件pyenv-virtualenv,但是它对我不起作用。

I’v tried pyenv and it’s very handy for switching python versions (global, local in folder or in the virtualenv):

brew install pyenv

then install Python version you want:

pyenv install 3.5.0

and simply create virtualenv with path to needed interpreter version:

virtualenv -p /Users/johnny/.pyenv/versions/3.5.0/bin/python3.5 myenv

That’s it, check the version:

. ./myenv/bin/activate && python -V

There are also plugin for pyenv pyenv-virtualenv but it didn’t work for me somehow.


回答 3

安装先决条件。

sudo apt-get install python3 python3-pip virtualenvwrapper

创建一个基于Python3的虚拟环境。(可选)启用--system-site-packages标志。

mkvirtualenv -p /usr/bin/python3 <venv-name>

设置到虚拟环境中。

workon <venv-name>

使用pip程序包管理器安装其他要求。

pip install -r requirements.txt
pip install <package_name>

当同时处理多个python项目时,通常建议安装pdbpp全局通用包,然后在virtualenvs中重用它们。

除了消耗最少的磁盘空间和网络带宽外,使用此技术还节省了很多时间来获取软件包和安装软件包。

sudo -H pip3 -v install pdbpp
mkvirtualenv -p $(which python3) --system-site-packages <venv-name>

Django特定说明

如果有很多系统范围的python软件包,那么建议不要使用--system-site-packagesflag,尤其是在开发过程中,因为我注意到它会大大降低Django的启动速度。我认为Django环境初始化是手动扫描并从系统路径附加所有站点包,这可能是原因。甚至python manage.py shell变得很慢。

话虽如此,实验哪个选项更好。跳过--system-site-packagesDjango项目的标志可能是安全的。

Install prerequisites.

sudo apt-get install python3 python3-pip virtualenvwrapper

Create a Python3 based virtual environment. Optionally enable --system-site-packages flag.

mkvirtualenv -p /usr/bin/python3 <venv-name>

Set into the virtual environment.

workon <venv-name>

Install other requirements using pip package manager.

pip install -r requirements.txt
pip install <package_name>

When working on multiple python projects simultaneously it is usually recommended to install common packages like pdbpp globally and then reuse them in virtualenvs.

Using this technique saves a lot of time spent on fetching packages and installing them, apart from consuming minimal disk space and network bandwidth.

sudo -H pip3 -v install pdbpp
mkvirtualenv -p $(which python3) --system-site-packages <venv-name>

Django specific instructions

If there are a lot of system wide python packages then it is recommended to not use --system-site-packages flag especially during development since I have noticed that it slows down Django startup a lot. I presume Django environment initialisation is manually scanning and appending all site packages from the system path which might be the reason. Even python manage.py shell becomes very slow.

Having said that experiment which option works better. Might be safe to just skip --system-site-packages flag for Django projects.


回答 4

virtualenv --python=/usr/bin/python3 <name of env>

为我工作。

virtualenv --python=/usr/bin/python3 <name of env>

worked for me.


回答 5

您可以在创建环境时指定特定的Python版本
virtualenv.py中提到

virtualenv --python=python3.5 envname

在某些情况下,这必须是可执行文件的完整路径:

virtualenv --python=/Users/username/.pyenv/versions/3.6.0/bin/python3.6 envname

如何-p工作

parser.add_option(
    '-p', '--python',
    dest='python',
    metavar='PYTHON_EXE',
    help='The Python interpreter to use, e.g., --python=python3.5 will use the python3.5 '
    'interpreter to create the new environment.  The default is the interpreter that '
    'virtualenv was installed with (%s)' % sys.executable)

You can specify specific Version of Python while creating environment.
It’s mentioned in virtualenv.py

virtualenv --python=python3.5 envname

In some cases this has to be the full path to the executable:

virtualenv --python=/Users/username/.pyenv/versions/3.6.0/bin/python3.6 envname

How -p works

parser.add_option(
    '-p', '--python',
    dest='python',
    metavar='PYTHON_EXE',
    help='The Python interpreter to use, e.g., --python=python3.5 will use the python3.5 '
    'interpreter to create the new environment.  The default is the interpreter that '
    'virtualenv was installed with (%s)' % sys.executable)

回答 6

我有同样的ERROR信息。在我的情况下,tbrisker的解决方案不起作用。相反,这解决了问题:

$ python3 -m venv .env

I had the same ERROR message. tbrisker’s solution did not work in my case. Instead this solved the issue:

$ python3 -m venv .env

回答 7

这就是您所需要的,以便在python / python3中运行虚拟环境

首先,如果virtualenv未安装,请运行

pip3 install virtualenv 

现在运行:

virtualenv -p python3 <env name> 

有时,cmd virtualenv失败,请使用以下命令:

python3 -m virtualenv <env_name>  # you can specify full path instead <env_name> to install the file in a different location other than the current location

现在激活虚拟环境:

source <env_name>/bin/activate

要么:

source `pwd`/<env_name>/bin/activate

现在运行

which python

您应该看到目录和<env_name>/bin/python后缀的完整路径

要退出virtualenv,请运行:

deactivate 

This is all you need, in order to run a virtual environment in python / python3

First if virtualenv not installed, run

pip3 install virtualenv 

Now Run:

virtualenv -p python3 <env name> 

Sometime the cmd virtualenv fails, if so use this:

python3 -m virtualenv <env_name>  # you can specify full path instead <env_name> to install the file in a different location other than the current location

Now activate the virtual env:

source <env_name>/bin/activate

Or:

source `pwd`/<env_name>/bin/activate

Now run

which python

You should see the full path to your dir and <env_name>/bin/python suffix

To exit the virtualenv, run:

deactivate 

回答 8

Python现在带有自己的虚拟环境实现,名称为“ venv”。我建议使用它,而不是virtualenv。

引用venv-docs

自3.6版起不推荐使用:pyvenv是为Python 3.3和3.4创建虚拟环境的推荐工具,在Python 3.6中不推荐使用。

在版本3.5中进行了更改:现在建议使用venv创建虚拟环境。

对于Windows,要在某些项目上启动venv,请打开cmd:

python -m venv "c:\path\to\myenv"

(如果目录路径包含空格,建议在目录路径周围使用双引号。例如:“ C:/ My Dox / Spaced Directory / Something”)

设置venv后,您将在项目目录中看到一些新文件夹。其中之一就是“脚本”。

要激活或调用venv,您需要:

C:\> <venv>\Scripts\activate.bat

您可以通过在Shell中键入“ deactivate”来停用虚拟环境。这样,您现在就可以安装特定于项目的库,该库位于文件夹“ Lib”下。

===============================编辑1 ================ ====================下面将要讨论的场景不是最初要求的,只是在有人将vscode与python扩展一起使用的情况下添加此场景

如果您使用vs代码及其python扩展名,您的pylint可能会遇到问题,该问题指向全局安装。在这种情况下,pylint将无法查看虚拟环境中安装的模块,因此在导入时将显示错误。

是克服此问题的简单方法。

cd Workspace\Scripts
.\Activate.ps1
code .

我们基本上是先激活环境,然后再调用vs代码,以便pylint在环境中启动并可以看到所有本地包。

Python now comes with its own implementation of virtual environment, by the name of “venv”. I would suggest using that, instead of virtualenv.

Quoting from venv – docs,

Deprecated since version 3.6: pyvenv was the recommended tool for creating virtual environments for Python 3.3 and 3.4, and is deprecated in Python 3.6.

Changed in version 3.5: The use of venv is now recommended for creating virtual environments.

For windows, to initiate venv on some project, open cmd:

python -m venv "c:\path\to\myenv"

(Would suggest using double quote around directory path if it contains any spaces. Ex: “C:/My Dox/Spaced Directory/Something”)

Once venv is set up, you will see some new folders inside your project directory. One of them would be “Scripts”.

To activate or invoke venv you need:

C:\> <venv>\Scripts\activate.bat

You can deactivate a virtual environment by typing “deactivate” in your shell. With this, you are now ready to install your project specific libraries, which will reside under the folder “Lib”.

================================ Edit 1 ==================================== The scenario which will be discussed below is not what originally asked, just adding this in case someone use vscode with python extension

In case, you use vs code with its python extension, you might face an issue with its pylint which points to the global installation. In this case, pylint won’t be able to see the modules that are installed in your virtual environment and hence will show errors while importing.

Here is a simple method to get past this.

cd Workspace\Scripts
.\Activate.ps1
code .

We are basically activating the environment first and then invoking vs-code so that pylint starts within the environment and can see all local packages.


回答 9

除了其他答案,我建议检查您正在执行哪个virtualenv实例:

which virtualenv

如果在/ usr / local / bin中出现问题,则可能甚至可能安装了virtualenv(可能使用easy_tools或pip实例)而没有使用系统的程序包管理器(在OP中为棕色)。这是我的问题。

多年前-当我更加无知的时候-我安装了virtualenv,它掩盖了我系统的软件包提供的virtualenv。

删除了这个破旧的virtualenv之后,我的问题就消失了。

In addition to the other answers, I recommend checking what instance of virtualenv you are executing:

which virtualenv

If this turns up something in /usr/local/bin, then it is possible – even likely – that you installed virtualenv (possibly using an instance of easy_tools or pip) without using your system’s package manager (brew in OP’s case). This was my problem.

Years ago – when I was even more ignorant – I had installed virtualenv and it was masking my system’s package-provided virtualenv.

After removing this old, broken virtualenv, my problems went away.


回答 10

在python3.6中,我python3 -m venv myenv根据文档尝试 了,但是花费了很长时间。因此,非常简单快捷的命令是: python -m venv yourenv 它在python3.6上对我有效。

In python3.6 I tried python3 -m venv myenv, as per the documentation, but it was taking so long. So the very simple and quick command is python -m venv yourenv It worked for me on python3.6.


回答 11

在Mac上,我必须执行以下操作才能使其正常工作。

mkvirtualenv --python=/usr/bin/python3 YourEnvNameHere

On Mac I had to do the following to get it to work.

mkvirtualenv --python=/usr/bin/python3 YourEnvNameHere

回答 12

如果您将python3(brew install python3)与virtualenv burrito一起安装,则可以 mkvirtualenv -p $(which python3) env_name

当然,我知道virtualenv burrito只是一个包装,但是多年来,它对我很有用,减少了一些学习难度。

If you install python3 (brew install python3) along with virtualenv burrito, you can then do mkvirtualenv -p $(which python3) env_name

Of course, I know virtualenv burrito is just a wrapper, but it has served me well over the years, reducing some learning curves.


回答 13

virtualenv --python=/usr/local/bin/python3 <VIRTUAL ENV NAME> 这将为 您的虚拟环境添加python3路径。

virtualenv --python=/usr/local/bin/python3 <VIRTUAL ENV NAME> this will add python3 path for your virtual enviroment.


回答 14

对我有用

virtualenv --no-site-packages --distribute -p /usr/bin/python3 ~/.virtualenvs/py3

It worked for me

virtualenv --no-site-packages --distribute -p /usr/bin/python3 ~/.virtualenvs/py3

回答 15

对于那些在使用Anaconda3(Python 3)时遇到麻烦的人。

你可以用

conda create -n name_of_your_virtualenv python=python_version 

激活环境(Linux,MacOS)

source activate name_of_your_virtualenv

对于Windows

activate name_of_your_virtualenv

For those having troubles while working with Anaconda3 (Python 3).

You could use

conda create -n name_of_your_virtualenv python=python_version 

To activate the environment ( Linux, MacOS)

source activate name_of_your_virtualenv

For Windows

activate name_of_your_virtualenv

回答 16

我尝试了以上所有方法,但仍然没有效果。因此,作为蛮力,我只是重新安装了anaconda,重新安装了virtualenv …,它确实起作用了。

Amans-MacBook-Pro:~ amanmadan$ pip install virtualenv
You are using pip version 6.1.1, however version 8.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting virtualenv
  Downloading virtualenv-15.0.3-py2.py3-none-any.whl (3.5MB)
    100% |████████████████████████████████| 3.5MB 114kB/s 
Installing collected packages: virtualenv
Successfully installed virtualenv-15.0.3
Amans-MacBook-Pro:python amanmadan$ virtualenv my_env
New python executable in /Users/amanmadan/Documents/HadoopStuff/python/my_env/bin/python
Installing setuptools, pip, wheel...done.
Amans-MacBook-Pro:python amanmadan$ 

I tried all the above stuff, it still didn’t work. So as a brute force, I just re-installed the anaconda, re-installed the virtualenv… and it worked.

Amans-MacBook-Pro:~ amanmadan$ pip install virtualenv
You are using pip version 6.1.1, however version 8.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting virtualenv
  Downloading virtualenv-15.0.3-py2.py3-none-any.whl (3.5MB)
    100% |████████████████████████████████| 3.5MB 114kB/s 
Installing collected packages: virtualenv
Successfully installed virtualenv-15.0.3
Amans-MacBook-Pro:python amanmadan$ virtualenv my_env
New python executable in /Users/amanmadan/Documents/HadoopStuff/python/my_env/bin/python
Installing setuptools, pip, wheel...done.
Amans-MacBook-Pro:python amanmadan$ 

回答 17

我想将python 2.7.5保留为Centos 7的默认版本,但在虚拟环境中将python 3.6.1与python 2.x中的其他虚拟环境一起运行

我发现以下链接是最新python版本(python 3.6.1)的最佳解决方案 https://www.digitalocean.com/community/tutorial_series/how-to-install-and-set-up-a-local-programming -for-python-3环境。它显示了不同平台的步骤,但是基本步骤是

  1. 为您的平台安装python3.x(如果不存在)
  2. 为您的平台安装python3.x-devel
  3. 在python 3.x中创建虚拟环境(例如$ python3.6 -m venv virenv_test_p3 /)
  4. 激活python 3.x的测试环境(例如源virenv_test_p3 / bin / activate)
  5. 安装要在新的python 3虚拟环境中使用且受支持的软件包(例如pip install Django == 1.11.2)

I wanted to keep python 2.7.5 as default version on Centos 7 but have python 3.6.1 in a virtual environment running alongside other virtual environments in python 2.x

I found the below link the best solution for the newest python version ( python 3.6.1) https://www.digitalocean.com/community/tutorial_series/how-to-install-and-set-up-a-local-programming-environment-for-python-3. It shows the steps for different platforms but the basic steps are

  1. Install python3.x (if not present) for your platform
  2. Install python3.x-devel for your platform
  3. Create virtual environment in python 3.x (for example $ python3.6 -m venv virenv_test_p3/ )
  4. Activate the testenvironment for python 3.x (for example source virenv_test_p3/bin/activate)
  5. Install the packages which you want to use in your new python 3 virtual environment and which are supported ( for example pip install Django==1.11.2)

回答 18

下面的简单命令可以使用3.5版创建虚拟环境

apt-get install python3-venv

python3.5 -m venv <your env name>

如果您希望虚拟环境版本为3.6

python3.6 -m venv <your env name>

The below simple commands can create a virtual env with version 3.5

apt-get install python3-venv

python3.5 -m venv <your env name>

if you want virtual env version as 3.6

python3.6 -m venv <your env name>

回答 19

对于正在使用pipenv并想要安装特定版本的用户:

pipenv install --python 3.6

For those of you who are using pipenv and want to install specific version:

pipenv install --python 3.6

回答 20

由于存在与miniconda3安装冲突的问题,因此出现了相同的错误,因此当您键入“哪个virtualenv”并且安装了miniconda并指向该安装时,您可以将其删除(如果您喜欢我并且没有移动)或更改环境变量以指向所需的安装。

I got the same error due to it being a conflict with miniconda3 install so when you type “which virtualenv” and if you’ve installed miniconda and it’s pointing to that install you can either remove it (if your like me and haven’t moved to it yet) or change your environment variable to point to the install you want.


回答 21

在Windows命令行上,以下内容对我有用。首先找出您的python可执行文件所在的位置:

where python

这会将路径输出到系统上其他python.exe的路径。这是我的:

C:\Users\carandangc\Anaconda3\python.exe
C:\Python27\python.exe

因此,对于Python3而言,这位于我的第一个路径中,因此我进入了要在其中创建虚拟环境文件夹的应用程序的根文件夹。然后,我运行以下命令,其中包括我的Python3可执行文件的路径,将我的虚拟环境命名为“ venv”:

virtualenv --python=/Users/carandangc/Anaconda3/python.exe venv

接下来,激活虚拟环境:

call venv\Scripts\activate.bat

最后,安装此虚拟环境的依赖项:

pip install -r requirements.txt

如果您知道虚拟环境中应用程序所需的库/模块,则可以手动填充此requirements.txt。如果您的应用程序在另一个环境中运行,则可以通过运行以下命令(在运行它的环境中的cd到应用程序文件夹中)来自动生成依赖项:

pip freeze > requirements.txt

然后,一旦您具有“冻结”的requests.txt,则可以使用以下命令(在cd到应用程序文件夹之后)在另一台计算机或干净的环境中安装需求:

pip install -r requirements.txt

要在虚拟环境中查看python版本,请运行:

python --version

然后,瞧……您的Python3正在虚拟环境中运行。为我输出:

Python 3.7.2

On Windows command line, the following worked for me. First find out where your python executables are located:

where python

This will output the paths to the different python.exe on your system. Here were mine:

C:\Users\carandangc\Anaconda3\python.exe
C:\Python27\python.exe

So for Python3, this was located in the first path for me, so I cd to the root folder of the application where I want to create a virtual environment folder. Then I run the following which includes the path to my Python3 executable, naming my virtual environment ‘venv’:

virtualenv --python=/Users/carandangc/Anaconda3/python.exe venv

Next, activate the virtual environment:

call venv\Scripts\activate.bat

Finally, install the dependencies for this virtual environment:

pip install -r requirements.txt

This requirements.txt could be populated manually if you know the libraries/modules needed for your application in the virtual environment. If you had the application running in another environment, then you can automatically produce the dependencies by running the following (cd to the application folder in the environment where it is working):

pip freeze > requirements.txt

Then once you have the requirements.txt that you have ‘frozen’, then you can install the requirements on another machine or clean environment with the following (after cd to the application folder):

pip install -r requirements.txt

To see your python version in the virtual environment, run:

python --version

Then voila…you have your Python3 running in your virtual environment. Output for me:

Python 3.7.2

如何在Python中将字典键作为列表返回?

问题:如何在Python中将字典键作为列表返回?

Python 2.7中,我可以将字典作为列表获取:

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

现在,在Python> = 3.3中,我得到如下信息:

>>> newdict.keys()
dict_keys([1, 2, 3])

因此,我必须这样做以获得列表:

newlist = list()
for i in newdict.keys():
    newlist.append(i)

我想知道,是否有更好的方法在Python 3中返回列表?

In Python 2.7, I could get dictionary keys, values, or items as a list:

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

Now, in Python >= 3.3, I get something like this:

>>> newdict.keys()
dict_keys([1, 2, 3])

So, I have to do this to get a list:

newlist = list()
for i in newdict.keys():
    newlist.append(i)

I’m wondering, is there a better way to return a list in Python 3?


回答 0

尝试list(newdict.keys())

这会将dict_keys对象转换为列表。

另一方面,您应该问自己是否重要。Python的编码方式是假设鸭子输入(如果它看起来像鸭子,而像鸭子一样嘎嘎叫,那就是鸭子)。在dict_keys大多数情况下,该对象的作用类似于列表。例如:

for key in newdict.keys():
  print(key)

显然,插入运算符可能不起作用,但是对于字典关键字列表而言,这并没有多大意义。

Try list(newdict.keys()).

This will convert the dict_keys object to a list.

On the other hand, you should ask yourself whether or not it matters. The Pythonic way to code is to assume duck typing (if it looks like a duck and it quacks like a duck, it’s a duck). The dict_keys object will act like a list for most purposes. For instance:

for key in newdict.keys():
  print(key)

Obviously, insertion operators may not work, but that doesn’t make much sense for a list of dictionary keys anyway.


回答 1

Python> = 3.5替代方法:解压缩为列表文字 [*newdict]

Python 3.5引入了新的拆包概括(PEP 448),使您现在可以轻松进行以下操作:

>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]

与解压缩的对象可*任何可迭代的对象一起使用,并且由于字典在迭代过程中会返回其键,因此您可以在列表文字中使用它轻松创建列表。

添加.keys()ie [*newdict.keys()]可能有助于使您的意图更加明确,尽管这将花费您函数查找和调用的费用。(实际上,这不是您真正应该担心的事情)。

*iterable语法类似于做list(iterable)其行为最初记录在呼叫部分 Python的参考手册。对于PEP 448,放宽了对*iterable可能出现的位置的限制,使其也可以放置在列表,集合和元组文字中,“ 表达式”列表上的参考手册也进行了更新以说明这一点。


尽管这等效于list(newdict)它更快(至少对于小型词典而言),因为实际上没有执行任何函数调用:

%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop

%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop

%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop

对于较大的字典,速度几乎是相同的(遍历大量集合的开销胜过了函数调用的小开销)。


您可以用类似的方式创建元组和字典键集:

>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}

在元组的情况下要小心尾随逗号!

Python >= 3.5 alternative: unpack into a list literal [*newdict]

New unpacking generalizations (PEP 448) were introduced with Python 3.5 allowing you to now easily do:

>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]

Unpacking with * works with any object that is iterable and, since dictionaries return their keys when iterated through, you can easily create a list by using it within a list literal.

Adding .keys() i.e [*newdict.keys()] might help in making your intent a bit more explicit though it will cost you a function look-up and invocation. (which, in all honesty, isn’t something you should really be worried about).

The *iterable syntax is similar to doing list(iterable) and its behaviour was initially documented in the Calls section of the Python Reference manual. With PEP 448 the restriction on where *iterable could appear was loosened allowing it to also be placed in list, set and tuple literals, the reference manual on Expression lists was also updated to state this.


Though equivalent to list(newdict) with the difference that it’s faster (at least for small dictionaries) because no function call is actually performed:

%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop

%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop

%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop

with larger dictionaries the speed is pretty much the same (the overhead of iterating through a large collection trumps the small cost of a function call).


In a similar fashion, you can create tuples and sets of dictionary keys:

>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}

beware of the trailing comma in the tuple case!


回答 2

list(newdict)在Python 2和Python 3中均可使用,在中提供了键的简单列表newdictkeys()没必要 (:

list(newdict) works in both Python 2 and Python 3, providing a simple list of the keys in newdict. keys() isn’t necessary. (:


回答 3

在“鸭子类型”定义上有一点点偏离- dict.keys()返回一个可迭代的对象,而不是类似列表的对象。它可以在任何可迭代的地方都可以使用-列表不能在任何地方使用。列表也是可迭代的,但可迭代的不是列表(或序列…)

在实际的用例中,与字典中的键有关的最常见的事情是遍历它们,因此这很有意义。如果确实需要它们作为清单,则可以调用list()

非常相似zip()-在大多数情况下,它会被迭代-为什么创建一个新的元组列表只是为了对其进行迭代,然后又将其丢弃?

这是python中使用更多迭代器(和生成器),而不是到处都是列表副本的一种大趋势的一部分。

dict.keys() 不过,应该可以理解-仔细检查是否有错别字或其他内容…对我来说效果很好:

>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]

A bit off on the “duck typing” definition — dict.keys() returns an iterable object, not a list-like object. It will work anywhere an iterable will work — not any place a list will. a list is also an iterable, but an iterable is NOT a list (or sequence…)

In real use-cases, the most common thing to do with the keys in a dict is to iterate through them, so this makes sense. And if you do need them as a list you can call list().

Very similarly for zip() — in the vast majority of cases, it is iterated through — why create an entire new list of tuples just to iterate through it and then throw it away again?

This is part of a large trend in python to use more iterators (and generators), rather than copies of lists all over the place.

dict.keys() should work with comprehensions, though — check carefully for typos or something… it works fine for me:

>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]

回答 4

您还可以使用列表推导

>>> newdict = {1:0, 2:0, 3:0}
>>> [k  for  k in  newdict.keys()]
[1, 2, 3]

或更短一点

>>> [k  for  k in  newdict]
[1, 2, 3]

注意:在3.7版以下的版本中,不能保证订购(订购仍然只是CPython 3.6的实现细节)。

You can also use a list comprehension:

>>> newdict = {1:0, 2:0, 3:0}
>>> [k  for  k in  newdict.keys()]
[1, 2, 3]

Or, shorter,

>>> [k  for  k in  newdict]
[1, 2, 3]

Note: Order is not guaranteed on versions under 3.7 (ordering is still only an implementation detail with CPython 3.6).


回答 5

不使用该keys方法转换为列表使其更具可读性:

list(newdict)

并且,当遍历字典时,不需要keys()

for key in newdict:
    print key

除非您要在循环中进行修改,否则将需要预先创建的键列表:

for key in list(newdict):
    del newdict[key]

在Python 2上,使用会产生少量性能提升keys()

Converting to a list without using the keys method makes it more readable:

list(newdict)

and, when looping through dictionaries, there’s no need for keys():

for key in newdict:
    print key

unless you are modifying it within the loop which would require a list of keys created beforehand:

for key in list(newdict):
    del newdict[key]

On Python 2 there is a marginal performance gain using keys().


回答 6

如果您需要单独存储密钥,那么此解决方案使用扩展的可迭代拆包(python3.x +),与迄今为止提供的所有其他解决方案相比,它的键入次数更少。

newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict

k
# [1, 2, 3]

            ╒═══════════════╤═════════════════════════════════════════╕
             k = list(d)      9 characters (excluding whitespace)   
            ├───────────────┼─────────────────────────────────────────┤
             k = [*d]         6 characters                          
            ├───────────────┼─────────────────────────────────────────┤
             *k, = d          5 characters                          
            ╘═══════════════╧═════════════════════════════════════════╛

If you need to store the keys separately, here’s a solution that requires less typing than every other solution presented thus far, using Extended Iterable Unpacking (python3.x+).

newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict

k
# [1, 2, 3]

            ╒═══════════════╤═════════════════════════════════════════╕
            │ k = list(d)   │   9 characters (excluding whitespace)   │
            ├───────────────┼─────────────────────────────────────────┤
            │ k = [*d]      │   6 characters                          │
            ├───────────────┼─────────────────────────────────────────┤
            │ *k, = d       │   5 characters                          │
            ╘═══════════════╧═════════════════════════════════════════╛

回答 7

我可以想到两种从字典中提取键的方法。

方法1:- 使用.keys()方法获取密钥,然后将其转换为列表。

some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]

方法2:- 创建一个空列表,然后通过循环将键附加到列表中。您也可以通过此循环获取值(仅将.keys()用于键,将.items()用于键和值提取)

list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
    list_of_keys.append(key)
    list_of_values.append(val)

print(list_of_keys)
-->[1,2,3]

print(list_of_values)
-->['one','two','three']

I can think of 2 ways in which we can extract the keys from the dictionary.

Method 1: – To get the keys using .keys() method and then convert it to list.

some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]

Method 2: – To create an empty list and then append keys to the list via a loop. You can get the values with this loop as well (use .keys() for just keys and .items() for both keys and values extraction)

list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
    list_of_keys.append(key)
    list_of_values.append(val)

print(list_of_keys)
-->[1,2,3]

print(list_of_values)
-->['one','two','three']

Python 3中的相对导入

问题:Python 3中的相对导入

我想从同一目录中的另一个文件导入函数。

有时它对我有用,from .mymodule import myfunction但有时我得到:

SystemError: Parent module '' not loaded, cannot perform relative import

有时它可与一起使用from mymodule import myfunction,但有时我也会得到:

SystemError: Parent module '' not loaded, cannot perform relative import

我不了解这里的逻辑,也找不到任何解释。这看起来完全是随机的。

有人可以向我解释所有这些背后的逻辑是什么?

I want to import a function from another file in the same directory.

Sometimes it works for me with from .mymodule import myfunction but sometimes I get a:

SystemError: Parent module '' not loaded, cannot perform relative import

Sometimes it works with from mymodule import myfunction, but sometimes I also get a:

SystemError: Parent module '' not loaded, cannot perform relative import

I don’t understand the logic here, and I couldn’t find any explanation. This looks completely random.

Could someone explain to me what’s the logic behind all this?


回答 0

不幸的是,该模块需要位于程序包内部,有时还需要作为脚本运行。知道如何实现吗?

像这样的布局很普遍…

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

mymodule.py像这样…

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

……一个myothermodule.py像这样…

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

main.py这样的…

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

…在您运行main.py或时工作正常mypackage/mymodule.py,但mypackage/myothermodule.py由于相对导入而失败,…

from .mymodule import as_int

您应该运行它的方式是…

python3 -m mypackage.myothermodule

…但是有些冗长,并且与像这样的shebang行不能很好地融合在一起#!/usr/bin/env python3

假设名称mymodule在全球范围内是唯一的,这种情况下最简单的解决方法是避免使用相对导入,而只需使用…

from mymodule import as_int

…尽管它不是唯一的,或者您的包结构更复杂,您仍需要在中包含包含包目录的目录PYTHONPATH,并按以下步骤进行操作…

from mypackage.mymodule import as_int

…或者如果您希望它“开箱即用”运行,则可以PYTHONPATH使用此方法首先获取输入代码…

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

这有点痛苦,但是有一个线索可以说明为什么某位Guido van Rossum写的电子邮件中

我对此表示怀疑,也对任何其他提议的__main__ 机械装置都为-1 。唯一的用例似乎是正在运行的脚本,它们恰好位于模块目录中,我一直将其视为反模式。为了让我改变主意,您必须说服我不要。

在程序包中运行脚本是否是反模式是主观的,但是就我个人而言,我发现它在包含一些自定义wxPython小部件的程序包中非常有用,因此我可以为任何源文件运行脚本以wx.Frame仅显示包含该小部件用于测试目的。

unfortunately, this module needs to be inside the package, and it also needs to be runnable as a script, sometimes. Any idea how I could achieve that?

It’s quite common to have a layout like this…

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

…with a mymodule.py like this…

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

…a myothermodule.py like this…

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

…and a main.py like this…

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

…which works fine when you run main.py or mypackage/mymodule.py, but fails with mypackage/myothermodule.py, due to the relative import…

from .mymodule import as_int

The way you’re supposed to run it is…

python3 -m mypackage.myothermodule

…but it’s somewhat verbose, and doesn’t mix well with a shebang line like #!/usr/bin/env python3.

The simplest fix for this case, assuming the name mymodule is globally unique, would be to avoid using relative imports, and just use…

from mymodule import as_int

…although, if it’s not unique, or your package structure is more complex, you’ll need to include the directory containing your package directory in PYTHONPATH, and do it like this…

from mypackage.mymodule import as_int

…or if you want it to work “out of the box”, you can frob the PYTHONPATH in code first with this…

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

It’s kind of a pain, but there’s a clue as to why in an email written by a certain Guido van Rossum…

I’m -1 on this and on any other proposed twiddlings of the __main__ machinery. The only use case seems to be running scripts that happen to be living inside a module’s directory, which I’ve always seen as an antipattern. To make me change my mind you’d have to convince me that it isn’t.

Whether running scripts inside a package is an antipattern or not is subjective, but personally I find it really useful in a package I have which contains some custom wxPython widgets, so I can run the script for any of the source files to display a wx.Frame containing only that widget for testing purposes.


回答 1

说明

PEP 328

相对导入使用模块的__name__属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,将其设置为’__main__’), 则相对导入的解析就好像该模块是顶级模块一样,无论该模块实际位于文件系统上的哪个位置。

在某些时候,PEP 338PEP 328冲突:

…相对导入依赖于__name__来确定当前模块在包层次结构中的位置。在主模块中,__name__的值始终为‘__main__’,因此显式相对导入将始终失败(因为它们仅适用于包中的模块)

为了解决这个问题,PEP 366引入了顶层变量__package__

通过添加新的模块级别属性,如果使用-m 开关执行模块,则该PEP允许相对导入自动进行。当按名称执行文件时,模块本身中的少量样板文件将允许相对导入工作。[…]如果存在[属性],则相对导入将基于此属性而不是模块__name__属性。[…]当通过其文件名指定主模块时,__package__属性将设置为None。[…] 当导入系统在未设置__package__的模块(或将其设置为None)的模块中遇到显式相对导入时,它将计算并存储正确的值__name __。rpartition(’。’)[0]用于常规模块__ name__用于程序包初始化模块)

(强调我的)

如果__name__'__main__',则__name__.rpartition('.')[0]返回空字符串。这就是为什么错误描述中有空字符串文字的原因:

SystemError: Parent module '' not loaded, cannot perform relative import

CPython PyImport_ImportModuleLevelObject函数的相关部分:

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

如果CPython packageinterp->modules(可通过访问)中找不到(包的名称),则会引发此异常sys.modules。由于sys.modules“将模块名称映射到已经加载的模块的字典”,因此现在很清楚,必须在执行相对导入之前显式绝对导入父模块

注意:问题18018中 的补丁添加了另一个ifblock,它将在以上代码之前执行:

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

如果package(与上面相同)为空字符串,则错误消息将为

ImportError: attempted relative import with no known parent package

但是,您只会在Python 3.6或更高版本中看到它。

解决方案1:使用-m运行脚本

考虑一个目录(这是一个Python ):

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

软件包中的所有文件均以相同的两行代码开头:

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

我加入这两行只是为了使操作顺序显而易见。我们可以完全忽略它们,因为它们不会影响执行。

__init__.pymodule.py仅包含这两行(即,它们实际上是空的)。

standalone.py另外尝试通过相对导入来导入module.py

from . import module  # explicit relative import

我们深知这/path/to/python/interpreter package/standalone.py将失败。但是,我们可以使用-m命令行选项运行该模块,该选项“搜索sys.path命名的模块并将其内容作为__main__模块执行”

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-m为您完成所有导入工作并自动设置__package__,但是您可以在

解决方案2:手动设置__package__

请把它当作概念证明而不是实际解决方案。它不适合在实际代码中使用。

PEP 366可以解决此问题,但是它不完整,因为__package__仅设置是不够的。您将需要至少在模块层次结构中导入N个先前的软件包,其中N是要搜索要导入的模块的父目录(相对于脚本目录)的数量。

从而,

  1. 将当前模块的第N个前辈的父目录添加到sys.path

  2. 从中删除当前文件的目录 sys.path

  3. 使用标准名称导入当前模块的父模块

  4. 设置__package__2的标准名称

  5. 执行相对导入

我将从解决方案1中借用文件,并添加更多子包:

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

这次standalone.py将使用以下相对导入方式从软件包中导入module.py

from ... import module  # N = 3

我们需要在该行之前加上样板代码,以使其正常工作。

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

它允许我们按文件名执行standalone.py

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

包裹在一个功能更通用的解决方案,可以发现在这里。用法示例:

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

解决方案3:使用绝对导入和设置工具

步骤是-

  1. 将显式相对导入替换为等效的绝对导入

  2. 安装package以使其可导入

例如,目录结构可以如下

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

其中setup.py

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

其余文件是从解决方案#1借用的。

安装后,无论您的工作目录如何,都可以导入软件包(假设没有命名问题)。

我们可以修改standalone.py以利用这一优势(步骤1):

from package import module  # absolute import

将工作目录更改为project并运行/path/to/python/interpreter setup.py install --user--user将软件包安装在site-packages目录中)(步骤2):

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

让我们验证一下现在可以将standalone.py作为脚本运行:

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

注意:如果您决定走这条路,最好使用虚拟环境来隔离安装软件包。

解决方案4:使用绝对导入和一些样板代码

坦白地说,不需要安装-您可以在脚本中添加一些样板代码以使绝对导入工作。

我将从解决方案1借用文件并更改standalone.py

  1. 尝试使用绝对导入从包中导入任何内容之前,将的父目录添加到:sys.path

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
  2. 用绝对导入替换相对导入:

    from package import module  # absolute import

standalone.py运行没有问题:

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

我认为我应该警告您:请不要这样做,尤其是在您的项目结构复杂的情况下。


作为附带说明,PEP 8建议使用绝对导入,但指出在某些情况下,显式相对导入是可以接受的:

建议使用绝对导入,因为它们通常更具可读性,并且往往表现得更好(或至少会提供更好的错误消息)。[…]但是,显式相对导入是绝对导入的一种可接受的替代方法,尤其是在处理复杂的包装布局时,使用绝对导入会不必要地冗长。

Explanation

From PEP 328

Relative imports use a module’s __name__ attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to ‘__main__’) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

At some point PEP 338 conflicted with PEP 328:

… relative imports rely on __name__ to determine the current module’s position in the package hierarchy. In a main module, the value of __name__ is always ‘__main__’, so explicit relative imports will always fail (as they only work for a module inside a package)

and to address the issue, PEP 366 introduced the top level variable __package__:

By adding a new module level attribute, this PEP allows relative imports to work automatically if the module is executed using the -m switch. A small amount of boilerplate in the module itself will allow the relative imports to work when the file is executed by name. […] When it [the attribute] is present, relative imports will be based on this attribute rather than the module __name__ attribute. […] When the main module is specified by its filename, then the __package__ attribute will be set to None. […] When the import system encounters an explicit relative import in a module without __package__ set (or with it set to None), it will calculate and store the correct value (__name__.rpartition(‘.’)[0] for normal modules and __name__ for package initialisation modules)

(emphasis mine)

If the __name__ is '__main__', __name__.rpartition('.')[0] returns empty string. This is why there’s empty string literal in the error description:

SystemError: Parent module '' not loaded, cannot perform relative import

The relevant part of the CPython’s PyImport_ImportModuleLevelObject function:

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

CPython raises this exception if it was unable to find package (the name of the package) in interp->modules (accessible as sys.modules). Since sys.modules is “a dictionary that maps module names to modules which have already been loaded”, it’s now clear that the parent module must be explicitly absolute-imported before performing relative import.

Note: The patch from the issue 18018 has added another if block, which will be executed before the code above:

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

If package (same as above) is empty string, the error message will be

ImportError: attempted relative import with no known parent package

However, you will only see this in Python 3.6 or newer.

Solution #1: Run your script using -m

Consider a directory (which is a Python package):

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

All of the files in package begin with the same 2 lines of code:

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

I’m including these two lines only to make the order of operations obvious. We can ignore them completely, since they don’t affect the execution.

__init__.py and module.py contain only those two lines (i.e., they are effectively empty).

standalone.py additionally attempts to import module.py via relative import:

from . import module  # explicit relative import

We’re well aware that /path/to/python/interpreter package/standalone.py will fail. However, we can run the module with the -m command line option that will “search sys.path for the named module and execute its contents as the __main__ module”:

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-m does all the importing stuff for you and automatically sets __package__, but you can do that yourself in the

Solution #2: Set __package__ manually

Please treat it as a proof of concept rather than an actual solution. It isn’t well-suited for use in real-world code.

PEP 366 has a workaround to this problem, however, it’s incomplete, because setting __package__ alone is not enough. You’re going to need to import at least N preceding packages in the module hierarchy, where N is the number of parent directories (relative to the directory of the script) that will be searched for the module being imported.

Thus,

  1. Add the parent directory of the Nth predecessor of the current module to sys.path

  2. Remove the current file’s directory from sys.path

  3. Import the parent module of the current module using its fully-qualified name

  4. Set __package__ to the fully-qualified name from 2

  5. Perform the relative import

I’ll borrow files from the Solution #1 and add some more subpackages:

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

This time standalone.py will import module.py from the package package using the following relative import

from ... import module  # N = 3

We’ll need to precede that line with the boilerplate code, to make it work.

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

It allows us to execute standalone.py by filename:

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

A more general solution wrapped in a function can be found here. Example usage:

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

Solution #3: Use absolute imports and setuptools

The steps are –

  1. Replace explicit relative imports with equivalent absolute imports

  2. Install package to make it importable

For instance, the directory structure may be as follows

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

where setup.py is

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

The rest of the files were borrowed from the Solution #1.

Installation will allow you to import the package regardless of your working directory (assuming there’ll be no naming issues).

We can modify standalone.py to use this advantage (step 1):

from package import module  # absolute import

Change your working directory to project and run /path/to/python/interpreter setup.py install --user (--user installs the package in your site-packages directory) (step 2):

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

Let’s verify that it’s now possible to run standalone.py as a script:

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

Note: If you decide to go down this route, you’d be better off using virtual environments to install packages in isolation.

Solution #4: Use absolute imports and some boilerplate code

Frankly, the installation is not necessary – you could add some boilerplate code to your script to make absolute imports work.

I’m going to borrow files from Solution #1 and change standalone.py:

  1. Add the parent directory of package to sys.path before attempting to import anything from package using absolute imports:

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
    
  2. Replace the relative import by the absolute import:

    from package import module  # absolute import
    

standalone.py runs without problems:

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

I feel that I should warn you: try not to do this, especially if your project has a complex structure.


As a side note, PEP 8 recommends the use of absolute imports, but states that in some scenarios explicit relative imports are acceptable:

Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages). […] However, explicit relative imports are an acceptable alternative to absolute imports, especially when dealing with complex package layouts where using absolute imports would be unnecessarily verbose.


回答 2

将其放入包的__init__.py文件中

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

假设您的包裹是这样的:

├── project
   ├── package
      ├── __init__.py
      ├── module1.py
      └── module2.py
   └── setup.py

现在在包中使用常规导入,例如:

# in module2.py
from module1 import class1

这适用于python 2和3。

Put this inside your package’s __init__.py file:

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

Assuming your package is like this:

├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module1.py
│   │   └── module2.py
│   └── setup.py

Now use regular imports in you package, like:

# in module2.py
from module1 import class1

This works in both python 2 and 3.


回答 3

我遇到了这个问题。黑客的解决方法是通过if / else块导入,如下所示:

#!/usr/bin/env python3
#myothermodule

if __name__ == '__main__':
    from mymodule import as_int
else:
    from .mymodule import as_int


# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

I ran into this issue. A hack workaround is importing via an if/else block like follows:

#!/usr/bin/env python3
#myothermodule

if __name__ == '__main__':
    from mymodule import as_int
else:
    from .mymodule import as_int


# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

回答 4

希望这对那里的某人有价值-我浏览了六堆stackoverflow帖子,试图找出与上面上面发布的内容类似的相对进口量。我按照建议设置了所有内容,但仍在执行ModuleNotFoundError: No module named 'my_module_name'

由于我只是在本地开发和玩耍,所以我没有创建/运行setup.py文件。我也没有明显地设置了我PYTHONPATH

我意识到,当我像在模块位于同一目录中那样运行代码时,找不到模块:

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

但是,当我明确指定路径时,事情开始起作用:

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

因此,如果有人尝试了一些建议,则认为他们的代码结构正确,并且如果您不将当前目录导出到PYTHONPATH,则仍然遇到与我类似的情况:

  1. 运行您的代码,并明确包含如下路径: $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. 为避免调用PYTHONPATH=.,请创建一个setup.py内容如下的文件,然后运行python setup.py development以将软件包添加到路径中:
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)

Hopefully, this will be of value to someone out there – I went through half a dozen stackoverflow posts trying to figure out relative imports similar to whats posted above here. I set up everything as suggested but I was still hitting ModuleNotFoundError: No module named 'my_module_name'

Since I was just developing locally and playing around, I hadn’t created/run a setup.py file. I also hadn’t apparently set my PYTHONPATH.

I realized that when I ran my code as I had been when the tests were in the same directory as the module, I couldn’t find my module:

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

However, when I explicitly specified the path things started to work:

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

So, in the event that anyone has tried a few suggestions, believes their code is structured correctly and still finds themselves in a similar situation as myself try either of the following if you don’t export the current directory to your PYTHONPATH:

  1. Run your code and explicitly include the path like so: $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. To avoid calling PYTHONPATH=., create a setup.py file with contents like the following and run python setup.py development to add packages to the path:
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)

回答 5

我需要从主项目目录运行python3才能使其工作。

例如,如果项目具有以下结构:

project_demo/
├── main.py
├── some_package/
   ├── __init__.py
   └── project_configs.py
└── test/
    └── test_project_configs.py

我将在文件夹project_demo /中运行python3 ,然后执行

from some_package import project_configs

I needed to run python3 from the main project directory to make it work.

For example, if the project has the following structure:

project_demo/
├── main.py
├── some_package/
│   ├── __init__.py
│   └── project_configs.py
└── test/
    └── test_project_configs.py

Solution

I would run python3 inside folder project_demo/ and then perform a

from some_package import project_configs

回答 6

为了解决这个问题,我设计了带有重新包装软件包的解决方案,该解决方案已经为我服务了一段时间。它将上层目录添加到lib路径:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

重新打包可以使用智能策略(检查调用堆栈)进行相对导入,从而在各种情况下都起作用。

To obviate this problem, I devised a solution with the repackage package, which has worked for me for some time. It adds the upper directory to the lib path:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

Repackage can make relative imports that work in a wide range of cases, using an intelligent strategy (inspecting the call stack).


回答 7

如果两个软件包都在您的导入路径(sys.path)中,并且您想要的模块/类在example / example.py中,则在没有相对导入的情况下访问该类,请尝试:

from example.example import fkt

if both packages are in your import path (sys.path), and the module/class you want is in example/example.py, then to access the class without relative import try:

from example.example import fkt

回答 8

我认为最好的解决方案是为您的模块创建一个软件包: 是有关如何执行操作的更多信息。

有了软件包后,您就不必担心相对导入了,就可以进行绝对导入。

I think the best solution is to create a package for your module: Here is more info on how to do it.

Once you have a package you don’t need to worry about relative import, you can just do absolute imports.


回答 9

我有一个类似的问题:我需要一个Linux服务和cgi插件,它们使用公共常量进行协作。做到这一点的“自然”方法是将它们放在程序包的init .py中,但是我无法使用-m参数启动cgi插件。

我的最终解决方案与上述解决方案2类似:

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

缺点是必须在常量(或通用函数)前加上pkg:

print(pkg.Glob)

I had a similar problem: I needed a Linux service and cgi plugin which use common constants to cooperate. The ‘natural’ way to do this is to place them in the init.py of the package, but I cannot start the cgi plugin with the -m parameter.

My final solution was similar to Solution #2 above:

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

The disadvantage is that you must prefix the constants (or common functions) with pkg:

print(pkg.Glob)

什么是__pycache__?

问题:什么是__pycache__?

据我了解,缓存是类似文件的加密文件。

__pycache__文件夹怎么办?是我们提供给人们的,而不是我们提供的源代码吗?只是我的输入数据吗?这个文件夹不断创建,它是做什么用的?

From what I understand, a cache is an encrypted file of similar files.

What do we do with the __pycache__ folder? Is it what we give to people instead of our source code? Is it just my input data? This folder keeps getting created, what it is for?


回答 0

当您在python中运行程序时,解释器首先将其编译为字节码(这过于简化),并将其存储在__pycache__文件夹中。如果在其中查看,则会在项目文件夹中找到一堆共享.py文件名的文件,只有它们的扩展名是.pyc或.pyo。它们分别是程序文件的字节码编译版本和优化的字节码编译版本。

作为程序员,您基本上可以忽略它……它所做的只是使您的程序启动更快。脚本更改时,将重新编译它们,如果删除文件或整个文件夹并再次运行程序,它们将重新出现(除非您明确禁止这种行为)

如果您使用的是cpython(这是最常见的实现,因为它是参考实现),并且您不想要该文件夹,则可以通过使用-B标志启动解释器来取消显示该文件夹。

python -B foo.py

如tcaswell所述,另一种选择是将环境变量设置PYTHONDONTWRITEBYTECODE为任何值(根据python的手册页,任何“非空字符串”)。

When you run a program in python, the interpreter compiles it to bytecode first (this is an oversimplification) and stores it in the __pycache__ folder. If you look in there you will find a bunch of files sharing the names of the .py files in your project’s folder, only their extensions will be either .pyc or .pyo. These are bytecode-compiled and optimized bytecode-compiled versions of your program’s files, respectively.

As a programmer, you can largely just ignore it… All it does is make your program start a little faster. When your scripts change, they will be recompiled, and if you delete the files or the whole folder and run your program again, they will reappear (unless you specifically suppress that behavior)

If you are using cpython (which is the most common, as it’s the reference implementation) and you don’t want that folder, then you can suppress it by starting the interpreter with the -B flag, for example

python -B foo.py

Another option, as noted by tcaswell, is to set the environment variable PYTHONDONTWRITEBYTECODE to any value (according to python’s man page, any “non-empty string”).


回答 1

__pycache__是一个包含已编译并准备执行的Python 3字节码的文件夹。

我不建议您定期删除这些文件或在开发过程中禁止创建文件,因为这可能会影响性能。只需准备好一个递归命令(请参见下文)即可在需要时进行清理,因为在极端情况下字节码可能会变得过时(请参见注释)。

Python程序员通常忽略字节码。事实上,__pycache__*.pyc有共同线看.gitignore文件。字节码不用于分发,可以使用dismodule进行反汇编。


如果使用的是OS X,则可以通过从项目的根文件夹运行以下命令来轻松地将所有这些文件夹隐藏在项目中。

find . -name '__pycache__' -exec chflags hidden {} \;

更换__pycache__*.pyc的Python 2。

这会在所有这些目录(.pyc文件)上设置一个标志,告诉Finder / Textmate 2将其从列表中排除。重要的是字节码在那里,它只是隐藏的。

如果创建新模块并希望隐藏新的字节码或删除隐藏的字节码文件,请重新运行该命令。


在Windows上,可以使用等效命令(未经测试,欢迎使用批处理脚本):

dir * /s/b | findstr __pycache__ | attrib +h +s +r

这与使用右键单击>隐藏…浏览项目隐藏文件夹相同。


运行单元测试是一种方案(在注释中更多),在该方案中删除*.pyc文件和__pycache__文件夹确实很有用。我在我的代码中使用以下几行,~/.bash_profilecl在需要时进行清理。

alias cpy='find . -name "__pycache__" -delete'
alias cpc='find . -name "*.pyc"       -delete'
...
alias cl='cpy && cpc && ...'

__pycache__ is a folder containing Python 3 bytecode compiled and ready to be executed.

I don’t recommend routinely deleting these files or suppressing creation during development as it may hurt performance. Just have a recursive command ready (see below) to clean up when needed as bytecode can become stale in edge cases (see comments).

Python programmers usually ignore bytecode. Indeed __pycache__ and *.pyc are common lines to see in .gitignore files. Bytecode is not meant for distribution and can be disassembled using dis module.


If you are using OS X you can easily hide all of these folders in your project by running following command from the root folder of your project.

find . -name '__pycache__' -exec chflags hidden {} \;

Replace __pycache__ with *.pyc for Python 2.

This sets a flag on all those directories (.pyc files) telling Finder/Textmate 2 to exclude them from listings. Importantly the bytecode is there, it’s just hidden.

Rerun the command if you create new modules and wish to hide new bytecode or if you delete the hidden bytecode files.


On Windows the equivalent command might be (not tested, batch script welcome):

dir * /s/b | findstr __pycache__ | attrib +h +s +r

Which is same as going through the project hiding folders using right-click > hide…


Running unit tests is one scenario (more in comments) where deleting the *.pyc files and __pycache__ folders is indeed useful. I use the following lines in my ~/.bash_profile and just run cl to clean up when needed.

alias cpy='find . -name "__pycache__" -delete'
alias cpc='find . -name "*.pyc"       -delete'
...
alias cl='cpy && cpc && ...'

回答 2

__pycache__使用以下行时将创建一个文件夹:

import file_name

或尝试从您创建的另一个文件中获取信息。这使得第二次运行程序打开另一个文件时速度更快。

A __pycache__ folder is created when you use the line:

import file_name

or try to get information from another file you have created. This makes it a little faster when running your program the second time to open the other file.


回答 3

更新了3.7+文档中的答案:

为了加快模块的加载速度,Python将每个模块的编译版本都缓存在__pycache__名称下的 目录中module.version.pyc,该版本对编译文件的格式进行编码;它通常包含Python版本号。例如,在CPython版本3.3中,spam.py的编译版本将被缓存为__pycache__/spam.cpython-33.pyc。此命名约定允许来自不同发行版和不同版本的Python的编译模块共存。

来源:https : //docs.python.org/3/tutorial/modules.html#compiled-python-files

也就是说,该目录由Python生成,并且存在以使您的程序运行更快。它不应致力于源代码控制,而应与本地源代码共存。


__pycache__是一个目录,其中包含由python自动生成的字节码缓存文件,即已编译的python或.pyc文件。您可能想知道为什么Python(一种“解释”语言)根本没有任何编译文件。这个SO问题解决了这个问题(绝对值得阅读此答案)。

python文档更深入地介绍了它的确切工作方式及其存在的原因:

  • 它是在python 3.2中添加的,因为现有的将.pyc文件保存在同一目录中的系统会引起各种问题,例如,使用不同版本的Python解释器运行程序时。有关完整功能的规范,请参阅PEP 3174

Updated answer from 3.7+ docs:

To speed up loading modules, Python caches the compiled version of each module in the __pycache__ directory under the name module.version.pyc, where the version encodes the format of the compiled file; it generally contains the Python version number. For example, in CPython release 3.3 the compiled version of spam.py would be cached as __pycache__/spam.cpython-33.pyc. This naming convention allows compiled modules from different releases and different versions of Python to coexist.

Source: https://docs.python.org/3/tutorial/modules.html#compiled-python-files

That is, this directory is generated by Python and exists to make your programs run faster. It shouldn’t be committed to source control, and should coexist in peace with your local source code.


__pycache__ is a directory that contains bytecode cache files that are automatically generated by python, namely compiled python, or .pyc, files. You might be wondering why Python, an “interpreted” language, has any compiled files at all. This SO question addresses that (and it’s definitely worth reading this answer).

The python docs go into more depth about exactly how it works and why it exists:

  • It was added in python 3.2 because the existing system of maintaining .pyc files in the same directory caused various problems, such as when a program was run with Python interpreters of different versions. For the full feature spec, see PEP 3174.

回答 4

来自官方python教程模块

为了加快模块的加载速度,Python将每个模块的编译版本都缓存在__pycache__名称下的目录中module.version.pyc,该版本对编译文件的格式进行编码;它通常包含Python版本号。例如,在CPython版本3.6中,spam.py的编译版本将被缓存为__pycache__/spam.cpython-36.pyc

来自Python doc 编程常见问题解答

首次导入模块时(或自创建当前编译文件以来源文件已更改),应在__pycache__包含该.py文件的目录的子目录中创建一个包含编译代码的.pyc 文件。该.pyc文件的文件名以与该.py文件相同的名称开头,以结尾.pyc,其中间部分取决于创建该文件的特定python二进制文件。

from the official python tutorial Modules

To speed up loading modules, Python caches the compiled version of each module in the __pycache__ directory under the name module.version.pyc, where the version encodes the format of the compiled file; it generally contains the Python version number. For example, in CPython release 3.6 the compiled version of spam.py would be cached as __pycache__/spam.cpython-36.pyc.

from Python doc Programming FAQs

When a module is imported for the first time (or when the source file has changed since the current compiled file was created) a .pyc file containing the compiled code should be created in a __pycache__ subdirectory of the directory containing the .py file. The .pyc file will have a filename that starts with the same name as the .py file, and ends with .pyc, with a middle component that depends on the particular python binary that created it.


回答 5

执行python脚本将导致字节码在内存中生成并保留直到程序关闭。如果导入了模块,则为了提高重用性,Python会创建一个缓存.pyc(PYC是“ Python”“已编译”)文件,其中将要导入的模块的字节码存储在该文件中。想法是通过避免重新导入时避免重新编译(一次编译,多次运行策略)来加快python模块的加载。

文件名与模块名相同。起始点后面的部分表示创建缓存的Python实现(可以是CPython),其后是版本号。

Execution of a python script would cause the byte code to be generated in memory and kept until the program is shutdown. In case a module is imported, for faster reusability, Python would create a cache .pyc (PYC is ‘Python’ ‘Compiled’) file where the byte code of the module being imported is cached. Idea is to speed up loading of python modules by avoiding re-compilation ( compile once, run multiple times policy ) when they are re-imported.

The name of the file is the same as the module name. The part after the initial dot indicates Python implementation that created the cache (could be CPython) followed by its version number.


回答 6

python解释器编译* .py脚本文件,并将编译结果保存到__pycache__目录中。

当再次执行该项目时,如果解释器识别出* .py脚本尚未被修改,则它将跳过编译步骤并运行存储在该__pycache__文件夹中的先前生成的* .pyc文件。

当项目很复杂时,您可以缩短项目运行的准备时间。如果程序太小,则可以通过python -B abc.pyB选项一起使用来忽略它。

The python interpreter compiles the *.py script file and saves the results of the compilation to the __pycache__ directory.

When the project is executed again, if the interpreter identifies that the *.py script has not been modified, it skips the compile step and runs the previously generated *.pyc file stored in the __pycache__ folder.

When the project is complex, you can make the preparation time before the project is run shorter. If the program is too small, you can ignore that by using python -B abc.py with the B option.


回答 7

解释器编译代码时,Python版本2.x将具有.pyc

当解释器编译代码时,Python版本3.x将具有__pycache__

alok@alok:~$ ls
module.py  module.pyc  __pycache__  test.py
alok@alok:~$

Python Version 2.x will have .pyc when interpreter compiles the code.

Python Version 3.x will have __pycache__ when interpreter compiles the code.

alok@alok:~$ ls
module.py  module.pyc  __pycache__  test.py
alok@alok:~$

回答 8

在3.2及更高版本中,Python将.pyc编译后的字节代码文件保存在一个子目录__pycache__中,该子目录位于源文件所在的目录中,该目录中带有标识创建它们的Python版本的文件名(例如script.cpython-33.pyc)。

In 3.2 and later, Python saves .pyc compiled byte code files in a sub-directory named __pycache__ located in the directory where your source files reside with filenames that identify the Python version that created them (e.g. script.cpython-33.pyc)


回答 9

当您导入模块

import file_name

Python将已编译的字节码存储在__pycache__目录中,以便将来的导入可以直接使用它,而不必再次解析和编译源代码。

仅导入文件时,它不会仅运行脚本就这样做。

(以前的版本用于将缓存的字节码存储为.pyc文件,这些文件与.py文件位于同一目录中,但是从Python 3开始,它们被移到了一个子目录以使内容变得整洁。)

PYTHONDONTWRITEBYTECODE —>如果将其设置为非空字符串,Python将不会尝试在源模块的导入中写入.pyc文件。这等效于指定-B选项。

When you import a module,

import file_name

Python stores the compiled bytecode in __pycache__ directory so that future imports can use it directly, rather than having to parse and compile the source again.

It does not do that for merely running a script, only when a file is imported.

(Previous versions used to store the cached bytecode as .pyc files that littered up the same directory as the .py files, but starting in Python 3 they were moved to a subdirectory to make things tidier.)

PYTHONDONTWRITEBYTECODE —> If this is set to a non-empty string, Python won’t try to write .pyc files on the import of source modules. This is equivalent to specifying the -B option.