分类目录归档:知识问答

在Python中使用** kwargs的正确方法

问题:在Python中使用** kwargs的正确方法

关于**kwargs默认值,在Python中使用的正确方法是什么?

kwargs返回一本字典,但是设置默认值的最佳方法是什么?我应该以字典的形式访问它吗?使用获取功能?

class ExampleClass:
    def __init__(self, **kwargs):
        self.val = kwargs['val']
        self.val2 = kwargs.get('val2')

一个简单的问题,但是我找不到很好的资源。人们在我见过的代码中以不同的方式进行操作,很难知道该使用什么。

What is the proper way to use **kwargs in Python when it comes to default values?

kwargs returns a dictionary, but what is the best way to set default values, or is there one? Should I just access it as a dictionary? Use get function?

class ExampleClass:
    def __init__(self, **kwargs):
        self.val = kwargs['val']
        self.val2 = kwargs.get('val2')

A simple question, but one that I can’t find good resources on. People do it different ways in code that I’ve seen and it’s hard to know what to use.


回答 0

您可以将默认值传递给get()不在字典中的键:

self.val2 = kwargs.get('val2',"default value")

但是,如果计划使用具有特定默认值的特定参数,为什么不首先使用命名参数?

def __init__(self, val2="default value", **kwargs):

You can pass a default value to get() for keys that are not in the dictionary:

self.val2 = kwargs.get('val2',"default value")

However, if you plan on using a particular argument with a particular default value, why not use named arguments in the first place?

def __init__(self, val2="default value", **kwargs):

回答 1

虽然大多数答案都在说,例如,

def f(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...etc...

是相同的”

def f(foo=None, bar=None, **kwargs):
    ...etc...

这不是真的。在后一种情况下,f可以称为f(23, 42),而前一种情况接受命名参数-不能进行位置调用。通常,您想让调用者具有最大的灵活性,因此,如大多数答案所断言的那样,第二种形式是可取的:但这并非总是如此。当您接受许多通常仅传递几个可选参数的可选参数时,强制使用命名参数可能是一个好主意(避免意外和调用代码不可读!)threading.Thread就是一个例子。第一种形式是如何在Python 2中实现它。

成语是如此重要,以至于在Python 3现在有专门的配套语法:单后每个参数*def签名关键字只,也就是说,不能被作为位置参数传递,但只是作为一个命名的。因此,在Python 3中,您可以将上述代码编写为:

def f(*, foo=None, bar=None, **kwargs):
    ...etc...

实际上,在Python 3中,您甚至可以具有可选的仅关键字参数(没有默认值的参数)。

但是,Python 2仍有很长的生产寿命,因此最好不要忘记使您能够在Python 2中实现重要设计思想的技术和习惯用法,而Python 3语言直接支持这些重要设计思想!

While most answers are saying that, e.g.,

def f(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...etc...

is “the same as”

def f(foo=None, bar=None, **kwargs):
    ...etc...

this is not true. In the latter case, f can be called as f(23, 42), while the former case accepts named arguments only — no positional calls. Often you want to allow the caller maximum flexibility and therefore the second form, as most answers assert, is preferable: but that is not always the case. When you accept many optional parameters of which typically only a few are passed, it may be an excellent idea (avoiding accidents and unreadable code at your call sites!) to force the use of named arguments — threading.Thread is an example. The first form is how you implement that in Python 2.

The idiom is so important that in Python 3 it now has special supporting syntax: every argument after a single * in the def signature is keyword-only, that is, cannot be passed as a positional argument, but only as a named one. So in Python 3 you could code the above as:

def f(*, foo=None, bar=None, **kwargs):
    ...etc...

Indeed, in Python 3 you can even have keyword-only arguments that aren’t optional (ones without a default value).

However, Python 2 still has long years of productive life ahead, so it’s better to not forget the techniques and idioms that let you implement in Python 2 important design ideas that are directly supported in the language in Python 3!


回答 2

我建议像这样

def testFunc( **kwargs ):
    options = {
            'option1' : 'default_value1',
            'option2' : 'default_value2',
            'option3' : 'default_value3', }

    options.update(kwargs)
    print options

testFunc( option1='new_value1', option3='new_value3' )
# {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'}

testFunc( option2='new_value2' )
# {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}

然后根据需要使用值

dictionaryA.update(dictionaryB)添加的内容dictionaryBdictionaryA覆盖任何重复的密钥。

I suggest something like this

def testFunc( **kwargs ):
    options = {
            'option1' : 'default_value1',
            'option2' : 'default_value2',
            'option3' : 'default_value3', }

    options.update(kwargs)
    print options

testFunc( option1='new_value1', option3='new_value3' )
# {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'}

testFunc( option2='new_value2' )
# {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}

And then use the values any way you want

dictionaryA.update(dictionaryB) adds the contents of dictionaryB to dictionaryA overwriting any duplicate keys.


回答 3

你会的

self.attribute = kwargs.pop('name', default_value)

要么

self.attribute = kwargs.get('name', default_value)

如果使用pop,则可以检查是否发送了任何虚假值,并采取适当的措施(如果有)。

You’d do

self.attribute = kwargs.pop('name', default_value)

or

self.attribute = kwargs.get('name', default_value)

If you use pop, then you can check if there are any spurious values sent, and take the appropriate action (if any).


回答 4

使用** kwargs和默认值很容易。但是,有时候,您不应该一开始就使用** kwargs。

在这种情况下,我们并没有真正充分利用** kwargs。

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = kwargs.get('val',"default1")
        self.val2 = kwargs.get('val2',"default2")

以上是“为什么要打扰?” 宣言。与…相同

class ExampleClass( object ):
    def __init__(self, val="default1", val2="default2"):
        self.val = val
        self.val2 = val2

当您使用** kwargs时,意味着关键字不仅是可选的,而且是有条件的。规则比简单的默认值复杂得多。

当您使用** kwargs时,通常意味着类似以下内容,其中简单的默认值不适用。

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = "default1"
        self.val2 = "default2"
        if "val" in kwargs:
            self.val = kwargs["val"]
            self.val2 = 2*self.val
        elif "val2" in kwargs:
            self.val2 = kwargs["val2"]
            self.val = self.val2 / 2
        else:
            raise TypeError( "must provide val= or val2= parameter values" )

Using **kwargs and default values is easy. Sometimes, however, you shouldn’t be using **kwargs in the first place.

In this case, we’re not really making best use of **kwargs.

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = kwargs.get('val',"default1")
        self.val2 = kwargs.get('val2',"default2")

The above is a “why bother?” declaration. It is the same as

class ExampleClass( object ):
    def __init__(self, val="default1", val2="default2"):
        self.val = val
        self.val2 = val2

When you’re using **kwargs, you mean that a keyword is not just optional, but conditional. There are more complex rules than simple default values.

When you’re using **kwargs, you usually mean something more like the following, where simple defaults don’t apply.

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = "default1"
        self.val2 = "default2"
        if "val" in kwargs:
            self.val = kwargs["val"]
            self.val2 = 2*self.val
        elif "val2" in kwargs:
            self.val2 = kwargs["val2"]
            self.val = self.val2 / 2
        else:
            raise TypeError( "must provide val= or val2= parameter values" )

回答 5

由于**kwargs在参数个数未知时使用,为什么不这样做呢?

class Exampleclass(object):
  def __init__(self, **kwargs):
    for k in kwargs.keys():
       if k in [acceptable_keys_list]:
          self.__setattr__(k, kwargs[k])

Since **kwargs is used when the number of arguments is unknown, why not doing this?

class Exampleclass(object):
  def __init__(self, **kwargs):
    for k in kwargs.keys():
       if k in [acceptable_keys_list]:
          self.__setattr__(k, kwargs[k])

回答 6

这是另一种方法:

def my_func(arg1, arg2, arg3):
    ... so something ...

kwargs = {'arg1': 'Value One', 'arg2': 'Value Two', 'arg3': 'Value Three'}
# Now you can call the function with kwargs like this:

my_func(**kwargs)

Here’s another approach:

def my_func(arg1, arg2, arg3):
    ... so something ...

kwargs = {'arg1': 'Value One', 'arg2': 'Value Two', 'arg3': 'Value Three'}
# Now you can call the function with kwargs like this:

my_func(**kwargs)

回答 7

我认为在**kwargs默认值上使用Python 的正确方法是使用dictionary方法setdefault,如下所示:

class ExampleClass:
    def __init__(self, **kwargs):
        kwargs.setdefault('val', value1)
        kwargs.setdefault('val2', value2)

这样,如果用户在关键字中传递了’val’或’val2′ args,则将使用它们。否则,将使用已设置的默认值。

I think the proper way to use **kwargs in Python when it comes to default values is to use the dictionary method setdefault, as given below:

class ExampleClass:
    def __init__(self, **kwargs):
        kwargs.setdefault('val', value1)
        kwargs.setdefault('val2', value2)

In this way, if a user passes ‘val’ or ‘val2’ in the keyword args, they will be used; otherwise, the default values that have been set will be used.


回答 8

你可以做这样的事情

class ExampleClass:
    def __init__(self, **kwargs):
        arguments = {'val':1, 'val2':2}
        arguments.update(kwargs)
        self.val = arguments['val']
        self.val2 = arguments['val2']

You could do something like this

class ExampleClass:
    def __init__(self, **kwargs):
        arguments = {'val':1, 'val2':2}
        arguments.update(kwargs)
        self.val = arguments['val']
        self.val2 = arguments['val2']

回答 9

跟进@srhegde建议使用setattr的建议:

class ExampleClass(object):
    __acceptable_keys_list = ['foo', 'bar']

    def __init__(self, **kwargs):
        [self.__setattr__(key, kwargs.get(key)) for key in self.__acceptable_keys_list]

当期望该类具有acceptable列表中的所有项目时,此变体很有用。

Following up on @srhegde suggestion of using setattr:

class ExampleClass(object):
    __acceptable_keys_list = ['foo', 'bar']

    def __init__(self, **kwargs):
        [self.__setattr__(key, kwargs.get(key)) for key in self.__acceptable_keys_list]

This variant is useful when the class is expected to have all of the items in our acceptable list.


回答 10

如果要将其与* args结合使用,则必须在定义末尾保留* args和** kwargs。

所以:

def method(foo, bar=None, *args, **kwargs):
    do_something_with(foo, bar)
    some_other_function(*args, **kwargs)

If you want to combine this with *args you have to keep *args and **kwargs at the end of the definition.

So:

def method(foo, bar=None, *args, **kwargs):
    do_something_with(foo, bar)
    some_other_function(*args, **kwargs)

回答 11

@AbhinavGupta和@Steef建议使用update(),这对处理大型参数列表非常有帮助:

args.update(kwargs)

如果我们要检查用户是否未传递任何虚假/不受支持的参数,该怎么办?@VinaySajip指出,pop()可以用来迭代处理参数列表。然后,任何剩余的参数都是虚假的。真好

这是执行此操作的另一种可能方法,保留了using的简单语法update()

# kwargs = dictionary of user-supplied arguments
# args = dictionary containing default arguments

# Check that user hasn't given spurious arguments
unknown_args = user_args.keys() - default_args.keys()
if unknown_args:
    raise TypeError('Unknown arguments: {}'.format(unknown_args))

# Update args to contain user-supplied arguments
args.update(kwargs)

unknown_args是一个set包含默认值中不出现的参数名称。

@AbhinavGupta and @Steef suggested using update(), which I found very helpful for processing large argument lists:

args.update(kwargs)

What if we want to check that the user hasn’t passed any spurious/unsupported arguments? @VinaySajip pointed out that pop() can be used to iteratively process the list of arguments. Then, any leftover arguments are spurious. Nice.

Here’s another possible way to do this, which keeps the simple syntax of using update():

# kwargs = dictionary of user-supplied arguments
# args = dictionary containing default arguments

# Check that user hasn't given spurious arguments
unknown_args = user_args.keys() - default_args.keys()
if unknown_args:
    raise TypeError('Unknown arguments: {}'.format(unknown_args))

# Update args to contain user-supplied arguments
args.update(kwargs)

unknown_args is a set containing the names of arguments that don’t occur in the defaults.


回答 12

处理未知或多个参数的另一种简单解决方案可以是:

class ExampleClass(object):

    def __init__(self, x, y, **kwargs):
      self.x = x
      self.y = y
      self.attributes = kwargs

    def SomeFunction(self):
      if 'something' in self.attributes:
        dosomething()

Another simple solution for processing unknown or multiple arguments can be:

class ExampleClass(object):

    def __init__(self, x, y, **kwargs):
      self.x = x
      self.y = y
      self.attributes = kwargs

    def SomeFunction(self):
      if 'something' in self.attributes:
        dosomething()

回答 13

** kwargs可以自由添加任意数量的关键字参数。可能会有一个密钥列表,他可以为其设置默认值。但是,不必为无限数量的键设置默认值。最后,将键作为实例属性可能很重要。因此,我将执行以下操作:

class Person(object):
listed_keys = ['name', 'age']

def __init__(self, **kwargs):
    _dict = {}
    # Set default values for listed keys
    for item in self.listed_keys: 
        _dict[item] = 'default'
    # Update the dictionary with all kwargs
    _dict.update(kwargs)

    # Have the keys of kwargs as instance attributes
    self.__dict__.update(_dict)

**kwargs gives the freedom to add any number of keyword arguments. One may have a list of keys for which he can set default values. But setting default values for an indefinite number of keys seems unnecessary. Finally, it may be important to have the keys as instance attributes. So, I would do this as follows:

class Person(object):
listed_keys = ['name', 'age']

def __init__(self, **kwargs):
    _dict = {}
    # Set default values for listed keys
    for item in self.listed_keys: 
        _dict[item] = 'default'
    # Update the dictionary with all kwargs
    _dict.update(kwargs)

    # Have the keys of kwargs as instance attributes
    self.__dict__.update(_dict)

没有名为pkg_resources的模块

问题:没有名为pkg_resources的模块

我正在将Django应用程序部署到开发服务器,并且在运行时遇到此错误pip install -r requirements.txt

Traceback (most recent call last):
  File "/var/www/mydir/virtualenvs/dev/bin/pip", line 5, in <module>
    from pkg_resources import load_entry_point
ImportError: No module named pkg_resources

pkg_resources似乎与一起分发setuptools。最初,我认为可能不会将它安装到virtualenv中的Python,所以我setuptools 2.6使用以下命令将了(与Python相同的版本)安装到virtualenv 中的Python站点软件包中:

sh setuptools-0.6c11-py2.6.egg --install-dir /var/www/mydir/virtualenvs/dev/lib/python2.6/site-packages

编辑:这只发生在virtualenv内部。如果我在virtualenv之外打开控制台,则pkg_resources存在,但仍然出现相同的错误。

关于为什么pkg_resources不在路上的任何想法?

I’m deploying a Django app to a dev server and am hitting this error when I run pip install -r requirements.txt:

Traceback (most recent call last):
  File "/var/www/mydir/virtualenvs/dev/bin/pip", line 5, in <module>
    from pkg_resources import load_entry_point
ImportError: No module named pkg_resources

pkg_resources appears to be distributed with setuptools. Initially I thought this might not be installed to the Python in the virtualenv, so I installed setuptools 2.6 (same version as Python) to the Python site-packages in the virtualenv with the following command:

sh setuptools-0.6c11-py2.6.egg --install-dir /var/www/mydir/virtualenvs/dev/lib/python2.6/site-packages

EDIT: This only happens inside the virtualenv. If I open a console outside the virtualenv then pkg_resources is present, but I am still getting the same error.

Any ideas as to why pkg_resources is not on the path?


回答 0

2018年7月更新

现在大多数人都应该使用pip install setuptools(可能与一起使用sudo)。

有些人可能需要(重新)安装python-setuptools通过他们的软件包管理的软件包(apt-get installyum install,等)。

此问题可能高度取决于您的操作系统和开发环境。如果上述方法不适用于您,请参见下面的旧式/其他答案。

说明

此错误消息是由缺少/损坏的Python setuptools软件包引起的。根据Matt M.的注释和setuptools问题#581,以下引用的引导脚本不再是推荐的安装方法。

如果仍然对任何人有帮助,引导脚本说明将保留在下面。

旧版答案

ImportError今天在尝试使用点子时遇到了同样的问题。不知何故,该setuptools软件包已在我的Python环境中删除。

要解决此问题,请运行以下安装脚本setuptools

wget https://bootstrap.pypa.io/ez_setup.py -O - | python

(或者,如果您尚未wget安装(例如OS X),请尝试

curl https://bootstrap.pypa.io/ez_setup.py | python

可能带有sudo前缀。)

如果您使用的任何版本distribute,或setuptools0.6以下的版本,则必须先将其卸载。*

有关更多详细信息,请参见安装说明


*如果您已经可以使用distribute,则将其升级到“兼容性包装器” setuptools可以更轻松地进行切换。但是,如果事情已经坏了,请不要尝试。

July 2018 Update

Most people should now use pip install setuptools (possibly with sudo).

Some may need to (re)install the python-setuptools package via their package manager (apt-get install, yum install, etc.).

This issue can be highly dependent on your OS and dev environment. See the legacy/other answers below if the above isn’t working for you.

Explanation

This error message is caused by a missing/broken Python setuptools package. Per Matt M.’s comment and setuptools issue #581, the bootstrap script referred to below is no longer the recommended installation method.

The bootstrap script instructions will remain below, in case it’s still helpful to anyone.

Legacy Answer

I encountered the same ImportError today while trying to use pip. Somehow the setuptools package had been deleted in my Python environment.

To fix the issue, run the setup script for setuptools:

wget https://bootstrap.pypa.io/ez_setup.py -O - | python

(or if you don’t have wget installed (e.g. OS X), try

curl https://bootstrap.pypa.io/ez_setup.py | python

possibly with sudo prepended.)

If you have any version of distribute, or any setuptools below 0.6, you will have to uninstall it first.*

See Installation Instructions for further details.


* If you already have a working distribute, upgrading it to the “compatibility wrapper” that switches you over to setuptools is easier. But if things are already broken, don’t try that.


回答 1

sudo apt-get install --reinstall python-pkg-resources

在Debian中为我修复了该问题。似乎卸载某些.deb软件包(在我的情况下为扭曲集)已破坏python用于查找软件包的路径

sudo apt-get install --reinstall python-pkg-resources

fixed it for me in Debian. Seems like uninstalling some .deb packages (twisted set in my case) has broken the path python uses to find packages


回答 2

尝试在Ubuntu 13.10上将rhodecode安装到virtualenv时,我已经看到此错误。对我来说,解决方案是运行

pip install --upgrade setuptools
pip install --upgrade distribute 

在运行easy_install rhodecode之前。

I have seen this error while trying to install rhodecode to a virtualenv on ubuntu 13.10. For me the solution was to run

pip install --upgrade setuptools
pip install --upgrade distribute 

before I run easy_install rhodecode.


回答 3

这也发生在我身上。我认为,在virtualenv使用setuptools的情况下,如果requirements.txt包含“ distribute”条目,则会出现此问题。Pip将尝试修补setuptools以便为分发腾出空间,但不幸的是,它将失败一半。

一种简单的解决方案是删除当前的virtualenv,然后使用–distribute参数创建一个新的virtualenv。

如果使用virtualenvwrapper的示例:

$ deactivate
$ rmvirtualenv yourenv
$ mkvirtualenv yourenv --distribute
$ workon yourenv
$ pip install -r requirements.txt

It also happened to me. I think the problem will happen if the requirements.txt contains a “distribute” entry while the virtualenv uses setuptools. Pip will try to patch setuptools to make room for distribute, but unfortunately it will fail half way.

The easy solution is delete your current virtualenv then make a new virtualenv with –distribute argument.

An example if using virtualenvwrapper:

$ deactivate
$ rmvirtualenv yourenv
$ mkvirtualenv yourenv --distribute
$ workon yourenv
$ pip install -r requirements.txt

回答 4

在CentOS 6中,安装软件包python-setuptools对其进行了修复。

yum install python-setuptools

In CentOS 6 installing the package python-setuptools fixed it.

yum install python-setuptools

回答 5

我之前有这个错误,评分最高的答案给我一个错误,试图下载ez_setup.py文件。我找到了另一个来源,因此您可以运行以下命令:

curl http://peak.telecommunity.com/dist/ez_setup.py | python

我发现还必须使用sudo它才能使其正常工作,因此您可能需要运行:

sudo curl http://peak.telecommunity.com/dist/ez_setup.py | sudo python

我还创建了另一个位置,可以从以下位置下载脚本:

https://gist.github.com/ajtrichards/42e73562a89edb1039f3

I had this error earlier and the highest rated answer gave me an error trying to download the ez_setup.py file. I found another source so you can run the command:

curl http://peak.telecommunity.com/dist/ez_setup.py | python

I found that I also had to use sudo to get it working, so you may need to run:

sudo curl http://peak.telecommunity.com/dist/ez_setup.py | sudo python

I’ve also created another location that the script can be downloaded from:

https://gist.github.com/ajtrichards/42e73562a89edb1039f3


回答 6

在尝试了以下几个答案之后,与一位同事联系,在Ubuntu 16.04上为我工作的是:

pip install --force-reinstall -U setuptools
pip install --force-reinstall -U pip

就我而言,只有枕头3.1.1的旧版本有问题(枕头4.x正常工作),现在已解决!

After trying several of these answers, then reaching out to a colleague, what worked for me on Ubuntu 16.04 was:

pip install --force-reinstall -U setuptools
pip install --force-reinstall -U pip

In my case, it was only an old version of pillow 3.1.1 that was having trouble (pillow 4.x worked fine), and that’s now resolved!


回答 7

需要更多的须藤。然后使用easy_install安装pip。作品。

sudo wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python
sudo easy_install pip

Needed a little bit more sudo. Then used easy_install to install pip. Works.

sudo wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python
sudo easy_install pip

回答 8

我通过执行以下操作修复了virtualenv的错误:

从复制了pkg_resources.py

/Library/Python/2.7/site-packages/setuptools

/Library/Python/2.7/site-packages/

这可能是一个便宜的解决方法,但对我有用。

如果不存在安装工具,则可以通过键入尝试安装系统站点软件包virtualenv --system-site-packages /DESTINATION DIRECTORY,将最后一部分更改为要安装到的目录。pkg_rousources.py将在lib / python2.7 / site-packages中的该目录下

I fixed the error with virtualenv by doing this:

Copied pkg_resources.py from

/Library/Python/2.7/site-packages/setuptools

to

/Library/Python/2.7/site-packages/

This may be a cheap workaround, but it worked for me.

.

If setup tools doesn’t exist, you can try installing system-site-packages by typing virtualenv --system-site-packages /DESTINATION DIRECTORY, changing the last part to be the directory you want to install to. pkg_rousources.py will be under that directory in lib/python2.7/site-packages


回答 9

对我来说,导致此错误是因为我有一个名为“ site”的子目录!我不知道这是否是pip错误,但我从以下内容开始:

/some/dir/requirements.txt / some / dir / site /

pip install -r requirements.txt无法正常工作,出现上述错误!

将子文件夹从“ site”重命名为“ src”解决了该问题!也许pip正在寻找“网站包装”?疯。

For me, this error was being caused because I had a subdirectory called “site”! I don’t know if this is a pip bug or not, but I started with:

/some/dir/requirements.txt /some/dir/site/

pip install -r requirements.txt wouldn’t work, giving me the above error!

renaming the subfolder from “site” to “src” fixed the problem! Maybe pip is looking for “site-packages”? Crazy.


回答 10

当我将我的virtualenv激活为不同于创建它的用户时,我遇到了这个问题。看来是权限问题。我在尝试@cwc的答案时发现了这一点,并在输出中看到了这一点:

Installing easy_install script to /path/env/bin
error: /path/env/bin/easy_install: Permission denied

切换回创建virtualenv的用户,然后运行原始pip install命令没有任何问题。希望这可以帮助!

I had this problem when I had activated my virtualenv as a different user than the one who created it. It seems to be a permission problem. I discovered this when I tried the answer by @cwc and saw this in the output:

Installing easy_install script to /path/env/bin
error: /path/env/bin/easy_install: Permission denied

Switching back to the user that created the virtualenv, then running the original pip install command went without problems. Hope this helps!


回答 11

我今天也有这个问题。我只在虚拟环境中遇到问题。

对我来说,解决方案是停用虚拟环境,删除后再使用pip卸载virtualenv并重新安装。之后,我为我的项目创建了一个新的虚拟环境,然后pip在虚拟环境中都能正常工作,就像在正常环境中一样。

I had this problem today as well. I only got the problem inside the virtual env.

The solution for me was deactivating the virtual env, deleting and then uninstalling virtualenv with pip and reinstalling it. After that I created a new virtual env for my project, then pip worked fine both inside the virtual environment as in the normal environment.


回答 12

看起来他们已经离开了bitbucket,现在在github(https://github.com/pypa/setuptools)上

运行的命令是:

wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python

Looks like they have moved away from bitbucket and are now on github (https://github.com/pypa/setuptools)

Command to run is:

wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python

回答 13

对我来说,原来是上的权限问题site-packages。由于这只是我的开发环境,因此我提出了权限,然后一切又重新开始了:

sudo chmod -R a+rwx /path/to/my/venv/lib/python2.7/site-packages/

For me, it turned out to be a permissions problem on site-packages. Since it’s only my dev environment, I raised the permissions and everything is working again:

sudo chmod -R a+rwx /path/to/my/venv/lib/python2.7/site-packages/

回答 14

如果通过conda安装的应用程序遇到此问题,则解决方案(如此错误报告中所述)仅是使用以下命令安装安装工具:

conda install setuptools

If you are encountering this issue with an application installed via conda, the solution (as stated in this bug report) is simply to install setup-tools with:

conda install setuptools

回答 15

在Windows上,使用python 3.7,这对我有用:

pip install --upgrade setuptools --user

--user 将软件包安装在您的主目录中,该目录不需要管理员权限。

On Windows, with python 3.7, this worked for me:

pip install --upgrade setuptools --user

--user installs packages in your home directory, which doesn’t require admin privileges.


回答 16

简单的解决方法是您可以使用conda升级setuptools或整个环境。(特别适用于Windows用户。)

conda upgrade -c anaconda setuptools

如果删除了setuptools,则需要再次安装setuptools。

conda install -c anaconda setuptools

如果所有方法均无效,则可以升级conda环境。但是我不建议您需要重新安装和卸载某些软件包,因为这样做会加剧这种情况。

the simple resoluition is that you can use conda to upgrade setuptools or entire enviroment. (Specially for windows user.)

conda upgrade -c anaconda setuptools

if the setuptools is removed, you need to install setuptools again.

conda install -c anaconda setuptools

if these all methodes doesn’t work, you can upgrade conda environement. But I do not recommend that you need to reinstall and uninstall some packages because after that it will exacerbate the situation.


回答 17

显然您缺少setuptools。某些virtualenv版本默认情况下使用分发而不是setuptools。--setuptools在创建virtualenv时使用该选项,或者VIRTUALENV_SETUPTOOLS=1在您的环境中设置。

Apparently you’re missing setuptools. Some virtualenv versions use distribute instead of setuptools by default. Use the --setuptools option when creating the virtualenv or set the VIRTUALENV_SETUPTOOLS=1 in your environment.


回答 18

就我而言,我最初安装了2个python版本,后来又删除了较旧的版本。因此,在创建虚拟环境时

virtualenv venv

指的是卸载的python

什么对我有用

python3 -m virtualenv venv

当您尝试使用点子时也是如此。

In my case, I had 2 python versions installed initially and later I had deleted the older one. So while creating the virtual environment

virtualenv venv

was referring to the uninstalled python

What worked for me

python3 -m virtualenv venv

Same is true when you are trying to use pip.


回答 19

当我尝试遵循本OSX指南时,遇到了这个答案。对我python get-pip有用的是,跑步后,我还必须easy_install pip。这解决了根本无法运行点子的问题。我确实安装了一堆旧的Macport东西。那可能有冲突。

I came across this answer when I was trying to follow this guide for OSX. What worked for me was, after running python get-pip, I had to ALSO easy_install pip. That fixed the issue of not being able to run pip at all. I did have a bunch of old macport stuff installed. That may have conflicted.


回答 20

在Windows上,我安装了从www.lfd.uci.edu/~gohlke/pythonlibs/下载的pip然后出现了这个问题。

所以我应该先安装setuptools(easy_install)。

On windows, I installed pip downloaded from www.lfd.uci.edu/~gohlke/pythonlibs/ then encontered this problem.

So I should have installed setuptools(easy_install) first.


回答 21

只需setuptools通过以下方式重新安装您的:

$ sudo wget https://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz#md5=7df2a529a074f613b509fb44feefefe74e
$ tar -zxvf setuptools-0.6c11.tar.gz
$ cd setuptools-0.6c11/
$ sudo python setup.py build
$ sudo python setup.py install
$ sudo pip install --upgrade setuptools

那么一切都会好起来的。

just reinstall your setuptools by :

$ sudo wget https://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz#md5=7df2a529a074f613b509fb44feefefe74e
$ tar -zxvf setuptools-0.6c11.tar.gz
$ cd setuptools-0.6c11/
$ sudo python setup.py build
$ sudo python setup.py install
$ sudo pip install --upgrade setuptools

then everything will be fine.


回答 22

我使用CentOS 6.7,而我的python刚刚从2.6.6升级到2.7.11,在尝试了许多不同的答案之后,终于有以下一个工作了:

sudo yum install python-devel

希望能帮助同样情况的人。

I use CentOS 6.7, and my python was just upgrade from 2.6.6 to 2.7.11, after tried so many different answer, finally the following one does the job:

sudo yum install python-devel

Hope help someone in the same situation.


回答 23

没有一个发布的答案对我有用,所以我重新安装了pip并成功了!

sudo apt-get install python-setuptools python-dev build-essential 

sudo easy_install pip 

pip install --upgrade setuptools

(参考:http//www.saltycrane.com/blog/2010/02/how-install-pip-ubuntu/

None of the posted answers worked for me, so I reinstalled pip and it worked!

sudo apt-get install python-setuptools python-dev build-essential 

sudo easy_install pip 

pip install --upgrade setuptools

(reference: http://www.saltycrane.com/blog/2010/02/how-install-pip-ubuntu/)


回答 24

更新我的Ubuntu版本后,我遇到了这个问题。它似乎已经遍历并删除了我所有虚拟环境中的设置工具。

为了解决这个问题,我将虚拟环境重新安装回了目标目录。这清理了缺少的设置工具,并使一切重新运行。

例如:

~/RepoDir/TestProject$ virtualenv TestEnvironmentDir

I ran into this problem after updating my Ubuntu build. It seems to have gone through and removed set up tools in all of my virtual environments.

To remedy this I reinstalled the virtual environment back into the target directory. This cleaned up missing setup tools and got things running again.

e.g.:

~/RepoDir/TestProject$ virtualenv TestEnvironmentDir

回答 25

对我来说,一个很好的解决方法是使用--no-download选项virtualenv(VIRTUALENV_NO_DOWNLOAD=1 tox用于tox。)

For me a good fix was to use --no-download option to virtualenv (VIRTUALENV_NO_DOWNLOAD=1 tox for tox.)


回答 26

在Opensuse 42.1上,以下内容解决了此问题:

zypper in python-Pygments

On Opensuse 42.1 the following fixed this issue:

zypper in python-Pygments

回答 27

ImportError:没有名为pkg_resources的模块:解决方法是使用下面的命令重新安装python pip。

步骤:1登录到root用户。

sudo su root

步骤:2卸载python-pip软件包(如果存在)。

apt-get purge -y python-pip

步骤:3使用wget命令下载文件(在中下载文件pwd

wget https://bootstrap.pypa.io/get-pip.py

步骤:4运行python文件。

python ./get-pip.py

步骤:5 Finalic exicute安装命令。

apt-get install python-pip

注意:用户必须是root用户。

ImportError: No module named pkg_resources: the solution is to reinstall python pip using the following Command are under.

Step: 1 Login in root user.

sudo su root

Step: 2 Uninstall python-pip package if existing.

apt-get purge -y python-pip

Step: 3 Download files using wget command(File download in pwd )

wget https://bootstrap.pypa.io/get-pip.py

Step: 4 Run python file.

python ./get-pip.py

Step: 5 Finaly exicute installation command.

apt-get install python-pip

Note: User must be root.


回答 28

我在Google App Engine环境中遇到了该错误。并pip install -t lib setuptools解决了问题。

I experienced that error in my Google App Engine environment. And pip install -t lib setuptools fixed the issue.


回答 29

如果您使用的是Python 3,则应使用pip3而不是pip。该命令看起来像$ pip3 install requirements.txt

If you are using Python 3, you should use pip3 instead of pip. The command looks like $ pip3 install requirements.txt


使用Django和Python创建JSON响应

问题:使用Django和Python创建JSON响应

我正在尝试将服务器端Ajax响应脚本转换为Django HttpResponse,但显然无法正常工作。

这是服务器端脚本:

/* RECEIVE VALUE */
$validateValue=$_POST['validateValue'];
$validateId=$_POST['validateId'];
$validateError=$_POST['validateError'];

/* RETURN VALUE */
$arrayToJs = array();
$arrayToJs[0] = $validateId;
$arrayToJs[1] = $validateError;

if($validateValue =="Testuser"){  // Validate??
    $arrayToJs[2] = "true";       // RETURN TRUE
    echo '{"jsonValidateReturn":'.json_encode($arrayToJs).'}';  // RETURN ARRAY WITH success
}
else{
    for($x=0;$x<1000000;$x++){
        if($x == 990000){
            $arrayToJs[2] = "false";
            echo '{"jsonValidateReturn":'.json_encode($arrayToJs).'}';   // RETURNS ARRAY WITH ERROR.
        }
    }
}

这是转换后的代码

def validate_user(request):
    if request.method == 'POST':
        vld_value = request.POST.get('validateValue')
        vld_id = request.POST.get('validateId')
        vld_error = request.POST.get('validateError')

        array_to_js = [vld_id, vld_error, False]

        if vld_value == "TestUser":
            array_to_js[2] = True
            x = simplejson.dumps(array_to_js)
            return HttpResponse(x)
        else:
            array_to_js[2] = False
            x = simplejson.dumps(array_to_js)
            error = 'Error'
            return render_to_response('index.html',{'error':error},context_instance=RequestContext(request))
    return render_to_response('index.html',context_instance=RequestContext(request))

我正在使用simplejson对Python列表进行编码(因此它将返回JSON数组)。我还不能解决问题。但是我认为我对“回声”做错了。

I’m trying to convert a server side Ajax response script into a Django HttpResponse, but apparently it’s not working.

This is the server-side script:

/* RECEIVE VALUE */
$validateValue=$_POST['validateValue'];
$validateId=$_POST['validateId'];
$validateError=$_POST['validateError'];

/* RETURN VALUE */
$arrayToJs = array();
$arrayToJs[0] = $validateId;
$arrayToJs[1] = $validateError;

if($validateValue =="Testuser"){  // Validate??
    $arrayToJs[2] = "true";       // RETURN TRUE
    echo '{"jsonValidateReturn":'.json_encode($arrayToJs).'}';  // RETURN ARRAY WITH success
}
else{
    for($x=0;$x<1000000;$x++){
        if($x == 990000){
            $arrayToJs[2] = "false";
            echo '{"jsonValidateReturn":'.json_encode($arrayToJs).'}';   // RETURNS ARRAY WITH ERROR.
        }
    }
}

And this is the converted code

def validate_user(request):
    if request.method == 'POST':
        vld_value = request.POST.get('validateValue')
        vld_id = request.POST.get('validateId')
        vld_error = request.POST.get('validateError')

        array_to_js = [vld_id, vld_error, False]

        if vld_value == "TestUser":
            array_to_js[2] = True
            x = simplejson.dumps(array_to_js)
            return HttpResponse(x)
        else:
            array_to_js[2] = False
            x = simplejson.dumps(array_to_js)
            error = 'Error'
            return render_to_response('index.html',{'error':error},context_instance=RequestContext(request))
    return render_to_response('index.html',context_instance=RequestContext(request))

I’m using simplejson to encode the Python list (so it will return a JSON array). I couldn’t figure out the problem yet. But I think that I did something wrong about the ‘echo’.


回答 0

我通常使用字典,而不是列表来返回JSON内容。

import json

from django.http import HttpResponse

response_data = {}
response_data['result'] = 'error'
response_data['message'] = 'Some error message'

在Django 1.7之前的版本中,您将像这样返回它:

return HttpResponse(json.dumps(response_data), content_type="application/json")

对于Django 1.7+,请JsonResponse按照以下SO答案所示使用:

from django.http import JsonResponse
return JsonResponse({'foo':'bar'})

I usually use a dictionary, not a list to return JSON content.

import json

from django.http import HttpResponse

response_data = {}
response_data['result'] = 'error'
response_data['message'] = 'Some error message'

Pre-Django 1.7 you’d return it like this:

return HttpResponse(json.dumps(response_data), content_type="application/json")

For Django 1.7+, use JsonResponse as shown in this SO answer like so :

from django.http import JsonResponse
return JsonResponse({'foo':'bar'})

回答 1

Django 1.7的新功能

您可以使用JsonResponse对象。

从文档:

from django.http import JsonResponse
return JsonResponse({'foo':'bar'})

New in django 1.7

you could use JsonResponse objects.

from the docs:

from django.http import JsonResponse
return JsonResponse({'foo':'bar'})

回答 2

我用这个,很好用。

from django.utils import simplejson
from django.http import HttpResponse

def some_view(request):
    to_json = {
        "key1": "value1",
        "key2": "value2"
    }
    return HttpResponse(simplejson.dumps(to_json), mimetype='application/json')

选择:

from django.utils import simplejson

class JsonResponse(HttpResponse):
    """
        JSON response
    """
    def __init__(self, content, mimetype='application/json', status=None, content_type=None):
        super(JsonResponse, self).__init__(
            content=simplejson.dumps(content),
            mimetype=mimetype,
            status=status,
            content_type=content_type,
        )

在Django 1.7中,JsonResponse对象已添加到Django框架本身,这使此任务更加容易:

from django.http import JsonResponse
def some_view(request):
    return JsonResponse({"key": "value"})

I use this, it works fine.

from django.utils import simplejson
from django.http import HttpResponse

def some_view(request):
    to_json = {
        "key1": "value1",
        "key2": "value2"
    }
    return HttpResponse(simplejson.dumps(to_json), mimetype='application/json')

Alternative:

from django.utils import simplejson

class JsonResponse(HttpResponse):
    """
        JSON response
    """
    def __init__(self, content, mimetype='application/json', status=None, content_type=None):
        super(JsonResponse, self).__init__(
            content=simplejson.dumps(content),
            mimetype=mimetype,
            status=status,
            content_type=content_type,
        )

In Django 1.7 JsonResponse objects have been added to the Django framework itself which makes this task even easier:

from django.http import JsonResponse
def some_view(request):
    return JsonResponse({"key": "value"})

回答 3

从Django 1.7开始,您便拥有了所需的标准JsonResponse

from django.http import JsonResponse
...
return JsonResponse(array_to_js, safe=False)

您甚至不需要json.dump您的数组。

Since Django 1.7 you have a standard JsonResponse that’s exactly what you need:

from django.http import JsonResponse
...
return JsonResponse(array_to_js, safe=False)

You don’t even need to json.dump your array.


回答 4

from django.http import HttpResponse
import json

class JsonResponse(HttpResponse):
    def __init__(self, content={}, mimetype=None, status=None,
             content_type='application/json'):
        super(JsonResponse, self).__init__(json.dumps(content), mimetype=mimetype,
                                           status=status, content_type=content_type)

并在视图中:

resp_data = {'my_key': 'my value',}
return JsonResponse(resp_data)
from django.http import HttpResponse
import json

class JsonResponse(HttpResponse):
    def __init__(self, content={}, mimetype=None, status=None,
             content_type='application/json'):
        super(JsonResponse, self).__init__(json.dumps(content), mimetype=mimetype,
                                           status=status, content_type=content_type)

And in the view:

resp_data = {'my_key': 'my value',}
return JsonResponse(resp_data)

回答 5

对于使用Django 1.7+的用户

from django.http import JsonResponse

def your_view(request):
    json_object = {'key': "value"}
    return JsonResponse(json_object)

官方文档

For those who use Django 1.7+

from django.http import JsonResponse

def your_view(request):
    json_object = {'key': "value"}
    return JsonResponse(json_object)

official docs


回答 6

您将要使用django序列化程序来帮助处理unicode内容:

from django.core import serializers

json_serializer = serializers.get_serializer("json")()
    response =  json_serializer.serialize(list, ensure_ascii=False, indent=2, use_natural_keys=True)
    return HttpResponse(response, mimetype="application/json")

You’ll want to use the django serializer to help with unicode stuff:

from django.core import serializers

json_serializer = serializers.get_serializer("json")()
    response =  json_serializer.serialize(list, ensure_ascii=False, indent=2, use_natural_keys=True)
    return HttpResponse(response, mimetype="application/json")

回答 7

使用基于Django类的视图,您可以编写:

from django.views import View
from django.http import JsonResponse

class JsonView(View):
    def get(self, request):
        return JsonResponse({'some': 'data'})

并使用Django-Rest-Framework可以编写:

from rest_framework.views import APIView
from rest_framework.response import Response

class JsonView(APIView):
    def get(self, request):
        return Response({'some': 'data'})

With Django Class-based views you can write:

from django.views import View
from django.http import JsonResponse

class JsonView(View):
    def get(self, request):
        return JsonResponse({'some': 'data'})

and with Django-Rest-Framework you can write:

from rest_framework.views import APIView
from rest_framework.response import Response

class JsonView(APIView):
    def get(self, request):
        return Response({'some': 'data'})

回答 8

对于Django 1.7或更高版本,使用JsonResponse类非常方便,因为它是HttpResponse的子类。

from django.http import JsonResponse
    def profile(request):
        data = {
            'name': 'Raghav',
            'location': 'India',
            'is_active': False,
            'count': 28
        }
        return JsonResponse(data)

对于旧版本的Django,您必须使用HttpResponse对象。

import json
from django.http import HttpResponse

def profile(request):
    data = {
        'name': 'Raghav',
        'location': 'India',
        'is_active': False,
        'count': 28
    }
    dump = json.dumps(data)
    return HttpResponse(dump, content_type='application/json')

Its very convenient with Django version 1.7 or higher as you have the JsonResponse class, which is a subclass of HttpResponse.

from django.http import JsonResponse
    def profile(request):
        data = {
            'name': 'Raghav',
            'location': 'India',
            'is_active': False,
            'count': 28
        }
        return JsonResponse(data)

For older versions of Django, you must use an HttpResponse object.

import json
from django.http import HttpResponse

def profile(request):
    data = {
        'name': 'Raghav',
        'location': 'India',
        'is_active': False,
        'count': 28
    }
    dump = json.dumps(data)
    return HttpResponse(dump, content_type='application/json')

回答 9

如何在Ajax(json)中使用Google App Engine?

使用JQuery的代码Javascript:

$.ajax({
    url: '/ajax',
    dataType : 'json',
    cache: false,
    success: function(data) {
        alert('Load was performed.'+data.ajax_resp);
    }
});

程式码Python

class Ajax(webapp2.RequestHandler):
    def get(self):
        my_response = {'ajax_resp':'Hello, webapp World!'}
        datos = json.dumps(my_response)

        self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
        self.response.out.write(datos)

How to use google app engine with ajax (json)?

Code Javascript with JQuery:

$.ajax({
    url: '/ajax',
    dataType : 'json',
    cache: false,
    success: function(data) {
        alert('Load was performed.'+data.ajax_resp);
    }
});

Code Python

class Ajax(webapp2.RequestHandler):
    def get(self):
        my_response = {'ajax_resp':'Hello, webapp World!'}
        datos = json.dumps(my_response)

        self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
        self.response.out.write(datos)

回答 10

这是使用基于类的视图的首选版本。只需将基本View子类化并覆盖get()方法。

import json

class MyJsonView(View):

    def get(self, *args, **kwargs):
        resp = {'my_key': 'my value',}
        return HttpResponse(json.dumps(resp), mimetype="application/json" )

This is my preferred version using a class based view. Simply subclass the basic View and override the get()-method.

import json

class MyJsonView(View):

    def get(self, *args, **kwargs):
        resp = {'my_key': 'my value',}
        return HttpResponse(json.dumps(resp), mimetype="application/json" )

回答 11

Django代码views.py

def view(request):
    if request.method == 'POST':
        print request.body
        data = request.body
        return HttpResponse(json.dumps(data))

HTML代码view.html

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
    $("#mySelect").change(function(){
        selected = $("#mySelect option:selected").text()
        $.ajax({
            type: 'POST',
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            url: '/view/',
            data: {
                    'fruit': selected
                  },
            success: function(result) {
                        document.write(result)
                    }
    });
  });
});
</script>
</head>
<body>

<form>
    {{data}}
    <br>
Select your favorite fruit:
<select id="mySelect">
  <option value="apple" selected >Select fruit</option>
  <option value="apple">Apple</option>
  <option value="orange">Orange</option>
  <option value="pineapple">Pineapple</option>
  <option value="banana">Banana</option>
</select>
</form>
</body>
</html>

Django code views.py:

def view(request):
    if request.method == 'POST':
        print request.body
        data = request.body
        return HttpResponse(json.dumps(data))

HTML code view.html:

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
    $("#mySelect").change(function(){
        selected = $("#mySelect option:selected").text()
        $.ajax({
            type: 'POST',
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            url: '/view/',
            data: {
                    'fruit': selected
                  },
            success: function(result) {
                        document.write(result)
                    }
    });
  });
});
</script>
</head>
<body>

<form>
    {{data}}
    <br>
Select your favorite fruit:
<select id="mySelect">
  <option value="apple" selected >Select fruit</option>
  <option value="apple">Apple</option>
  <option value="orange">Orange</option>
  <option value="pineapple">Pineapple</option>
  <option value="banana">Banana</option>
</select>
</form>
</body>
</html>

回答 12

首先导入:

from django.http import HttpResponse

如果您已经有了JSON:

def your_method(request):
    your_json = [{'key1': value, 'key2': value}]
    return HttpResponse(your_json, 'application/json')

如果您从另一个HTTP请求获取JSON:

def your_method(request):
    response = request.get('https://www.example.com/get/json')
    return HttpResponse(response, 'application/json')

First import this:

from django.http import HttpResponse

If you have the JSON already:

def your_method(request):
    your_json = [{'key1': value, 'key2': value}]
    return HttpResponse(your_json, 'application/json')

If you get the JSON from another HTTP request:

def your_method(request):
    response = request.get('https://www.example.com/get/json')
    return HttpResponse(response, 'application/json')

回答 13

使用JsonResponse

from django.http import JsonResponse

Use JsonResponse

from django.http import JsonResponse

回答 14

在View中使用以下命令:

form.field.errors|striptags

用于获取没有html的验证消息

In View use this:

form.field.errors|striptags

for getting validation messages without html


使Python记录器将除日志文件外的所有消息输出到stdout

问题:使Python记录器将除日志文件外的所有消息输出到stdout

除了应该将日志文件放到哪里,是否有一种方法可以使用该logging模块使Python日志自动输出到stdout ?例如,我想所有呼叫,,去他们预期的地方,但除了总是被复制到。这是为了避免重复消息,例如:logger.warninglogger.criticallogger.errorstdout

mylogger.critical("something failed")
print "something failed"

Is there a way to make Python logging using the logging module automatically output things to stdout in addition to the log file where they are supposed to go? For example, I’d like all calls to logger.warning, logger.critical, logger.error to go to their intended places but in addition always be copied to stdout. This is to avoid duplicating messages like:

mylogger.critical("something failed")
print "something failed"

回答 0

所有日志记录输出均由处理程序处理;只需添加一个logging.StreamHandler()在根记录器中即可。

这是配置流处理程序(使用stdout而不是默认值stderr)并将其添加到根记录器的示例:

import logging
import sys

root = logging.getLogger()
root.setLevel(logging.DEBUG)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
root.addHandler(handler)

All logging output is handled by the handlers; just add a logging.StreamHandler() to the root logger.

Here’s an example configuring a stream handler (using stdout instead of the default stderr) and adding it to the root logger:

import logging
import sys

root = logging.getLogger()
root.setLevel(logging.DEBUG)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
root.addHandler(handler)

回答 1

登录到stdout的最简单方法:

import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

The simplest way to log to stdout:

import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

回答 2

可以使用多个处理程序。

import logging
import auxiliary_module

# create logger with 'spam_application'
log = logging.getLogger('spam_application')
log.setLevel(logging.DEBUG)

# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
log.addHandler(fh)

# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
ch.setFormatter(formatter)
log.addHandler(ch)

log.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary()
log.info('created an instance of auxiliary_module.Auxiliary')

log.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something()
log.info('finished auxiliary_module.Auxiliary.do_something')

log.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function()
log.info('done with auxiliary_module.some_function()')

# remember to close the handlers
for handler in log.handlers:
    handler.close()
    log.removeFilter(handler)

请参阅:https : //docs.python.org/2/howto/logging-cookbook.html

It’s possible using multiple handlers.

import logging
import auxiliary_module

# create logger with 'spam_application'
log = logging.getLogger('spam_application')
log.setLevel(logging.DEBUG)

# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
log.addHandler(fh)

# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
ch.setFormatter(formatter)
log.addHandler(ch)

log.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary()
log.info('created an instance of auxiliary_module.Auxiliary')

log.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something()
log.info('finished auxiliary_module.Auxiliary.do_something')

log.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function()
log.info('done with auxiliary_module.some_function()')

# remember to close the handlers
for handler in log.handlers:
    handler.close()
    log.removeFilter(handler)

Please see: https://docs.python.org/2/howto/logging-cookbook.html


回答 3

您可以为file和stdout创建两个处理程序,然后创建一个handlers参数为的记录器basicConfig。如果两个处理程序具有相同的log_level和format输出,则可能会很有用:

import logging
import sys

file_handler = logging.FileHandler(filename='tmp.log')
stdout_handler = logging.StreamHandler(sys.stdout)
handlers = [file_handler, stdout_handler]

logging.basicConfig(
    level=logging.DEBUG, 
    format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
    handlers=handlers
)

logger = logging.getLogger('LOGGER_NAME')

You could create two handlers for file and stdout and then create one logger with handlers argument to basicConfig. It could be useful if you have the same log_level and format output for both handlers:

import logging
import sys

file_handler = logging.FileHandler(filename='tmp.log')
stdout_handler = logging.StreamHandler(sys.stdout)
handlers = [file_handler, stdout_handler]

logging.basicConfig(
    level=logging.DEBUG, 
    format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
    handlers=handlers
)

logger = logging.getLogger('LOGGER_NAME')

回答 4

登录文件和stderr的最简单方法:

import logging

logging.basicConfig(filename="logfile.txt")
stderrLogger=logging.StreamHandler()
stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
logging.getLogger().addHandler(stderrLogger)

The simplest way to log to file and to stderr:

import logging

logging.basicConfig(filename="logfile.txt")
stderrLogger=logging.StreamHandler()
stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
logging.getLogger().addHandler(stderrLogger)

回答 5

这是基于强大的,但记录不完整的解决方案logging.config.dictConfig的方法。而不是将所有日志消息发送到stdout,而是将日志级别ERROR和更高级别的消息发送stderrstdout。如果系统的其他部分正在收听stderr或,则此功能很有用stdout

import logging
import logging.config
import sys

class _ExcludeErrorsFilter(logging.Filter):
    def filter(self, record):
        """Filters out log messages with log level ERROR (numeric value: 40) or higher."""
        return record.levelno < 40


config = {
    'version': 1,
    'filters': {
        'exclude_errors': {
            '()': _ExcludeErrorsFilter
        }
    },
    'formatters': {
        # Modify log message format here or replace with your custom formatter class
        'my_formatter': {
            'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
        }
    },
    'handlers': {
        'console_stderr': {
            # Sends log messages with log level ERROR or higher to stderr
            'class': 'logging.StreamHandler',
            'level': 'ERROR',
            'formatter': 'my_formatter',
            'stream': sys.stderr
        },
        'console_stdout': {
            # Sends log messages with log level lower than ERROR to stdout
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filters': ['exclude_errors'],
            'stream': sys.stdout
        },
        'file': {
            # Sends all log messages to a file
            'class': 'logging.FileHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filename': 'my.log',
            'encoding': 'utf8'
        }
    },
    'root': {
        # In general, this should be kept at 'NOTSET'.
        # Otherwise it would interfere with the log levels set for each handler.
        'level': 'NOTSET',
        'handlers': ['console_stderr', 'console_stdout', 'file']
    },
}

logging.config.dictConfig(config)

Here is a solution based on the powerful but poorly documented logging.config.dictConfig method. Instead of sending every log message to stdout, it sends messages with log level ERROR and higher to stderr and everything else to stdout. This can be useful if other parts of the system are listening to stderr or stdout.

import logging
import logging.config
import sys

class _ExcludeErrorsFilter(logging.Filter):
    def filter(self, record):
        """Filters out log messages with log level ERROR (numeric value: 40) or higher."""
        return record.levelno < 40


config = {
    'version': 1,
    'filters': {
        'exclude_errors': {
            '()': _ExcludeErrorsFilter
        }
    },
    'formatters': {
        # Modify log message format here or replace with your custom formatter class
        'my_formatter': {
            'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
        }
    },
    'handlers': {
        'console_stderr': {
            # Sends log messages with log level ERROR or higher to stderr
            'class': 'logging.StreamHandler',
            'level': 'ERROR',
            'formatter': 'my_formatter',
            'stream': sys.stderr
        },
        'console_stdout': {
            # Sends log messages with log level lower than ERROR to stdout
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filters': ['exclude_errors'],
            'stream': sys.stdout
        },
        'file': {
            # Sends all log messages to a file
            'class': 'logging.FileHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filename': 'my.log',
            'encoding': 'utf8'
        }
    },
    'root': {
        # In general, this should be kept at 'NOTSET'.
        # Otherwise it would interfere with the log levels set for each handler.
        'level': 'NOTSET',
        'handlers': ['console_stderr', 'console_stdout', 'file']
    },
}

logging.config.dictConfig(config)

回答 6

由于没有人共享两个整齐的班轮,我将分享我自己的:

logging.basicConfig(filename='logs.log', level=logging.DEBUG, format="%(asctime)s:%(levelname)s: %(message)s")
logging.getLogger().addHandler(logging.StreamHandler())

Since no one has shared a neat two liner, I will share my own:

logging.basicConfig(filename='logs.log', level=logging.DEBUG, format="%(asctime)s:%(levelname)s: %(message)s")
logging.getLogger().addHandler(logging.StreamHandler())

回答 7

这是一个非常简单的示例:

import logging
l = logging.getLogger("test")

# Add a file logger
f = logging.FileHandler("test.log")
l.addHandler(f)

# Add a stream logger
s = logging.StreamHandler()
l.addHandler(s)

# Send a test message to both -- critical will always log
l.critical("test msg")

输出将在标准输出和文件中显示“ test msg”。

Here’s an extremely simple example:

import logging
l = logging.getLogger("test")

# Add a file logger
f = logging.FileHandler("test.log")
l.addHandler(f)

# Add a stream logger
s = logging.StreamHandler()
l.addHandler(s)

# Send a test message to both -- critical will always log
l.critical("test msg")

The output will show “test msg” on stdout and also in the file.


如何将字符串拆分为字符数组?

问题:如何将字符串拆分为字符数组?

我试图在网上四处寻找将字符串拆分为字符数组的答案,但似乎找不到一个简单的方法

str.split(//)似乎不像Ruby那样工作。有没有一种简单的方法可以不循环?

I’ve tried to look around the web for answers to splitting a string into an array of characters but I can’t seem to find a simple method

str.split(//) does not seem to work like Ruby does. Is there a simple way of doing this without looping?


回答 0

>>> s = "foobar"
>>> list(s)
['f', 'o', 'o', 'b', 'a', 'r']

你需要清单

>>> s = "foobar"
>>> list(s)
['f', 'o', 'o', 'b', 'a', 'r']

You need list


回答 1

您将字符串传递给list()

s = "mystring"
l = list(s)
print l

You take the string and pass it to list()

s = "mystring"
l = list(s)
print l

回答 2

您也可以不用list()来以非常简单的方式进行操作:

>>> [c for c in "foobar"]
['f', 'o', 'o', 'b', 'a', 'r']

You can also do it in this very simple way without list():

>>> [c for c in "foobar"]
['f', 'o', 'o', 'b', 'a', 'r']

回答 3

如果您想一次处理您的字符串一个字符。您有多种选择。

uhello = u'Hello\u0020World'

使用列表理解:

print([x for x in uhello])

输出:

['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

使用地图:

print(list(map(lambda c2: c2, uhello)))

输出:

['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

调用内置列表功能:

print(list(uhello))

输出:

['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

使用for循环:

for c in uhello:
    print(c)

输出:

H
e
l
l
o

W
o
r
l
d

If you want to process your String one character at a time. you have various options.

uhello = u'Hello\u0020World'

Using List comprehension:

print([x for x in uhello])

Output:

['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

Using map:

print(list(map(lambda c2: c2, uhello)))

Output:

['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

Calling Built in list function:

print(list(uhello))

Output:

['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

Using for loop:

for c in uhello:
    print(c)

Output:

H
e
l
l
o

W
o
r
l
d

回答 4

我探索了完成此任务的另外两种方法。这可能对某人有帮助。

第一个很简单:

In [25]: a = []
In [26]: s = 'foobar'
In [27]: a += s
In [28]: a
Out[28]: ['f', 'o', 'o', 'b', 'a', 'r']

以及第二个用途maplambda功能。它可能适用于更复杂的任务:

In [36]: s = 'foobar12'
In [37]: a = map(lambda c: c, s)
In [38]: a
Out[38]: ['f', 'o', 'o', 'b', 'a', 'r', '1', '2']

例如

# isdigit, isspace or another facilities such as regexp may be used
In [40]: a = map(lambda c: c if c.isalpha() else '', s)
In [41]: a
Out[41]: ['f', 'o', 'o', 'b', 'a', 'r', '', '']

有关更多方法,请参见python文档

I explored another two ways to accomplish this task. It may be helpful for someone.

The first one is easy:

In [25]: a = []
In [26]: s = 'foobar'
In [27]: a += s
In [28]: a
Out[28]: ['f', 'o', 'o', 'b', 'a', 'r']

And the second one use map and lambda function. It may be appropriate for more complex tasks:

In [36]: s = 'foobar12'
In [37]: a = map(lambda c: c, s)
In [38]: a
Out[38]: ['f', 'o', 'o', 'b', 'a', 'r', '1', '2']

For example

# isdigit, isspace or another facilities such as regexp may be used
In [40]: a = map(lambda c: c if c.isalpha() else '', s)
In [41]: a
Out[41]: ['f', 'o', 'o', 'b', 'a', 'r', '', '']

See python docs for more methods


回答 5

任务归结为遍历字符串中的字符并将它们收集到列表中。最幼稚的解决方案看起来像

result = []
for character in string:
    result.append(character)

当然,它可以缩短为

result = [character for character in string]

但是仍然有更短的解决方案可以做到这一点。

list构造函数可用于将任何可迭代的(迭代器,列表,元组,字符串等)转换为列表。

>>> list('abc')
['a', 'b', 'c']

最大的优点是,它在Python 2和Python 3中均相同。

另外,从Python 3.5开始(由于出色的PEP 448),现在可以通过将任何可迭代项解压缩为空列表文字来构建列表:

>>> [*'abc']
['a', 'b', 'c']

这比较整洁,并且在某些情况下比list直接调用构造函数更有效。

我建议不要使用map基于方法的方法,因为map不会在Python 3中返回列表。请参见如何在Python 3 中使用过滤,映射和精简

The task boils down to iterating over characters of the string and collecting them into a list. The most naïve solution would look like

result = []
for character in string:
    result.append(character)

Of course, it can be shortened to just

result = [character for character in string]

but there still are shorter solutions that do the same thing.

list constructor can be used to convert any iterable (iterators, lists, tuples, string etc.) to list.

>>> list('abc')
['a', 'b', 'c']

The big plus is that it works the same in both Python 2 and Python 3.

Also, starting from Python 3.5 (thanks to the awesome PEP 448) it’s now possible to build a list from any iterable by unpacking it to an empty list literal:

>>> [*'abc']
['a', 'b', 'c']

This is neater, and in some cases more efficient than calling list constructor directly.

I’d advise against using map-based approaches, because map does not return a list in Python 3. See How to use filter, map, and reduce in Python 3.


回答 6

我只需要一个字符数组:

arr = list(str)

如果要用特定的str拆分str:

# str = "temp//temps" will will be ['temp', 'temps']
arr = str.split("//")

I you just need an array of chars:

arr = list(str)

If you want to split the str by a particular str:

# str = "temp//temps" will will be ['temp', 'temps']
arr = str.split("//")

回答 7

split()内置函数将仅根据特定条件分隔值,但在单个单词中,它无法满足条件。因此,可以借助来解决list()。它在内部调用Array,它将基于数组存储值。

假设,

a = "bottle"
a.split() // will only return the word but not split the every single char.

a = "bottle"
list(a) // will separate ['b','o','t','t','l','e']

split() inbuilt function will only separate the value on the basis of certain condition but in the single word, it cannot fulfill the condition. So, it can be solved with the help of list(). It internally calls the Array and it will store the value on the basis of an array.

Suppose,

a = "bottle"
a.split() // will only return the word but not split the every single char.

a = "bottle"
list(a) // will separate ['b','o','t','t','l','e']

回答 8

打开包装:

word = "Paralelepipedo"
print([*word])

Unpack them:

word = "Paralelepipedo"
print([*word])

回答 9

如果您希望只读访问该字符串,则可以直接使用数组符号。

Python 2.7.6 (default, Mar 22 2014, 22:59:38) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> t = 'my string'
>>> t[1]
'y'

在不使用正则表达式的情况下可能对测试很有用。字符串是否包含结尾换行符?

>>> t[-1] == '\n'
False
>>> t = 'my string\n'
>>> t[-1] == '\n'
True

If you wish to read only access to the string you can use array notation directly.

Python 2.7.6 (default, Mar 22 2014, 22:59:38) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> t = 'my string'
>>> t[1]
'y'

Could be useful for testing without using regexp. Does the string contain an ending newline?

>>> t[-1] == '\n'
False
>>> t = 'my string\n'
>>> t[-1] == '\n'
True

回答 10

好吧,就像我喜欢列表版本一样,这是我发现的另一种更为冗长的方式(但它很酷,所以我认为我应该将其添加到列表中):

>>> text = "My hovercraft is full of eels"
>>> [text[i] for i in range(len(text))]
['M', 'y', ' ', 'h', 'o', 'v', 'e', 'r', 'c', 'r', 'a', 'f', 't', ' ', 'i', 's', ' ', 'f', 'u', 'l', 'l', ' ', 'o', 'f', ' ', 'e', 'e', 'l', 's']

Well, much as I like the list(s) version, here’s another more verbose way I found (but it’s cool so I thought I’d add it to the fray):

>>> text = "My hovercraft is full of eels"
>>> [text[i] for i in range(len(text))]
['M', 'y', ' ', 'h', 'o', 'v', 'e', 'r', 'c', 'r', 'a', 'f', 't', ' ', 'i', 's', ' ', 'f', 'u', 'l', 'l', ' ', 'o', 'f', ' ', 'e', 'e', 'l', 's']

回答 11

from itertools import chain

string = 'your string'
chain(string)

list(string)生成器类似,但返回在使用时延迟评估的生成器,因此内存效率高。

from itertools import chain

string = 'your string'
chain(string)

similar to list(string) but returns a generator that is lazily evaluated at point of use, so memory efficient.


回答 12

>>> for i in range(len(a)):
...     print a[i]
... 

其中a是您要分离的字符串。值“ a [i]”是字符串的各个字符,可以将它们附加到列表中。

>>> for i in range(len(a)):
...     print a[i]
... 

where a is the string that you want to separate out. The values “a[i]” are the individual character of the the string these could be appended to a list.


如何在Requirements.txt中声明直接的github源

问题:如何在Requirements.txt中声明直接的github源

我已经使用以下命令安装了一个库

pip install git+git://github.com/mozilla/elasticutils.git

直接从Github存储库安装它。这工作正常,我想在我的requirements.txt。我看其他的票像这样但这并没有解决我的问题。如果我把像

-f git+git://github.com/mozilla/elasticutils.git
elasticutils==0.7.dev

requirements.txt文件中,pip install -r requirements.txt结果为以下输出:

Downloading/unpacking elasticutils==0.7.dev (from -r requirements.txt (line 20))
  Could not find a version that satisfies the requirement elasticutils==0.7.dev (from -r requirements.txt (line 20)) (from versions: )
No distributions matching the version for elasticutils==0.7.dev (from -r requirements.txt (line 20))

需求文件文档中没有提及使用git+git协议说明符的链接,因此也许只是不被支持。

有人能解决我的问题吗?

I’ve installed a library using the command

pip install git+git://github.com/mozilla/elasticutils.git

which installs it directly from a Github repository. This works fine and I want to have that dependency in my requirements.txt. I’ve looked at other tickets like this but that didn’t solve my problem. If I put something like

-f git+git://github.com/mozilla/elasticutils.git
elasticutils==0.7.dev

in the requirements.txt file, a pip install -r requirements.txt results in the following output:

Downloading/unpacking elasticutils==0.7.dev (from -r requirements.txt (line 20))
  Could not find a version that satisfies the requirement elasticutils==0.7.dev (from -r requirements.txt (line 20)) (from versions: )
No distributions matching the version for elasticutils==0.7.dev (from -r requirements.txt (line 20))

The documentation of the requirements file does not mention links using the git+git protocol specifier, so maybe this is just not supported.

Does anybody have a solution for my problem?


回答 0

“ Editable”包语法可用于requirements.txt从各种VCS(git,hg,bzr,svn)导入包:

-e git://github.com/mozilla/elasticutils.git#egg=elasticutils

另外,可以指向特定的提交:

-e git://github.com/mozilla/elasticutils.git@000b14389171a9f0d7d713466b32bc649b0bed8e#egg=elasticutils

“Editable” packages syntax can be used in requirements.txt to import packages from a variety of VCS (git, hg, bzr, svn):

-e git://github.com/mozilla/elasticutils.git#egg=elasticutils

Also, it is possible to point to particular commit:

-e git://github.com/mozilla/elasticutils.git@000b14389171a9f0d7d713466b32bc649b0bed8e#egg=elasticutils

回答 1

通常,您的requirements.txt文件如下所示:

package-one==1.9.4
package-two==3.7.1
package-three==1.0.1
...

要指定Github存储库,您不需要package-name==约定。

下面的示例更新 package-two使用GitHub存储库进行。@和之间的文字#表示包装的详细信息。

指定提交哈希(41b95ec在updated的上下文中requirements.txt):

package-one==1.9.4
git+git://github.com/path/to/package-two@41b95ec#egg=package-two
package-three==1.0.1

指定分支名称(master):

git+git://github.com/path/to/package-two@master#egg=package-two

指定标签(0.1):

git+git://github.com/path/to/package-two@0.1#egg=package-two

指定发布(3.7.1):

git+git://github.com/path/to/package-two@releases/tag/v3.7.1#egg=package-two

请注意,#egg=package-two此处不是注释,而是要明确说明软件包名称

这篇博客文章对此主题进行了更多讨论。

Normally your requirements.txt file would look something like this:

package-one==1.9.4
package-two==3.7.1
package-three==1.0.1
...

To specify a Github repo, you do not need the package-name== convention.

The examples below update package-two using a GitHub repo. The text between @ and # denotes the specifics of the package.

Specify commit hash (41b95ec in the context of updated requirements.txt):

package-one==1.9.4
git+git://github.com/path/to/package-two@41b95ec#egg=package-two
package-three==1.0.1

Specify branch name (master):

git+git://github.com/path/to/package-two@master#egg=package-two

Specify tag (0.1):

git+git://github.com/path/to/package-two@0.1#egg=package-two

Specify release (3.7.1):

git+git://github.com/path/to/package-two@releases/tag/v3.7.1#egg=package-two

Note that #egg=package-two is not a comment here, it is to explicitly state the package name

This blog post has some more discussion on the topic.


回答 2

requirements.txt从pip 7.0开始,可以通过以下方式指定对git存储库中软件包的依赖关系:1

[-e] git+git://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+https://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+ssh://git.myproject.org/SomeProject#egg=SomeProject
-e git+git@git.myproject.org:SomeProject#egg=SomeProject

对于Github,这意味着您可以做到(请注意,省略了-e):

git+git://github.com/mozilla/elasticutils.git#egg=elasticutils

为什么要额外回答?
-e在其他答案中对标志有些困惑,所以这是我的澄清:

-e或” --editable标志表示包装已安装在<venv path>/src/SomeProject深处,因此不会放入深处<venv path>/lib/pythonX.X/site-packages/SomeProject。否则,它将被放置在其中。2

文献资料

requirements.txt allows the following ways of specifying a dependency on a package in a git repository as of pip 7.0:1

[-e] git+git://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+https://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+ssh://git.myproject.org/SomeProject#egg=SomeProject
-e git+git@git.myproject.org:SomeProject#egg=SomeProject

For Github that means you can do (notice the omitted -e):

git+git://github.com/mozilla/elasticutils.git#egg=elasticutils

Why the extra answer?
I got somewhat confused by the -e flag in the other answers so here’s my clarification:

The -e or --editable flag means that the package is installed in <venv path>/src/SomeProject and thus not in the deeply buried <venv path>/lib/pythonX.X/site-packages/SomeProject it would otherwise be placed in.2

Documentation


回答 3

首先,以任何已知的方式使用git+git或安装git+https。安装项目kronok的分支的示例brabeion

pip install -e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion

其次,使用pip freeze > requirements.txt来获取正确的东西requirements.txt。在这种情况下,您将获得

-e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion-master

三,测试结果:

pip uninstall brabeion
pip install -r requirements.txt

First, install with git+git or git+https, in any way you know. Example of installing kronok‘s branch of the brabeion project:

pip install -e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion

Second, use pip freeze > requirements.txt to get the right thing in your requirements.txt. In this case, you will get

-e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion-master

Third, test the result:

pip uninstall brabeion
pip install -r requirements.txt

回答 4

由于pip v1.5(发布于2014年1月1日:CHANGELOGPR),您还可以指定git repo的子目录来包含您的模块。语法如下所示:

pip install -e git+https://git.repo/some_repo.git#egg=my_subdir_pkg&subdirectory=my_subdir_pkg # install a python package from a repo subdirectory

注意:作为pip模块的作者,如果可能的话,理想情况下,您可能希望将模块发布到它自己的顶级仓库中。但是,此功能对于某些子目录中包含python模块的现有存储库很有帮助。如果它们也没有发布到pypi,则可能会被迫以这种方式安装它们。

Since pip v1.5, (released Jan 1 2014: CHANGELOG, PR) you may also specify a subdirectory of a git repo to contain your module. The syntax looks like this:

pip install -e git+https://git.repo/some_repo.git#egg=my_subdir_pkg&subdirectory=my_subdir_pkg # install a python package from a repo subdirectory

Note: As a pip module author, ideally you’d probably want to publish your module in it’s own top-level repo if you can. Yet this feature is helpful for some pre-existing repos that contain python modules in subdirectories. You might be forced to install them this way if they are not published to pypi too.


回答 5

我发现要获取pip3(v9.0.1,由Ubuntu 18.04的软件包管理器安装)来实际安装我告诉它要安装的东西有点棘手。我发布此答案是为了节省遇到此问题的任何人的时间。

将其放入Requirements.txt文件失败:

git+git://github.com/myname/myrepo.git@my-branch#egg=eggname

“失败”是指当它从Git下载代码时,它最终安装了PyPi上找到的代码的原始版本,而不是该分支上存储库中的代码。

但是,安装commmit而不是分支名称是可行的:

git+git://github.com/myname/myrepo.git@d27d07c9e862feb939e56d0df19d5733ea7b4f4d#egg=eggname

I’m finding that it’s kind of tricky to get pip3 (v9.0.1, as installed by Ubuntu 18.04’s package manager) to actually install the thing I tell it to install. I’m posting this answer to save anyone’s time who runs into this problem.

Putting this into a requirements.txt file failed:

git+git://github.com/myname/myrepo.git@my-branch#egg=eggname

By “failed” I mean that while it downloaded the code from Git, it ended up installing the original version of the code, as found on PyPi, instead of the code in the repo on that branch.

However, installing the commmit instead of the branch name works:

git+git://github.com/myname/myrepo.git@d27d07c9e862feb939e56d0df19d5733ea7b4f4d#egg=eggname

Python与Cpython

问题:Python与Cpython

关于Python和CPython (Jython,IronPython)的所有这些大惊小怪,我不明白:

python.org提到CPython是:

Python的“传统”实现(绰号为CPython)

另一个堆栈溢出问题提到:

CPython是Python的默认字节码解释器,它是用C编写的。

老实说,我并没有得到这两种解释的实际含义,但是我认为的是,如果我使用CPython,那意味着当我运行示例python代码时,它将其编译为C语言,然后像执行C语言一样执行它码

那么CPython到底是什么?与python相比,它有什么区别?我应该在Python上使用CPython吗?如果有,它的优点是什么?

What’s all this fuss about Python and CPython (Jython,IronPython), I don’t get it:

python.org mentions that CPython is:

The “traditional” implementation of Python (nicknamed CPython)

yet another Stack Overflow question mentions that:

CPython is the default byte-code interpreter of Python, which is written in C.

Honestly I don’t get what both of those explanations practically mean but what I thought was that, if I use CPython does that mean when I run a sample python code, it compiles it to C language and then executes it as if it were C code

So what exactly is CPython and how does it differ when compared with python and should I probably use CPython over Python and if so what are its advantages?


回答 0

那么CPython是什么?

CPython是原始的 Python实现。它是您从Python.org下载的实现。人们称它为CPython是为了将其与其他后来的Python实现区分开来,并将语言引擎的实现与Python 编程语言本身区分开来。

后面的部分是您困惑的来源。您需要将Python语言与运行 Python代码的代码分开。

CPython 恰好用C实现。实际上,这只是实现细节。CPython将您的Python代码(透明地)编译为字节码,并在评估循环中解释该字节码。

CPython也是第一个实现新功能的人。Python语言开发使用CPython作为基础。其他实现如下。

Jython等如何?

JythonIronPythonPyPy是Python编程语言的当前“其他”实现。它们分别用Java,C#和RPython(Python的子集)实现。Jython将您的Python代码编译为Java字节码,因此您的Python代码可以在JVM上运行。IronPython使您可以在Microsoft CLR上运行Python 。而且,PyPy(在Python(的一部分)中实现)使您可以比CPython更快地运行Python代码,这应该引起您的注意。:-)

实际编译为C

因此,CPython本身不会将您的Python代码转换为C。而是运行解释器循环。还有一个项目翻译的Python上下的代码转换为C,而被称为用Cython。用Cython增加了一些扩展Python语言,并让您编译代码,以C扩展,代码插头 CPython的解释。

So what is CPython?

CPython is the original Python implementation. It is the implementation you download from Python.org. People call it CPython to distinguish it from other, later, Python implementations, and to distinguish the implementation of the language engine from the Python programming language itself.

The latter part is where your confusion comes from; you need to keep Python-the-language separate from whatever runs the Python code.

CPython happens to be implemented in C. That is just an implementation detail, really. CPython compiles your Python code into bytecode (transparently) and interprets that bytecode in a evaluation loop.

CPython is also the first to implement new features; Python-the-language development uses CPython as the base; other implementations follow.

What about Jython, etc.?

Jython, IronPython and PyPy are the current “other” implementations of the Python programming language; these are implemented in Java, C# and RPython (a subset of Python), respectively. Jython compiles your Python code to Java bytecode, so your Python code can run on the JVM. IronPython lets you run Python on the Microsoft CLR. And PyPy, being implemented in (a subset of) Python, lets you run Python code faster than CPython, which rightly should blow your mind. :-)

Actually compiling to C

So CPython does not translate your Python code to C by itself. Instead, it runs an interpreter loop. There is a project that does translate Python-ish code to C, and that is called Cython. Cython adds a few extensions to the Python language, and lets you compile your code to C extensions, code that plugs into the CPython interpreter.


回答 1

您需要区分语言和实现。Python是一种语言

根据Wikipedia所说,“编程语言是用于编写程序的一种表示法,它是一种计算或算法的规范”。这意味着它只是编写代码的规则和语法。另外,我们有一个编程语言实现,在大多数情况下是实际的解释器或编译器。

Python是一种语言。CPython是C语言中Python的实现。Jython是Java语言中的实现,依此类推。

总结:您已经在使用CPython(如果从此处下载)。

You need to distinguish between a language and an implementation. Python is a language,

According to Wikipedia, “A programming language is a notation for writing programs, which are specifications of a computation or algorithm”. This means that it’s simply the rules and syntax for writing code. Separately we have a programming language implementation which in most cases, is the actual interpreter or compiler.

Python is a language. CPython is the implementation of Python in C. Jython is the implementation in Java, and so on.

To sum up: You are already using CPython (if you downloaded from here).


回答 2

甚至我在理解CPython,JPython,IronPython,PyPy之间的区别时也遇到了相同的问题。

因此,在开始解释之前,我愿意清除三件事:

  1. Python:这是一门语言,它仅说明/描述如何向解释器(接受您的python代码的程序)传达/表达自己。
  2. 实现:一切都与解释器的编写方式有关,特别是关于哪种语言以及最终使用的语言
  3. 字节码:它是由程序(通常称为虚拟机)而不是“真实”计算机(即硬件处理器)处理的代码。

CPython是用C语言编写的实现。它最终生成特定于Python的字节码(基于堆栈计算机的指令集),然后执行它。将Python代码转换为字节码的原因是,如果看起来像机器指令,则更容易实现解释器。但是,没有必要在执行Python代码之前产生一些字节码(但CPython确实会产生)。

如果您想查看CPython的字节码,则可以。方法如下:

>>> def f(x, y):                # line 1
...    print("Hello")           # line 2
...    if x:                    # line 3
...       y += x                # line 4
...    print(x, y)              # line 5
...    return x+y               # line 6
...                             # line 7
>>> import dis                  # line 8
>>> dis.dis(f)                  # line 9
  2           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('Hello')
              4 CALL_FUNCTION            1
              6 POP_TOP

  3           8 LOAD_FAST                0 (x)
             10 POP_JUMP_IF_FALSE       20

  4          12 LOAD_FAST                1 (y)
             14 LOAD_FAST                0 (x)
             16 INPLACE_ADD
             18 STORE_FAST               1 (y)

  5     >>   20 LOAD_GLOBAL              0 (print)
             22 LOAD_FAST                0 (x)
             24 LOAD_FAST                1 (y)
             26 CALL_FUNCTION            2
             28 POP_TOP

  6          30 LOAD_FAST                0 (x)
             32 LOAD_FAST                1 (y)
             34 BINARY_ADD
36 RETURN_VALUE

现在,让我们看一下上面的代码。第1至6行是功能定义。在第8行中,我们导入了“ dis”模块,该模块可用于查看由CPython(解释器)生成的中间Python字节码(或者可以说是Python字节码的反汇编程序)。

注意:我从#python IRC频道获得了此代码的链接:https ://gist.github.com/nedbat/e89fa710db0edfb9057dc8d18d979f9c

然后是Jython,它是用Java编写的,最终生成Java字节码。Java字节代码在Java运行时环境上运行,该环境是Java虚拟机(JVM)的实现。如果这令人困惑,那么我怀疑您不知道Java如何工作。用外行术语来说,Java编译器采用Java(语言,而不是编译器)代码,并输出只能使用JRE运行的文件(Java字节码)。这样做的目的是,一旦编译了Java代码,就可以将其以Java字节代码格式移植到其他计算机上,该格式只能由JRE运行。如果仍然令人困惑,那么您可能想看看该网页

在这里,您可能会问CPython的字节码是否像Jython一样可移植,我怀疑不是。CPython实现中生成字节码特定于该解释器,以便于进一步执行代码(我还怀疑,这种中间字节码的产生只是为了在许多其他解释器中简化处理)。

因此,在Jython中,当您编译Python代码时,最终会得到Java字节代码,该代码可以在JVM上运行。

同样,IronPython(用C#语言编写)将您的Python代码编译为公共语言运行时(CLR),与Microsoft开发的JVM相比,这项技术是类似的。

Even I had the same problem understanding how are CPython, JPython, IronPython, PyPy are different from each other.

So, I am willing to clear three things before I begin to explain:

  1. Python: It is a language, it only states/describes how to convey/express yourself to the interpreter (the program which accepts your python code).
  2. Implementation: It is all about how the interpreter was written, specifically, in what language and what it ends up doing.
  3. Bytecode: It is the code that is processed by a program, usually referred to as a virtual machine, rather than by the “real” computer machine, the hardware processor.

CPython is the implementation, which was written in C language. It ends up producing bytecode (stack-machine based instruction set) which is Python specific and then executes it. The reason to convert Python code to a bytecode is because it’s easier to implement an interpreter if it looks like machine instructions. But, it isn’t necessary to produce some bytecode prior to execution of the Python code (but CPython does produce).

If you want to look at CPython’s bytecode then you can. Here’s how you can:

>>> def f(x, y):                # line 1
...    print("Hello")           # line 2
...    if x:                    # line 3
...       y += x                # line 4
...    print(x, y)              # line 5
...    return x+y               # line 6
...                             # line 7
>>> import dis                  # line 8
>>> dis.dis(f)                  # line 9
  2           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('Hello')
              4 CALL_FUNCTION            1
              6 POP_TOP

  3           8 LOAD_FAST                0 (x)
             10 POP_JUMP_IF_FALSE       20

  4          12 LOAD_FAST                1 (y)
             14 LOAD_FAST                0 (x)
             16 INPLACE_ADD
             18 STORE_FAST               1 (y)

  5     >>   20 LOAD_GLOBAL              0 (print)
             22 LOAD_FAST                0 (x)
             24 LOAD_FAST                1 (y)
             26 CALL_FUNCTION            2
             28 POP_TOP

  6          30 LOAD_FAST                0 (x)
             32 LOAD_FAST                1 (y)
             34 BINARY_ADD
36 RETURN_VALUE

Now, let’s have a look at the above code. Lines 1 to 6 are a function definition. In line 8, we import the ‘dis’ module which can be used to view the intermediate Python bytecode (or you can say, disassembler for Python bytecode) that is generated by CPython (interpreter).

NOTE: I got the link to this code from #python IRC channel: https://gist.github.com/nedbat/e89fa710db0edfb9057dc8d18d979f9c

And then, there is Jython, which is written in Java and ends up producing Java byte code. The Java byte code runs on Java Runtime Environment, which is an implementation of Java Virtual Machine (JVM). If this is confusing then I suspect that you have no clue how Java works. In layman terms, Java (the language, not the compiler) code is taken by the Java compiler and outputs a file (which is Java byte code) that can be run only using a JRE. This is done so that, once the Java code is compiled then it can be ported to other machines in Java byte code format, which can be only run by JRE. If this is still confusing then you may want to have a look at this web page.

Here, you may ask if the CPython’s bytecode is portable like Jython, I suspect not. The bytecode produced in CPython implementation was specific to that interpreter for making it easy for further execution of code (I also suspect that, such intermediate bytecode production, just for the ease the of processing is done in many other interpreters).

So, in Jython, when you compile your Python code, you end up with Java byte code, which can be run on a JVM.

Similarly, IronPython (written in C# language) compiles down your Python code to Common Language Runtime (CLR), which is a similar technology as compared to JVM, developed by Microsoft.


回答 3

文章详细地介绍了Python中的不同实现之间的区别。如文章所述:

首先要意识到的是“ Python”是一个接口。有关于Python应该做什么以及应该如何表现的规范(与任何接口一样)。并且有多种实现方式(与任何接口一样)。

要了解的第二件事是,“解释”和“编译”是实现的属性,而不是接口。

This article thoroughly explains the difference between different implementations of Python. Like the article puts it:

The first thing to realize is that ‘Python’ is an interface. There’s a specification of what Python should do and how it should behave (as with any interface). And there are multiple implementations (as with any interface).

The second thing to realize is that ‘interpreted’ and ‘compiled’ are properties of an implementation, not an interface.


回答 4

Python是一种语言:一组可用于编写程序的规则。该语言有几种实现方式。

不管您采用哪种实现,它们都差不多做同样的事情:获取程序的文本并解释它,执行其指令。它们都没有将您的代码编译为C或任何其他语言。

CPython是用C编写的原始实现。(“ CPython”中的“ C”部分是指用于编写Python解释器本身的语言。)

Jython是相同的语言(Python),但是使用Java实现。

IronPython解释器是用C#编写的。

还有PyPy-用Python编写的Python解释器。选你一个:)

Python is a language: a set of rules that can be used to write programs. There are several implementaions of this language.

No matter what implementation you take, they do pretty much the same thing: take the text of your program and interpret it, executing its instructions. None of them compile your code into C or any other language.

CPython is the original implementation, written in C. (The “C” part in “CPython” refers to the language that was used to write Python interpreter itself.)

Jython is the same language (Python), but implemented using Java.

IronPython interpreter was written in C#.

There’s also PyPy – a Python interpreter written in Python. Make your pick :)


回答 5

implementation表示使用什么语言来实现Python,而不是如何实现python代码。使用CPython的优点是C运行时的可用性以及与C / C ++的轻松集成。

因此CPython最初是使用来实现的C。原始实现还有其他方面,使Python能够利用Java(JYthon)或.NET Runtime(IronPython)进行开发。

根据您使用的实现,库可用性可能会有所不同,例如Jython中不提供Ctypes,因此任何使用ctypes的库在Jython中均不起作用。同样,如果要使用Java类,则不能直接从CPython中使用。您需要胶水(JEPP)或需要使用Jython(Python的Java实现)

implementation means what language was used to implement Python and not how python Code would be implemented. The advantage of using CPython is the availability of C Run-time as well as easy integration with C/C++.

So CPython was originally implemented using C. There were other forks to the original implementation which enabled Python to lever-edge Java (JYthon) or .NET Runtime (IronPython).

Based on which Implementation you use, library availability might vary, for example Ctypes is not available in Jython, so any library which uses ctypes would not work in Jython. Similarly, if you want to use a Java Class, you cannot directly do so from CPython. You either need a glue (JEPP) or need to use Jython (The Java Implementation of Python)


回答 6

您应该知道,由于全局解释器锁,CPython并不真正支持多线程。它还没有用于递归的优化机制,并具有其他实现和库试图填补的许多其他限制。

您应该在python Wiki上查看此页面

查看页面上的代码片段,它将使您对解释器的含义有所了解。

You should know that CPython doesn’t really support multithreading because of the Global Interpreter Lock. It also has no Optimisation mechanisms for recursion, and has many other limitations that other implementations and libraries try to fill.

You should take a look at this page on the python wiki.

Look at the code snippets on this page, it’ll give you a good idea of what an interpreter is.


回答 7

当您想将其与其他选项进行对比时,通常会调用Python的原始和标准实现CPython否则,仅使用普通的“ Python”)。这个名字来自于事实,它被编码为可移植的ANSI C language code。这是您从http://www.python.org获取的Python,与ActivePythonEnthought发行版一起获得,并且已在大多数Linux和Mac OS X计算机上自动安装。如果您在计算机上找到了预装的Python版本,则可能是 CPython,除非您的公司或组织以更专业的方式使用Python。

除非您想使用Python 编写脚本Java.NET应用程序,或者想从中受益StacklessPyPy引人注目,否则您可能要使用标准CPython系统。因为它是该语言的参考实现,所以与替代系统相比,它往往运行最快,最完整,并且更新和更健壮。

The original, and standard, implementation of Python is usually called CPython when you want to contrast it with the other options (and just plain “Python” otherwise). This name comes from the fact that it is coded in portable ANSI C language code. This is the Python that you fetch from http://www.python.org, get with the ActivePython and Enthought distributions, and have automatically on most Linux and Mac OS X machines. If you’ve found a preinstalled version of Python on your machine, it’s probably CPython, unless your company or organization is using Python in more specialized ways.

Unless you want to script Java or .NET applications with Python or find the benefits of Stackless or PyPy compelling, you probably want to use the standard CPython system. Because it is the reference implementation of the language, it tends to run the fastest, be the most complete, and be more up-to-date and robust than the alternative systems.


回答 8

编程语言实现是用于执行计算机程序的系统。

编程语言实现有两种通用方法:

  • 解释:解释器将某种语言的程序作为输入,并在某种机器上执行以该语言编写的动作。
  • 编译:编译器将某种语言的程序作为输入,并将该程序翻译为某种其他语言,该语言可以用作另一解释器或另一编译器的输入。

PythonGuido van Rossum在1991年创建的一种解释型高级编程语言。

CPython是Python计算语言的参考版本,也是由Guido van Rossum创建的用C编写的。

其他Python实施清单

资源

A programming language implementation is a system for executing computer programs.

There are two general approaches to programming language implementation:

  • Interpretation: An interpreter takes as input a program in some language, and performs the actions written in that language on some machine.
  • Compilation: A compiler takes as input a program in some language, and translates that program into some other language, which may serve as input to another interpreter or another compiler.

Python is an interpreted high-level programming language created by Guido van Rossum in 1991.

CPython is reference version of the Python computing language, which is written in C created by Guido van Rossum too.

Other list of Python Implementations

Source


字典搜索的Python列表

问题:字典搜索的Python列表

假设我有这个:

[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

并通过搜索“ Pam”作为名称,我想检索相关的字典: {name: "Pam", age: 7}

如何实现呢?

Assume I have this:

[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

and by searching “Pam” as name, I want to retrieve the related dictionary: {name: "Pam", age: 7}

How to achieve this ?


回答 0

您可以使用生成器表达式

>>> dicts = [
...     { "name": "Tom", "age": 10 },
...     { "name": "Mark", "age": 5 },
...     { "name": "Pam", "age": 7 },
...     { "name": "Dick", "age": 12 }
... ]

>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

如果您需要处理不存在的项目,则可以执行用户Matt 在其注释中建议的操作,并使用略有不同的API提供默认值:

next((item for item in dicts if item["name"] == "Pam"), None)

为了找到项目的索引,而不是项目本身,可以枚举()列表:

next((i for i, item in enumerate(dicts) if item["name"] == "Pam"), None)

You can use a generator expression:

>>> dicts = [
...     { "name": "Tom", "age": 10 },
...     { "name": "Mark", "age": 5 },
...     { "name": "Pam", "age": 7 },
...     { "name": "Dick", "age": 12 }
... ]

>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

If you need to handle the item not being there, then you can do what user Matt suggested in his comment and provide a default using a slightly different API:

next((item for item in dicts if item["name"] == "Pam"), None)

And to find the index of the item, rather than the item itself, you can enumerate() the list:

next((i for i, item in enumerate(dicts) if item["name"] == "Pam"), None)

回答 1

在我看来,这是最Python的方式:

people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

filter(lambda person: person['name'] == 'Pam', people)

结果(在Python 2中作为列表返回):

[{'age': 7, 'name': 'Pam'}]

注意:在Python 3中,将返回一个过滤器对象。因此,python3解决方案将是:

list(filter(lambda person: person['name'] == 'Pam', people))

This looks to me the most pythonic way:

people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

filter(lambda person: person['name'] == 'Pam', people)

result (returned as a list in Python 2):

[{'age': 7, 'name': 'Pam'}]

Note: In Python 3, a filter object is returned. So the python3 solution would be:

list(filter(lambda person: person['name'] == 'Pam', people))

回答 2

@FrédéricHamidi的回答很好。在Python 3.x中,语法.next()略有变化。因此稍作修改:

>>> dicts = [
     { "name": "Tom", "age": 10 },
     { "name": "Mark", "age": 5 },
     { "name": "Pam", "age": 7 },
     { "name": "Dick", "age": 12 }
 ]
>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

如@Matt的评论中所述,您可以这样添加默认值:

>>> next((item for item in dicts if item["name"] == "Pam"), False)
{'name': 'Pam', 'age': 7}
>>> next((item for item in dicts if item["name"] == "Sam"), False)
False
>>>

@Frédéric Hamidi’s answer is great. In Python 3.x the syntax for .next() changed slightly. Thus a slight modification:

>>> dicts = [
     { "name": "Tom", "age": 10 },
     { "name": "Mark", "age": 5 },
     { "name": "Pam", "age": 7 },
     { "name": "Dick", "age": 12 }
 ]
>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

As mentioned in the comments by @Matt, you can add a default value as such:

>>> next((item for item in dicts if item["name"] == "Pam"), False)
{'name': 'Pam', 'age': 7}
>>> next((item for item in dicts if item["name"] == "Sam"), False)
False
>>>

回答 3

您可以使用列表推导

def search(name, people):
    return [element for element in people if element['name'] == name]

You can use a list comprehension:

def search(name, people):
    return [element for element in people if element['name'] == name]

回答 4

people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

def search(name):
    for p in people:
        if p['name'] == name:
            return p

search("Pam")
people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

def search(name):
    for p in people:
        if p['name'] == name:
            return p

search("Pam")

回答 5

我测试了各种方法来浏览字典列表,然后返回键x具有特定值的字典。

结果:

  • 速度:列表理解>生成器表达式>>普通列表迭代>>>过滤器。
  • 全部缩放与列表中的字典数量成线性关系(10倍列表大小-> 10倍时间)。
  • 对于大量(数千)键,每个词典的键不会显着影响速度。请查看我计算出的以下图表:https : //imgur.com/a/quQzv(方法名称请参见下文)。

所有测试均使用Python 3.6 .4,W7x64完成。

from random import randint
from timeit import timeit


list_dicts = []
for _ in range(1000):     # number of dicts in the list
    dict_tmp = {}
    for i in range(10):   # number of keys for each dict
        dict_tmp[f"key{i}"] = randint(0,50)
    list_dicts.append( dict_tmp )



def a():
    # normal iteration over all elements
    for dict_ in list_dicts:
        if dict_["key3"] == 20:
            pass

def b():
    # use 'generator'
    for dict_ in (x for x in list_dicts if x["key3"] == 20):
        pass

def c():
    # use 'list'
    for dict_ in [x for x in list_dicts if x["key3"] == 20]:
        pass

def d():
    # use 'filter'
    for dict_ in filter(lambda x: x['key3'] == 20, list_dicts):
        pass

结果:

1.7303 # normal list iteration 
1.3849 # generator expression 
1.3158 # list comprehension 
7.7848 # filter

I tested various methods to go through a list of dictionaries and return the dictionaries where key x has a certain value.

Results:

  • Speed: list comprehension > generator expression >> normal list iteration >>> filter.
  • All scale linear with the number of dicts in the list (10x list size -> 10x time).
  • The keys per dictionary does not affect speed significantly for large amounts (thousands) of keys. Please see this graph I calculated: https://imgur.com/a/quQzv (method names see below).

All tests done with Python 3.6.4, W7x64.

from random import randint
from timeit import timeit


list_dicts = []
for _ in range(1000):     # number of dicts in the list
    dict_tmp = {}
    for i in range(10):   # number of keys for each dict
        dict_tmp[f"key{i}"] = randint(0,50)
    list_dicts.append( dict_tmp )



def a():
    # normal iteration over all elements
    for dict_ in list_dicts:
        if dict_["key3"] == 20:
            pass

def b():
    # use 'generator'
    for dict_ in (x for x in list_dicts if x["key3"] == 20):
        pass

def c():
    # use 'list'
    for dict_ in [x for x in list_dicts if x["key3"] == 20]:
        pass

def d():
    # use 'filter'
    for dict_ in filter(lambda x: x['key3'] == 20, list_dicts):
        pass

Results:

1.7303 # normal list iteration 
1.3849 # generator expression 
1.3158 # list comprehension 
7.7848 # filter

回答 6

向@FrédéricHamidi添加一点点。

如果您不确定某个键是否在字典列表中,可以使用以下方法:

next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)

To add just a tiny bit to @FrédéricHamidi.

In case you are not sure a key is in the the list of dicts, something like this would help:

next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)

回答 7

您是否尝试过熊猫包装?它非常适合此类搜索任务,并且也进行了优化。

import pandas as pd

listOfDicts = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

# Create a data frame, keys are used as column headers.
# Dict items with the same key are entered into the same respective column.
df = pd.DataFrame(listOfDicts)

# The pandas dataframe allows you to pick out specific values like so:

df2 = df[ (df['name'] == 'Pam') & (df['age'] == 7) ]

# Alternate syntax, same thing

df2 = df[ (df.name == 'Pam') & (df.age == 7) ]

我在下面添加了一些基准测试,以大范围地(即100k +项)说明熊猫的运行时间:

setup_large = 'dicts = [];\
[dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 })) for _ in range(25000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'

setup_small = 'dicts = [];\
dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 }));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'

method1 = '[item for item in dicts if item["name"] == "Pam"]'
method2 = 'df[df["name"] == "Pam"]'

import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))

t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method Pandas: ' + str(t.timeit(100)))

#Small Method LC: 0.000191926956177
#Small Method Pandas: 0.044392824173
#Large Method LC: 1.98827004433
#Large Method Pandas: 0.324505090714

Have you ever tried out the pandas package? It’s perfect for this kind of search task and optimized too.

import pandas as pd

listOfDicts = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

# Create a data frame, keys are used as column headers.
# Dict items with the same key are entered into the same respective column.
df = pd.DataFrame(listOfDicts)

# The pandas dataframe allows you to pick out specific values like so:

df2 = df[ (df['name'] == 'Pam') & (df['age'] == 7) ]

# Alternate syntax, same thing

df2 = df[ (df.name == 'Pam') & (df.age == 7) ]

I’ve added a little bit of benchmarking below to illustrate pandas’ faster runtimes on a larger scale i.e. 100k+ entries:

setup_large = 'dicts = [];\
[dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 })) for _ in range(25000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'

setup_small = 'dicts = [];\
dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 }));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'

method1 = '[item for item in dicts if item["name"] == "Pam"]'
method2 = 'df[df["name"] == "Pam"]'

import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))

t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method Pandas: ' + str(t.timeit(100)))

#Small Method LC: 0.000191926956177
#Small Method Pandas: 0.044392824173
#Large Method LC: 1.98827004433
#Large Method Pandas: 0.324505090714

回答 8

这是在字典列表中搜索值的一般方法:

def search_dictionaries(key, value, list_of_dictionaries):
    return [element for element in list_of_dictionaries if element[key] == value]

This is a general way of searching a value in a list of dictionaries:

def search_dictionaries(key, value, list_of_dictionaries):
    return [element for element in list_of_dictionaries if element[key] == value]

回答 9

names = [{'name':'Tom', 'age': 10}, {'name': 'Mark', 'age': 5}, {'name': 'Pam', 'age': 7}]
resultlist = [d    for d in names     if d.get('name', '') == 'Pam']
first_result = resultlist[0]

这是一种方法

names = [{'name':'Tom', 'age': 10}, {'name': 'Mark', 'age': 5}, {'name': 'Pam', 'age': 7}]
resultlist = [d    for d in names     if d.get('name', '') == 'Pam']
first_result = resultlist[0]

This is one way…


回答 10

只需使用列表推导:

[i for i in dct if i['name'] == 'Pam'][0]

样例代码:

dct = [
    {'name': 'Tom', 'age': 10},
    {'name': 'Mark', 'age': 5},
    {'name': 'Pam', 'age': 7}
]

print([i for i in dct if i['name'] == 'Pam'][0])

> {'age': 7, 'name': 'Pam'}

Simply using list comprehension:

[i for i in dct if i['name'] == 'Pam'][0]

Sample code:

dct = [
    {'name': 'Tom', 'age': 10},
    {'name': 'Mark', 'age': 5},
    {'name': 'Pam', 'age': 7}
]

print([i for i in dct if i['name'] == 'Pam'][0])

> {'age': 7, 'name': 'Pam'}

回答 11

您可以通过在Python中使用filter和next方法来实现。

filter方法过滤给定的序列并返回一个迭代器。 next方法接受迭代器,并返回列表中的下一个元素。

因此,您可以通过以下方式找到元素

my_dict = [
    {"name": "Tom", "age": 10},
    {"name": "Mark", "age": 5},
    {"name": "Pam", "age": 7}
]

next(filter(lambda obj: obj.get('name') == 'Pam', my_dict), None)

输出是

{'name': 'Pam', 'age': 7}

注意:None如果找不到我们正在搜索的名称,上述代码将返回以防万一。

You can achieve this with the usage of filter and next methods in Python.

filter method filters the given sequence and returns an iterator. next method accepts an iterator and returns the next element in the list.

So you can find the element by,

my_dict = [
    {"name": "Tom", "age": 10},
    {"name": "Mark", "age": 5},
    {"name": "Pam", "age": 7}
]

next(filter(lambda obj: obj.get('name') == 'Pam', my_dict), None)

and the output is,

{'name': 'Pam', 'age': 7}

Note: The above code will return None incase if the name we are searching is not found.


回答 12

我的第一个想法是,您可能要考虑创建一个包含这些词典的字典…例如,如果您要搜索的词典次数不止一次。

但是,这可能是过早的优化。有什么问题:

def get_records(key, store=dict()):
    '''Return a list of all records containing name==key from our store
    '''
    assert key is not None
    return [d for d in store if d['name']==key]

My first thought would be that you might want to consider creating a dictionary of these dictionaries … if, for example, you were going to be searching it more a than small number of times.

However that might be a premature optimization. What would be wrong with:

def get_records(key, store=dict()):
    '''Return a list of all records containing name==key from our store
    '''
    assert key is not None
    return [d for d in store if d['name']==key]

回答 13

dicts=[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

from collections import defaultdict
dicts_by_name=defaultdict(list)
for d in dicts:
    dicts_by_name[d['name']]=d

print dicts_by_name['Tom']

#output
#>>>
#{'age': 10, 'name': 'Tom'}
dicts=[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

from collections import defaultdict
dicts_by_name=defaultdict(list)
for d in dicts:
    dicts_by_name[d['name']]=d

print dicts_by_name['Tom']

#output
#>>>
#{'age': 10, 'name': 'Tom'}

回答 14

使用列表推导的一种简单方法是,如果 l是列表

l = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

然后

[d['age'] for d in l if d['name']=='Tom']

One simple way using list comprehensions is , if l is the list

l = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

then

[d['age'] for d in l if d['name']=='Tom']

回答 15

您可以尝试以下方法:

''' lst: list of dictionaries '''
lst = [{"name": "Tom", "age": 10}, {"name": "Mark", "age": 5}, {"name": "Pam", "age": 7}]

search = raw_input("What name: ") #Input name that needs to be searched (say 'Pam')

print [ lst[i] for i in range(len(lst)) if(lst[i]["name"]==search) ][0] #Output
>>> {'age': 7, 'name': 'Pam'} 

You can try this:

''' lst: list of dictionaries '''
lst = [{"name": "Tom", "age": 10}, {"name": "Mark", "age": 5}, {"name": "Pam", "age": 7}]

search = raw_input("What name: ") #Input name that needs to be searched (say 'Pam')

print [ lst[i] for i in range(len(lst)) if(lst[i]["name"]==search) ][0] #Output
>>> {'age': 7, 'name': 'Pam'} 

回答 16

这是一个使用迭代遍历列表的比较,使用filter + lambda或重构(如果需要或对您的情况有效)的代码将您的代码用于命令,而不是命令列表

import time

# Build list of dicts
list_of_dicts = list()
for i in range(100000):
    list_of_dicts.append({'id': i, 'name': 'Tom'})

# Build dict of dicts
dict_of_dicts = dict()
for i in range(100000):
    dict_of_dicts[i] = {'name': 'Tom'}


# Find the one with ID of 99

# 1. iterate through the list
lod_ts = time.time()
for elem in list_of_dicts:
    if elem['id'] == 99999:
        break
lod_tf = time.time()
lod_td = lod_tf - lod_ts

# 2. Use filter
f_ts = time.time()
x = filter(lambda k: k['id'] == 99999, list_of_dicts)
f_tf = time.time()
f_td = f_tf- f_ts

# 3. find it in dict of dicts
dod_ts = time.time()
x = dict_of_dicts[99999]
dod_tf = time.time()
dod_td = dod_tf - dod_ts


print 'List of Dictionries took: %s' % lod_td
print 'Using filter took: %s' % f_td
print 'Dict of Dicts took: %s' % dod_td

输出是这样的:

List of Dictionries took: 0.0099310874939
Using filter took: 0.0121960639954
Dict of Dicts took: 4.05311584473e-06

结论: 在这些情况下,显然拥有字典词典是最有效的搜索方式,在这种情况下,您知道您将仅通过id进行搜索。有趣的是,使用过滤器是最慢的解决方案。

Here is a comparison using iterating throuhg list, using filter+lambda or refactoring(if needed or valid to your case) your code to dict of dicts rather than list of dicts

import time

# Build list of dicts
list_of_dicts = list()
for i in range(100000):
    list_of_dicts.append({'id': i, 'name': 'Tom'})

# Build dict of dicts
dict_of_dicts = dict()
for i in range(100000):
    dict_of_dicts[i] = {'name': 'Tom'}


# Find the one with ID of 99

# 1. iterate through the list
lod_ts = time.time()
for elem in list_of_dicts:
    if elem['id'] == 99999:
        break
lod_tf = time.time()
lod_td = lod_tf - lod_ts

# 2. Use filter
f_ts = time.time()
x = filter(lambda k: k['id'] == 99999, list_of_dicts)
f_tf = time.time()
f_td = f_tf- f_ts

# 3. find it in dict of dicts
dod_ts = time.time()
x = dict_of_dicts[99999]
dod_tf = time.time()
dod_td = dod_tf - dod_ts


print 'List of Dictionries took: %s' % lod_td
print 'Using filter took: %s' % f_td
print 'Dict of Dicts took: %s' % dod_td

And the output is this:

List of Dictionries took: 0.0099310874939
Using filter took: 0.0121960639954
Dict of Dicts took: 4.05311584473e-06

Conclusion: Clearly having a dictionary of dicts is the most efficient way to be able to search in those cases, where you know say you will be searching by id’s only. interestingly using filter is the slowest solution.


回答 17

您必须遍历列表的所有元素。没有捷径!

除非在其他地方保留了指向列表项的名称字典,否则您必须注意从列表中弹出元素的后果。

You have to go through all elements of the list. There is not a shortcut!

Unless somewhere else you keep a dictionary of the names pointing to the items of the list, but then you have to take care of the consequences of popping an element from your list.


回答 18

我在寻找同一问题的答案时找到了这个线程。虽然我意识到这是一个迟来的答案,但我认为我会做出贡献,以防它对其他人有用:

def find_dict_in_list(dicts, default=None, **kwargs):
    """Find first matching :obj:`dict` in :obj:`list`.

    :param list dicts: List of dictionaries.
    :param dict default: Optional. Default dictionary to return.
        Defaults to `None`.
    :param **kwargs: `key=value` pairs to match in :obj:`dict`.

    :returns: First matching :obj:`dict` from `dicts`.
    :rtype: dict

    """

    rval = default
    for d in dicts:
        is_found = False

        # Search for keys in dict.
        for k, v in kwargs.items():
            if d.get(k, None) == v:
                is_found = True

            else:
                is_found = False
                break

        if is_found:
            rval = d
            break

    return rval


if __name__ == '__main__':
    # Tests
    dicts = []
    keys = 'spam eggs shrubbery knight'.split()

    start = 0
    for _ in range(4):
        dct = {k: v for k, v in zip(keys, range(start, start+4))}
        dicts.append(dct)
        start += 4

    # Find each dict based on 'spam' key only.  
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam) == dicts[x]

    # Find each dict based on 'spam' and 'shrubbery' keys.
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+2) == dicts[x]

    # Search for one correct key, one incorrect key:
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+1) is None

    # Search for non-existent dict.
    for x in range(len(dicts)):
        spam = x+100
        assert find_dict_in_list(dicts, spam=spam) is None

I found this thread when I was searching for an answer to the same question. While I realize that it’s a late answer, I thought I’d contribute it in case it’s useful to anyone else:

def find_dict_in_list(dicts, default=None, **kwargs):
    """Find first matching :obj:`dict` in :obj:`list`.

    :param list dicts: List of dictionaries.
    :param dict default: Optional. Default dictionary to return.
        Defaults to `None`.
    :param **kwargs: `key=value` pairs to match in :obj:`dict`.

    :returns: First matching :obj:`dict` from `dicts`.
    :rtype: dict

    """

    rval = default
    for d in dicts:
        is_found = False

        # Search for keys in dict.
        for k, v in kwargs.items():
            if d.get(k, None) == v:
                is_found = True

            else:
                is_found = False
                break

        if is_found:
            rval = d
            break

    return rval


if __name__ == '__main__':
    # Tests
    dicts = []
    keys = 'spam eggs shrubbery knight'.split()

    start = 0
    for _ in range(4):
        dct = {k: v for k, v in zip(keys, range(start, start+4))}
        dicts.append(dct)
        start += 4

    # Find each dict based on 'spam' key only.  
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam) == dicts[x]

    # Find each dict based on 'spam' and 'shrubbery' keys.
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+2) == dicts[x]

    # Search for one correct key, one incorrect key:
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+1) is None

    # Search for non-existent dict.
    for x in range(len(dicts)):
        spam = x+100
        assert find_dict_in_list(dicts, spam=spam) is None

回答 19

这里提出的大多数(如果不是全部)实现都有两个缺陷:

  • 他们假定只传递一个键来进行搜索,而对于复杂的字典有更多键可能很有趣
  • 他们假定传递给搜索的所有键都存在于字典中,因此当键错误不存在时,它们将无法正确处理。

更新的主张:

def find_first_in_list(objects, **kwargs):
    return next((obj for obj in objects if
                 len(set(obj.keys()).intersection(kwargs.keys())) > 0 and
                 all([obj[k] == v for k, v in kwargs.items() if k in obj.keys()])),
                None)

也许不是最Python的,但至少具有更多的故障保护功能。

用法:

>>> obj1 = find_first_in_list(list_of_dict, name='Pam', age=7)
>>> obj2 = find_first_in_list(list_of_dict, name='Pam', age=27)
>>> obj3 = find_first_in_list(list_of_dict, name='Pam', address='nowhere')
>>> 
>>> print(obj1, obj2, obj3)
{"name": "Pam", "age": 7}, None, {"name": "Pam", "age": 7}

要点

Most (if not all) implementations proposed here have two flaws:

  • They assume only one key to be passed for searching, while it may be interesting to have more for complex dict
  • They assume all keys passed for searching exist in the dicts, hence they don’t deal correctly with KeyError occuring when it is not.

An updated proposition:

def find_first_in_list(objects, **kwargs):
    return next((obj for obj in objects if
                 len(set(obj.keys()).intersection(kwargs.keys())) > 0 and
                 all([obj[k] == v for k, v in kwargs.items() if k in obj.keys()])),
                None)

Maybe not the most pythonic, but at least a bit more failsafe.

Usage:

>>> obj1 = find_first_in_list(list_of_dict, name='Pam', age=7)
>>> obj2 = find_first_in_list(list_of_dict, name='Pam', age=27)
>>> obj3 = find_first_in_list(list_of_dict, name='Pam', address='nowhere')
>>> 
>>> print(obj1, obj2, obj3)
{"name": "Pam", "age": 7}, None, {"name": "Pam", "age": 7}

The gist.


用Python编写的CSV文件每行之间都有空行

问题:用Python编写的CSV文件每行之间都有空行

import csv

with open('thefile.csv', 'rb') as f:
  data = list(csv.reader(f))
  import collections
  counter = collections.defaultdict(int)

  for row in data:
        counter[row[10]] += 1


with open('/pythonwork/thefile_subset11.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    for row in data:
        if counter[row[10]] >= 504:
           writer.writerow(row)

该代码读取thefile.csv,进行更改并将结果写入thefile_subset1

但是,当我在Microsoft Excel中打开生成的csv时,每条记录后都有一个额外的空白行!

有没有办法使它不放在多余的空白行?

import csv

with open('thefile.csv', 'rb') as f:
  data = list(csv.reader(f))
  import collections
  counter = collections.defaultdict(int)

  for row in data:
        counter[row[10]] += 1


with open('/pythonwork/thefile_subset11.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    for row in data:
        if counter[row[10]] >= 504:
           writer.writerow(row)

This code reads thefile.csv, makes changes, and writes results to thefile_subset1.

However, when I open the resulting csv in Microsoft Excel, there is an extra blank line after each record!

Is there a way to make it not put an extra blank line?


回答 0

在Python 2中,请outfile使用模式'wb'而不是来打开'w'。该csv.writer写入\r\n直接到文件中。如果您未以二进制模式打开文件,则会写入文件,\r\r\n因为在Windows 文本模式下会将每个文件\n转换为\r\n

在Python 3中,所需的语法已更改(请参见下面的文档链接),因此请outfile使用附加参数newline=''(空字符串)打开。

例子:

# Python 2
with open('/pythonwork/thefile_subset11.csv', 'wb') as outfile:
    writer = csv.writer(outfile)

# Python 3
with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
    writer = csv.writer(outfile)

文档链接

In Python 2, open outfile with mode 'wb' instead of 'w'. The csv.writer writes \r\n into the file directly. If you don’t open the file in binary mode, it will write \r\r\n because on Windows text mode will translate each \n into \r\n.

In Python 3 the required syntax changed (see documentation links below), so open outfile with the additional parameter newline='' (empty string) instead.

Examples:

# Python 2
with open('/pythonwork/thefile_subset11.csv', 'wb') as outfile:
    writer = csv.writer(outfile)

# Python 3
with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
    writer = csv.writer(outfile)

Documentation Links


回答 1

以二进制模式“ wb”打开文件在Python 3+中不起作用。或者更确切地说,您必须在编写数据之前将数据转换为二进制。那只是一个麻烦。

相反,您应该将其保留在文本模式下,但是将换行符替换为空。像这样:

with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:

Opening the file in binary mode “wb” will not work in Python 3+. Or rather, you’d have to convert your data to binary before writing it. That’s just a hassle.

Instead, you should keep it in text mode, but override the newline as empty. Like so:

with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:

回答 2

简单的答案是,无论输入还是输出,都应始终以二进制模式打开csv文件,否则在Windows上,行尾出现问题。具体上输出csv模块将写\r\n(标准CSV行终止),然后(在文本模式)运行时将取代\n通过\r\n(Windows标准线路终端),得到的结果\r\r\n

摆弄lineterminator不是解决方案。

The simple answer is that csv files should always be opened in binary mode whether for input or output, as otherwise on Windows there are problems with the line ending. Specifically on output the csv module will write \r\n (the standard CSV row terminator) and then (in text mode) the runtime will replace the \n by \r\n (the Windows standard line terminator) giving a result of \r\r\n.

Fiddling with the lineterminator is NOT the solution.


回答 3

注意:似乎这不是首选的解决方案,因为在Windows系统上如何添加额外的行。如python文档中所述

如果csvfile是文件对象,则必须在有区别的平台上使用“ b”标志打开它。

Windows是其中一个与众不同的平台。虽然按照我下面所述更改行终止符可能已解决了该问题,但可以通过以二进制模式打开文件来完全避免该问题。有人可能会说这种解决方案更“优雅”。在这种情况下,用行终止符“摆弄”可能会导致系统之间无法移植的代码,在此情况下,在UNIX系统上以二进制模式打开文件不会产生任何效果。即。它导致跨系统兼容的代码。

Python Docs

在Windows上,附加到模式的’b’以二进制模式打开文件,因此也有’rb’,’wb’和’r + b’之类的模式。Windows上的Python区分文本文件和二进制文件。当读取或写入数据时,文本文件中的行尾字符会自动更改。对于ASCII文本文件来说,对文件数据进行这种幕后修改是可以的,但它会破坏JPEG或EXE文件中的二进制数据。读写此类文件时,请务必小心使用二进制模式。在Unix上,将’b’附加到该模式没有什么坏处,因此您可以在平台上独立地将其用于所有二进制文件。

原件

作为csv.writer的可选参数的一部分,如果您获得多余的空行,则可能必须更改lineterminator(信息此处)。以下示例是从python页面csv docs改编的 将其从“ \ n”更改为应有的值。由于这只是在暗中解决问题的方法,因此可能会或可能不会起作用,但这是我的最佳猜测。

>>> import csv
>>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])

Note: It seems this is not the preferred solution because of how the extra line was being added on a Windows system. As stated in the python document:

If csvfile is a file object, it must be opened with the ‘b’ flag on platforms where that makes a difference.

Windows is one such platform where that makes a difference. While changing the line terminator as I described below may have fixed the problem, the problem could be avoided altogether by opening the file in binary mode. One might say this solution is more “elegent”. “Fiddling” with the line terminator would have likely resulted in unportable code between systems in this case, where opening a file in binary mode on a unix system results in no effect. ie. it results in cross system compatible code.

From Python Docs:

On Windows, ‘b’ appended to the mode opens the file in binary mode, so there are also modes like ‘rb’, ‘wb’, and ‘r+b’. Python on Windows makes a distinction between text and binary files; the end-of-line characters in text files are automatically altered slightly when data is read or written. This behind-the-scenes modification to file data is fine for ASCII text files, but it’ll corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files. On Unix, it doesn’t hurt to append a ‘b’ to the mode, so you can use it platform-independently for all binary files.

Original:

As part of optional paramaters for the csv.writer if you are getting extra blank lines you may have to change the lineterminator (info here). Example below adapated from the python page csv docs. Change it from ‘\n’ to whatever it should be. As this is just a stab in the dark at the problem this may or may not work, but it’s my best guess.

>>> import csv
>>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])

回答 4

我正在将这个答案写给python 3,因为我最初遇到了同样的问题。

我应该使用来从arduino获取数据PySerial,并将其写入.csv文件中。在我的情况下'\r\n',每个读数都以结尾,因此换行符总是分隔每行。

就我而言,newline=''选项无效。因为它显示了一些错误,例如:

with open('op.csv', 'a',newline=' ') as csv_file:

ValueError: illegal newline value: ''

因此,他们似乎不接受此处省略换行符。

仅在这里看到答案之一,我在writer对象中提到了行终止符,例如,

writer = csv.writer(csv_file, delimiter=' ',lineterminator='\r')

这对我来说是多余的换行符。

I’m writing this answer w.r.t. to python 3, as I’ve initially got the same problem.

I was supposed to get data from arduino using PySerial, and write them in a .csv file. Each reading in my case ended with '\r\n', so newline was always separating each line.

In my case, newline='' option didn’t work. Because it showed some error like :

with open('op.csv', 'a',newline=' ') as csv_file:

ValueError: illegal newline value: ''

So it seemed that they don’t accept omission of newline here.

Seeing one of the answers here only, I mentioned line terminator in the writer object, like,

writer = csv.writer(csv_file, delimiter=' ',lineterminator='\r')

and that worked for me for skipping the extra newlines.


回答 5

with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

“ lineterminator =’\ r’”允许传递到下一行,而在两行之间没有空行。

with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

The “lineterminator=’\r'” permit to pass to next row, without empty row between two.


回答 6

这个答案中借用,似乎最干净的解决方案是使用io.TextIOWrapper。我设法为自己解决了以下问题:

from io import TextIOWrapper

...

with open(filename, 'wb') as csvfile, TextIOWrapper(csvfile, encoding='utf-8', newline='') as wrapper:
    csvwriter = csv.writer(wrapper)
    for data_row in data:
        csvwriter.writerow(data_row)

上面的答案与Python 2不兼容。为了具有兼容性,我想一个人只需要将所有写入逻辑包装在一个if块中即可:

if sys.version_info < (3,):
    # Python 2 way of handling CSVs
else:
    # The above logic

Borrowing from this answer, it seems like the cleanest solution is to use io.TextIOWrapper. I managed to solve this problem for myself as follows:

from io import TextIOWrapper

...

with open(filename, 'wb') as csvfile, TextIOWrapper(csvfile, encoding='utf-8', newline='') as wrapper:
    csvwriter = csv.writer(wrapper)
    for data_row in data:
        csvwriter.writerow(data_row)

The above answer is not compatible with Python 2. To have compatibility, I suppose one would simply need to wrap all the writing logic in an if block:

if sys.version_info < (3,):
    # Python 2 way of handling CSVs
else:
    # The above logic

回答 7

使用下面定义的方法将数据写入CSV文件。

open('outputFile.csv', 'a',newline='')

只需newline=''open方法内部添加一个附加参数:

def writePhoneSpecsToCSV():
    rowData=["field1", "field2"]
    with open('outputFile.csv', 'a',newline='') as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(rowData)

这将写入CSV行,而不会创建其他行!

Use the method defined below to write data to the CSV file.

open('outputFile.csv', 'a',newline='')

Just add an additional newline='' parameter inside the open method :

def writePhoneSpecsToCSV():
    rowData=["field1", "field2"]
    with open('outputFile.csv', 'a',newline='') as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(rowData)

This will write CSV rows without creating additional rows!


回答 8

使用Python 3时,可以使用编解码器模块避免出现空行。如文档中所述,文件以二进制模式打开,因此不需要更改换行符kwarg。我最近遇到了同样的问题,对我有用:

with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
     csv_out_file = csv.DictWriter(out_csv)

When using Python 3 the empty lines can be avoid by using the codecs module. As stated in the documentation, files are opened in binary mode so no change of the newline kwarg is necessary. I was running into the same issue recently and that worked for me:

with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
     csv_out_file = csv.DictWriter(out_csv)

Python和pip,列出可用的软件包的所有版本?

问题:Python和pip,列出可用的软件包的所有版本?

给定可以与pip一起安装的Python软件包的名称,是否有任何方法可以找到pip可以安装的所有可能版本的列表?现在是反复试验。

我正在尝试为第三方库安装一个版本,但是最新版本太新了,进行了向后不兼容的更改。所以我想以某种方式列出pip知道的所有版本,以便我可以对其进行测试。

Given the name of a Python package that can be installed with pip, is there any way to find out a list of all the possible versions of it that pip could install? Right now it’s trial and error.

I’m trying to install a version for a third party library, but the newest version is too new, there were backwards incompatible changes made. So I’d like to somehow have a list of all the versions that pip knows about, so that I can test them.


回答 0

(更新:截至2020年3月,许多人报告说,通过安装的蛋黄pip install yolk3k只能返回最新版本。 克里斯的回答似乎最支持我,并为我工作)

pastebin上的脚本可以正常工作。但是,如果您要使用多个环境/主机,这不是很方便,因为您每次都必须复制/创建它。

更好的全方位解决方案是使用yolk3k,该软件可与pip一起安装。例如,查看可用的Django版本:

$ pip install yolk3k
$ yolk -V django
Django 1.3
Django 1.2.5
Django 1.2.4
Django 1.2.3
Django 1.2.2
Django 1.2.1
Django 1.2
Django 1.1.4
Django 1.1.3
Django 1.1.2
Django 1.0.4

yolk3k2012年yolk停止开发的原版的叉子。尽管已不再维护(如下面的注释所示),yolkyolk3k似乎并支持Python 3。

注意:我不参与yolk3k的开发。如果某些事情似乎无法正常工作,则在此处发表评论不会有太大的不同。请改用yolk3k问题追踪器,并考虑提交修订(如果可能)。

(update: As of March 2020, many people have reported that yolk, installed via pip install yolk3k, only returns latest version. Chris’s answer seems to have the most upvotes and worked for me)

The script at pastebin does work. However it’s not very convenient if you’re working with multiple environments/hosts because you will have to copy/create it every time.

A better all-around solution would be to use yolk3k, which is available to install with pip. E.g. to see what versions of Django are available:

$ pip install yolk3k
$ yolk -V django
Django 1.3
Django 1.2.5
Django 1.2.4
Django 1.2.3
Django 1.2.2
Django 1.2.1
Django 1.2
Django 1.1.4
Django 1.1.3
Django 1.1.2
Django 1.0.4

yolk3k is a fork of the original yolk which ceased development in 2012. Though yolk is no longer maintained (as indicated in comments below), yolk3k appears to be and supports Python 3.

Note: I am not involved in the development of yolk3k. If something doesn’t seem to work as it should, leaving a comment here should not make much difference. Use the yolk3k issue tracker instead and consider submitting a fix, if possible.


回答 1

用于PIP> = 9.0使用

$ pip install pylibmc==
Collecting pylibmc==
  Could not find a version that satisfies the requirement pylibmc== (from 
  versions: 0.2, 0.3, 0.4, 0.5.1, 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5, 0.6.1, 0.6, 
  0.7.1, 0.7.2, 0.7.3, 0.7.4, 0.7, 0.8.1, 0.8.2, 0.8, 0.9.1, 0.9.2, 0.9, 
  1.0-alpha, 1.0-beta, 1.0, 1.1.1, 1.1, 1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.3.0)
No matching distribution found for pylibmc==

–将打印所有可用版本,而无需实际下载或安装任何其他软件包。

对于pip <9.0使用

pip install pylibmc==blork

在哪里blork可以是不是有效版本号的任何字符串。

For pip >= 9.0 use

$ pip install pylibmc==
Collecting pylibmc==
  Could not find a version that satisfies the requirement pylibmc== (from 
  versions: 0.2, 0.3, 0.4, 0.5.1, 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5, 0.6.1, 0.6, 
  0.7.1, 0.7.2, 0.7.3, 0.7.4, 0.7, 0.8.1, 0.8.2, 0.8, 0.9.1, 0.9.2, 0.9, 
  1.0-alpha, 1.0-beta, 1.0, 1.1.1, 1.1, 1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.3.0)
No matching distribution found for pylibmc==

– all the available versions will be printed without actually downloading or installing any additional packages.

For pip < 9.0 use

pip install pylibmc==blork

where blork can be any string that is not a valid version number.


回答 2

更新:
自2017年9月起,此方法不再起作用:--no-install已在第7点中删除

采用 pip install -v,您可以查看所有可用的版本

root@node7:~# pip install web.py -v
Downloading/unpacking web.py
  Using version 0.37 (newest of versions: 0.37, 0.36, 0.35, 0.34, 0.33, 0.33, 0.32, 0.31, 0.22, 0.2)
  Downloading web.py-0.37.tar.gz (90Kb): 90Kb downloaded
  Running setup.py egg_info for package web.py
    running egg_info
    creating pip-egg-info/web.py.egg-info

要不安装任何软件包,请使用以下解决方案之一:

root@node7:~# pip install --no-deps --no-install flask -v                                                                                                      
Downloading/unpacking flask
  Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
  Downloading Flask-0.10.1.tar.gz (544Kb): 544Kb downloaded

要么

root@node7:~# cd $(mktemp -d)
root@node7:/tmp/tmp.c6H99cWD0g# pip install flask -d . -v
Downloading/unpacking flask
  Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
  Downloading Flask-0.10.1.tar.gz (544Kb): 4.1Kb downloaded

经过pip 1.0测试

root@node7:~# pip --version
pip 1.0 from /usr/lib/python2.7/dist-packages (python 2.7)

Update:
As of Sep 2017 this method no longer works: --no-install was removed in pip 7

Use pip install -v, you can see all versions that available

root@node7:~# pip install web.py -v
Downloading/unpacking web.py
  Using version 0.37 (newest of versions: 0.37, 0.36, 0.35, 0.34, 0.33, 0.33, 0.32, 0.31, 0.22, 0.2)
  Downloading web.py-0.37.tar.gz (90Kb): 90Kb downloaded
  Running setup.py egg_info for package web.py
    running egg_info
    creating pip-egg-info/web.py.egg-info

To not install any package, use one of following solution:

root@node7:~# pip install --no-deps --no-install flask -v                                                                                                      
Downloading/unpacking flask
  Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
  Downloading Flask-0.10.1.tar.gz (544Kb): 544Kb downloaded

or

root@node7:~# cd $(mktemp -d)
root@node7:/tmp/tmp.c6H99cWD0g# pip install flask -d . -v
Downloading/unpacking flask
  Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
  Downloading Flask-0.10.1.tar.gz (544Kb): 4.1Kb downloaded

Tested with pip 1.0

root@node7:~# pip --version
pip 1.0 from /usr/lib/python2.7/dist-packages (python 2.7)

回答 3

您不需要第三方软件包即可获取此信息。pypi为以下所有包提供了简单的JSON feed

https://pypi.python.org/pypi/{PKG_NAME}/json

以下是一些仅使用获取所有版本的标准库的Python代码。

import json
import urllib2
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.python.org/pypi/%s/json" % (package_name,)
    data = json.load(urllib2.urlopen(urllib2.Request(url)))
    versions = data["releases"].keys()
    versions.sort(key=StrictVersion)
    return versions

print "\n".join(versions("scikit-image"))

该代码打印出来(截至2015年2月23日):

0.7.2
0.8.0
0.8.1
0.8.2
0.9.0
0.9.1
0.9.2
0.9.3
0.10.0
0.10.1

You don’t need a third party package to get this information. pypi provides simple JSON feeds for all packages under

https://pypi.python.org/pypi/{PKG_NAME}/json

Here’s some Python code using only the standard library which gets all versions.

import json
import urllib2
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.python.org/pypi/%s/json" % (package_name,)
    data = json.load(urllib2.urlopen(urllib2.Request(url)))
    versions = data["releases"].keys()
    versions.sort(key=StrictVersion)
    return versions

print "\n".join(versions("scikit-image"))

That code prints (as of Feb 23rd, 2015):

0.7.2
0.8.0
0.8.1
0.8.2
0.9.0
0.9.1
0.9.2
0.9.3
0.10.0
0.10.1

回答 4

我想出了简单的bash脚本。感谢jq的作者。

#!/bin/bash
set -e

PACKAGE_JSON_URL="https://pypi.org/pypi/${1}/json"

curl -s "$PACKAGE_JSON_URL" | jq  -r '.releases | keys | .[]' | sort -V

更新:添加按版本号排序。

I came up with dead-simple bash script. Thanks to jq‘s author.

#!/bin/bash
set -e

PACKAGE_JSON_URL="https://pypi.org/pypi/${1}/json"

curl -s "$PACKAGE_JSON_URL" | jq  -r '.releases | keys | .[]' | sort -V

Update: Add sorting by version number.


回答 5

您可以使用yolk3k软件包而不是yolk。yolk3k是原始蛋黄的叉子,它同时支持python2和3。

https://github.com/myint/yolk

pip install yolk3k

You could the yolk3k package instead of yolk. yolk3k is a fork from the original yolk and it supports both python2 and 3.

https://github.com/myint/yolk

pip install yolk3k

回答 6

看了一段时间的pip代码后,看起来可以在中的PackageFinder类中找到负责定位软件包的代码pip.index。它的方法find_requirement查找的版本InstallRequirement,但不幸的是仅返回最新版本。

下面的代码几乎是原始函数的1:1副本,第114行的return更改为返回所有版本。

该脚本将一个包名称作为第一个也是唯一的参数,并返回所有版本。

http://pastebin.com/axzdUQhZ

我不保证正确性,因为我对pip的代码不熟悉。但希望这会有所帮助。

样品输出

python test.py pip
Versions of pip
0.8.2
0.8.1
0.8
0.7.2
0.7.1
0.7
0.6.3
0.6.2
0.6.1
0.6
0.5.1
0.5
0.4
0.3.1
0.3
0.2.1
0.2 dev

编码:

import posixpath
import pkg_resources
import sys
from pip.download import url_to_path
from pip.exceptions import DistributionNotFound
from pip.index import PackageFinder, Link
from pip.log import logger
from pip.req import InstallRequirement
from pip.util import Inf


class MyPackageFinder(PackageFinder):

    def find_requirement(self, req, upgrade):
        url_name = req.url_name
        # Only check main index if index URL is given:
        main_index_url = None
        if self.index_urls:
            # Check that we have the url_name correctly spelled:
            main_index_url = Link(posixpath.join(self.index_urls[0], url_name))
            # This will also cache the page, so it's okay that we get it again later:
            page = self._get_page(main_index_url, req)
            if page is None:
                url_name = self._find_url_name(Link(self.index_urls[0]), url_name, req) or req.url_name

        # Combine index URLs with mirror URLs here to allow
        # adding more index URLs from requirements files
        all_index_urls = self.index_urls + self.mirror_urls

        def mkurl_pypi_url(url):
            loc = posixpath.join(url, url_name)
            # For maximum compatibility with easy_install, ensure the path
            # ends in a trailing slash.  Although this isn't in the spec
            # (and PyPI can handle it without the slash) some other index
            # implementations might break if they relied on easy_install's behavior.
            if not loc.endswith('/'):
                loc = loc + '/'
            return loc
        if url_name is not None:
            locations = [
                mkurl_pypi_url(url)
                for url in all_index_urls] + self.find_links
        else:
            locations = list(self.find_links)
        locations.extend(self.dependency_links)
        for version in req.absolute_versions:
            if url_name is not None and main_index_url is not None:
                locations = [
                    posixpath.join(main_index_url.url, version)] + locations

        file_locations, url_locations = self._sort_locations(locations)

        locations = [Link(url) for url in url_locations]
        logger.debug('URLs to search for versions for %s:' % req)
        for location in locations:
            logger.debug('* %s' % location)
        found_versions = []
        found_versions.extend(
            self._package_versions(
                [Link(url, '-f') for url in self.find_links], req.name.lower()))
        page_versions = []
        for page in self._get_pages(locations, req):
            logger.debug('Analyzing links from page %s' % page.url)
            logger.indent += 2
            try:
                page_versions.extend(self._package_versions(page.links, req.name.lower()))
            finally:
                logger.indent -= 2
        dependency_versions = list(self._package_versions(
            [Link(url) for url in self.dependency_links], req.name.lower()))
        if dependency_versions:
            logger.info('dependency_links found: %s' % ', '.join([link.url for parsed, link, version in dependency_versions]))
        file_versions = list(self._package_versions(
                [Link(url) for url in file_locations], req.name.lower()))
        if not found_versions and not page_versions and not dependency_versions and not file_versions:
            logger.fatal('Could not find any downloads that satisfy the requirement %s' % req)
            raise DistributionNotFound('No distributions at all found for %s' % req)
        if req.satisfied_by is not None:
            found_versions.append((req.satisfied_by.parsed_version, Inf, req.satisfied_by.version))
        if file_versions:
            file_versions.sort(reverse=True)
            logger.info('Local files found: %s' % ', '.join([url_to_path(link.url) for parsed, link, version in file_versions]))
            found_versions = file_versions + found_versions
        all_versions = found_versions + page_versions + dependency_versions
        applicable_versions = []
        for (parsed_version, link, version) in all_versions:
            if version not in req.req:
                logger.info("Ignoring link %s, version %s doesn't match %s"
                            % (link, version, ','.join([''.join(s) for s in req.req.specs])))
                continue
            applicable_versions.append((link, version))
        applicable_versions = sorted(applicable_versions, key=lambda v: pkg_resources.parse_version(v[1]), reverse=True)
        existing_applicable = bool([link for link, version in applicable_versions if link is Inf])
        if not upgrade and existing_applicable:
            if applicable_versions[0][1] is Inf:
                logger.info('Existing installed version (%s) is most up-to-date and satisfies requirement'
                            % req.satisfied_by.version)
            else:
                logger.info('Existing installed version (%s) satisfies requirement (most up-to-date version is %s)'
                            % (req.satisfied_by.version, applicable_versions[0][1]))
            return None
        if not applicable_versions:
            logger.fatal('Could not find a version that satisfies the requirement %s (from versions: %s)'
                         % (req, ', '.join([version for parsed_version, link, version in found_versions])))
            raise DistributionNotFound('No distributions matching the version for %s' % req)
        if applicable_versions[0][0] is Inf:
            # We have an existing version, and its the best version
            logger.info('Installed version (%s) is most up-to-date (past versions: %s)'
                        % (req.satisfied_by.version, ', '.join([version for link, version in applicable_versions[1:]]) or 'none'))
            return None
        if len(applicable_versions) > 1:
            logger.info('Using version %s (newest of versions: %s)' %
                        (applicable_versions[0][1], ', '.join([version for link, version in applicable_versions])))
        return applicable_versions


if __name__ == '__main__':
    req = InstallRequirement.from_line(sys.argv[1], None)
    finder = MyPackageFinder([], ['http://pypi.python.org/simple/'])
    versions = finder.find_requirement(req, False)
    print 'Versions of %s' % sys.argv[1]
    for v in versions:
        print v[1]

After looking at pip’s code for a while, it looks like the code responsible for locating packages can be found in the PackageFinder class in pip.index. Its method find_requirement looks up the versions of a InstallRequirement, but unfortunately only returns the most recent version.

The code below is almost a 1:1 copy of the original function, with the return in line 114 changed to return all versions.

The script expects one package name as first and only argument and returns all versions.

http://pastebin.com/axzdUQhZ

I can’t guarantee for the correctness, as I’m not familiar with pip’s code. But hopefully this helps.

Sample output

python test.py pip
Versions of pip
0.8.2
0.8.1
0.8
0.7.2
0.7.1
0.7
0.6.3
0.6.2
0.6.1
0.6
0.5.1
0.5
0.4
0.3.1
0.3
0.2.1
0.2 dev

The code:

import posixpath
import pkg_resources
import sys
from pip.download import url_to_path
from pip.exceptions import DistributionNotFound
from pip.index import PackageFinder, Link
from pip.log import logger
from pip.req import InstallRequirement
from pip.util import Inf


class MyPackageFinder(PackageFinder):

    def find_requirement(self, req, upgrade):
        url_name = req.url_name
        # Only check main index if index URL is given:
        main_index_url = None
        if self.index_urls:
            # Check that we have the url_name correctly spelled:
            main_index_url = Link(posixpath.join(self.index_urls[0], url_name))
            # This will also cache the page, so it's okay that we get it again later:
            page = self._get_page(main_index_url, req)
            if page is None:
                url_name = self._find_url_name(Link(self.index_urls[0]), url_name, req) or req.url_name

        # Combine index URLs with mirror URLs here to allow
        # adding more index URLs from requirements files
        all_index_urls = self.index_urls + self.mirror_urls

        def mkurl_pypi_url(url):
            loc = posixpath.join(url, url_name)
            # For maximum compatibility with easy_install, ensure the path
            # ends in a trailing slash.  Although this isn't in the spec
            # (and PyPI can handle it without the slash) some other index
            # implementations might break if they relied on easy_install's behavior.
            if not loc.endswith('/'):
                loc = loc + '/'
            return loc
        if url_name is not None:
            locations = [
                mkurl_pypi_url(url)
                for url in all_index_urls] + self.find_links
        else:
            locations = list(self.find_links)
        locations.extend(self.dependency_links)
        for version in req.absolute_versions:
            if url_name is not None and main_index_url is not None:
                locations = [
                    posixpath.join(main_index_url.url, version)] + locations

        file_locations, url_locations = self._sort_locations(locations)

        locations = [Link(url) for url in url_locations]
        logger.debug('URLs to search for versions for %s:' % req)
        for location in locations:
            logger.debug('* %s' % location)
        found_versions = []
        found_versions.extend(
            self._package_versions(
                [Link(url, '-f') for url in self.find_links], req.name.lower()))
        page_versions = []
        for page in self._get_pages(locations, req):
            logger.debug('Analyzing links from page %s' % page.url)
            logger.indent += 2
            try:
                page_versions.extend(self._package_versions(page.links, req.name.lower()))
            finally:
                logger.indent -= 2
        dependency_versions = list(self._package_versions(
            [Link(url) for url in self.dependency_links], req.name.lower()))
        if dependency_versions:
            logger.info('dependency_links found: %s' % ', '.join([link.url for parsed, link, version in dependency_versions]))
        file_versions = list(self._package_versions(
                [Link(url) for url in file_locations], req.name.lower()))
        if not found_versions and not page_versions and not dependency_versions and not file_versions:
            logger.fatal('Could not find any downloads that satisfy the requirement %s' % req)
            raise DistributionNotFound('No distributions at all found for %s' % req)
        if req.satisfied_by is not None:
            found_versions.append((req.satisfied_by.parsed_version, Inf, req.satisfied_by.version))
        if file_versions:
            file_versions.sort(reverse=True)
            logger.info('Local files found: %s' % ', '.join([url_to_path(link.url) for parsed, link, version in file_versions]))
            found_versions = file_versions + found_versions
        all_versions = found_versions + page_versions + dependency_versions
        applicable_versions = []
        for (parsed_version, link, version) in all_versions:
            if version not in req.req:
                logger.info("Ignoring link %s, version %s doesn't match %s"
                            % (link, version, ','.join([''.join(s) for s in req.req.specs])))
                continue
            applicable_versions.append((link, version))
        applicable_versions = sorted(applicable_versions, key=lambda v: pkg_resources.parse_version(v[1]), reverse=True)
        existing_applicable = bool([link for link, version in applicable_versions if link is Inf])
        if not upgrade and existing_applicable:
            if applicable_versions[0][1] is Inf:
                logger.info('Existing installed version (%s) is most up-to-date and satisfies requirement'
                            % req.satisfied_by.version)
            else:
                logger.info('Existing installed version (%s) satisfies requirement (most up-to-date version is %s)'
                            % (req.satisfied_by.version, applicable_versions[0][1]))
            return None
        if not applicable_versions:
            logger.fatal('Could not find a version that satisfies the requirement %s (from versions: %s)'
                         % (req, ', '.join([version for parsed_version, link, version in found_versions])))
            raise DistributionNotFound('No distributions matching the version for %s' % req)
        if applicable_versions[0][0] is Inf:
            # We have an existing version, and its the best version
            logger.info('Installed version (%s) is most up-to-date (past versions: %s)'
                        % (req.satisfied_by.version, ', '.join([version for link, version in applicable_versions[1:]]) or 'none'))
            return None
        if len(applicable_versions) > 1:
            logger.info('Using version %s (newest of versions: %s)' %
                        (applicable_versions[0][1], ', '.join([version for link, version in applicable_versions])))
        return applicable_versions


if __name__ == '__main__':
    req = InstallRequirement.from_line(sys.argv[1], None)
    finder = MyPackageFinder([], ['http://pypi.python.org/simple/'])
    versions = finder.find_requirement(req, False)
    print 'Versions of %s' % sys.argv[1]
    for v in versions:
        print v[1]

回答 7

您可以使用这个小的Python 3脚本(仅使用标准库模块)来使用JSON API从PyPI抓取软件包的可用版本列表,并以相反的时间顺序打印它们。不像其他一些Python的解决方案张贴在这里,但这并不松散的版本一样突破django2.2rc1还是uwsgi2.0.17.1

#!/usr/bin/env python3

import json
import sys
from urllib import request    
from pkg_resources import parse_version    

def versions(pkg_name):
    url = f'https://pypi.python.org/pypi/{pkg_name}/json'
    releases = json.loads(request.urlopen(url).read())['releases']
    return sorted(releases, key=parse_version, reverse=True)    

if __name__ == '__main__':
    print(*versions(sys.argv[1]), sep='\n')

保存脚本并以包名称作为参数运行它,例如:

python versions.py django
3.0a1
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2
2.2rc1
...

You can use this small Python 3 script (using only standard library modules) to grab the list of available versions for a package from PyPI using JSON API and print them in reverse chronological order. Unlike some other Python solutions posted here, this doesn’t break on loose versions like django‘s 2.2rc1 or uwsgi‘s 2.0.17.1:

#!/usr/bin/env python3

import json
import sys
from urllib import request    
from pkg_resources import parse_version    

def versions(pkg_name):
    url = f'https://pypi.python.org/pypi/{pkg_name}/json'
    releases = json.loads(request.urlopen(url).read())['releases']
    return sorted(releases, key=parse_version, reverse=True)    

if __name__ == '__main__':
    print(*versions(sys.argv[1]), sep='\n')

Save the script and run it with the package name as an argument, e.g.:

python versions.py django
3.0a1
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2
2.2rc1
...

回答 8

https://pypi.python.org/pypi/Django/适用于维护者选择显示所有软件包的软件包 https://pypi.python.org/simple/pip/-无论如何都应该做到这一点(列出所有链接)

https://pypi.python.org/pypi/Django/ – works for packages whose maintainers choose to show all packages https://pypi.python.org/simple/pip/ – should do the trick anyhow (lists all links)


回答 9

这对我在OSX上有效:

pip install docker-compose== 2>&1 \
| grep -oE '(\(.*\))' \
| awk -F:\  '{print$NF}' \
| sed -E 's/( |\))//g' \
| tr ',' '\n'

它每行返回一个列表:

1.1.0rc1
1.1.0rc2
1.1.0
1.2.0rc1
1.2.0rc2
1.2.0rc3
1.2.0rc4
1.2.0
1.3.0rc1
1.3.0rc2
1.3.0rc3
1.3.0
1.3.1
1.3.2
1.3.3
1.4.0rc1
1.4.0rc2
1.4.0rc3
1.4.0
1.4.1
1.4.2
1.5.0rc1
1.5.0rc2
1.5.0rc3
1.5.0
1.5.1
1.5.2
1.6.0rc1
1.6.0
1.6.1
1.6.2
1.7.0rc1
1.7.0rc2
1.7.0
1.7.1
1.8.0rc1
1.8.0rc2
1.8.0
1.8.1
1.9.0rc1
1.9.0rc2
1.9.0rc3
1.9.0rc4
1.9.0
1.10.0rc1
1.10.0rc2
1.10.0

或获取可用的最新版本:

pip install docker-compose== 2>&1 \
| grep -oE '(\(.*\))' \
| awk -F:\  '{print$NF}' \
| sed -E 's/( |\))//g' \
| tr ',' '\n' \
| gsort -r -V \
| head -1
1.10.0rc2

请记住gsort,必须安装(在OSX上)以解析版本。您可以使用安装brew install coreutils

This works for me on OSX:

pip install docker-compose== 2>&1 \
| grep -oE '(\(.*\))' \
| awk -F:\  '{print$NF}' \
| sed -E 's/( |\))//g' \
| tr ',' '\n'

It returns the list one per line:

1.1.0rc1
1.1.0rc2
1.1.0
1.2.0rc1
1.2.0rc2
1.2.0rc3
1.2.0rc4
1.2.0
1.3.0rc1
1.3.0rc2
1.3.0rc3
1.3.0
1.3.1
1.3.2
1.3.3
1.4.0rc1
1.4.0rc2
1.4.0rc3
1.4.0
1.4.1
1.4.2
1.5.0rc1
1.5.0rc2
1.5.0rc3
1.5.0
1.5.1
1.5.2
1.6.0rc1
1.6.0
1.6.1
1.6.2
1.7.0rc1
1.7.0rc2
1.7.0
1.7.1
1.8.0rc1
1.8.0rc2
1.8.0
1.8.1
1.9.0rc1
1.9.0rc2
1.9.0rc3
1.9.0rc4
1.9.0
1.10.0rc1
1.10.0rc2
1.10.0

Or to get the latest version available:

pip install docker-compose== 2>&1 \
| grep -oE '(\(.*\))' \
| awk -F:\  '{print$NF}' \
| sed -E 's/( |\))//g' \
| tr ',' '\n' \
| gsort -r -V \
| head -1
1.10.0rc2

Keep in mind gsort has to be installed (on OSX) to parse the versions. You can install it with brew install coreutils


回答 10

我的项目luddite具有此功能。

用法示例:

>>> import luddite
>>> luddite.get_versions_pypi("python-dateutil")
('0.1', '0.3', '0.4', '0.5', '1.0', '1.1', '1.2', '1.4', '1.4.1', '1.5', '2.0', '2.1', '2.2', '2.3', '2.4.0', '2.4.1', '2.4.2', '2.5.0', '2.5.1', '2.5.2', '2.5.3', '2.6.0', '2.6.1', '2.7.0', '2.7.1', '2.7.2', '2.7.3', '2.7.4', '2.7.5', '2.8.0')

通过查询https://pypi.org/的json API,它列出了可用软件包的所有版本。

My project luddite has this feature.

Example usage:

>>> import luddite
>>> luddite.get_versions_pypi("python-dateutil")
('0.1', '0.3', '0.4', '0.5', '1.0', '1.1', '1.2', '1.4', '1.4.1', '1.5', '2.0', '2.1', '2.2', '2.3', '2.4.0', '2.4.1', '2.4.2', '2.5.0', '2.5.1', '2.5.2', '2.5.3', '2.6.0', '2.6.1', '2.7.0', '2.7.1', '2.7.2', '2.7.3', '2.7.4', '2.7.5', '2.8.0')

It lists all versions of a package available, by querying the json API of https://pypi.org/


回答 11

我没有任何运气yolkyolk3kpip install -v可是所以最后我用这个(埃里克蒋介石的回答适合到Python 3):

import json
import requests
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.python.org/pypi/{}/json".format(package_name)
    data = requests.get(url).json()
    return sorted(list(data["releases"].keys()), key=StrictVersion, reverse=True)

>>> print("\n".join(versions("gunicorn")))
19.1.1
19.1.0
19.0.0
18.0
17.5
0.17.4
0.17.3
...

I didn’t have any luck with yolk, yolk3k or pip install -v but so I ended up using this (adapted to Python 3 from eric chiang’s answer):

import json
import requests
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.python.org/pypi/{}/json".format(package_name)
    data = requests.get(url).json()
    return sorted(list(data["releases"].keys()), key=StrictVersion, reverse=True)

>>> print("\n".join(versions("gunicorn")))
19.1.1
19.1.0
19.0.0
18.0
17.5
0.17.4
0.17.3
...

回答 12

另一种解决方案是使用Warehouse API:

https://warehouse.readthedocs.io/api-reference/json/#release

例如Flask:

import requests
r = requests.get("https://pypi.org/pypi/Flask/json")
print(r.json()['releases'].keys())

将打印:

dict_keys(['0.1', '0.10', '0.10.1', '0.11', '0.11.1', '0.12', '0.12.1', '0.12.2', '0.12.3', '0.12.4', '0.2', '0.3', '0.3.1', '0.4', '0.5', '0.5.1', '0.5.2', '0.6', '0.6.1', '0.7', '0.7.1', '0.7.2', '0.8', '0.8.1', '0.9', '1.0', '1.0.1', '1.0.2'])

Alternative solution is to use the Warehouse APIs:

https://warehouse.readthedocs.io/api-reference/json/#release

For instance for Flask:

import requests
r = requests.get("https://pypi.org/pypi/Flask/json")
print(r.json()['releases'].keys())

will print:

dict_keys(['0.1', '0.10', '0.10.1', '0.11', '0.11.1', '0.12', '0.12.1', '0.12.2', '0.12.3', '0.12.4', '0.2', '0.3', '0.3.1', '0.4', '0.5', '0.5.1', '0.5.2', '0.6', '0.6.1', '0.7', '0.7.1', '0.7.2', '0.8', '0.8.1', '0.9', '1.0', '1.0.1', '1.0.2'])

回答 13

bash仅依赖于python自身的简单脚本(我假设应该在问题的上下文中进行安装)以及curl或之一wget。假设您已setuptools安装软件包以对版本进行排序(几乎始终已安装)。它不依赖外部依赖项,例如:

  • jq 可能不存在;
  • grep并且awk在Linux和macOS上的行为可能有所不同。
curl --silent --location https://pypi.org/pypi/requests/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))"

带有注释的较长版本。

将包名称放入变量中:

PACKAGE=requests

获取版本(使用curl):

VERSIONS=$(curl --silent --location https://pypi.org/pypi/$PACKAGE/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))")

获取版本(使用wget):

VERSIONS=$(wget -qO- https://pypi.org/pypi/$PACKAGE/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))")

打印排序版本:

echo $VERSIONS

Simple bash script that relies only on python itself (I assume that in the context of the question it should be installed) and one of curl or wget. It has an assumption that you have setuptools package installed to sort versions (almost always installed). It doesn’t rely on external dependencies such as:

  • jq which may not be present;
  • grep and awk that may behave differently on Linux and macOS.
curl --silent --location https://pypi.org/pypi/requests/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))"

A little bit longer version with comments.

Put the package name into a variable:

PACKAGE=requests

Get versions (using curl):

VERSIONS=$(curl --silent --location https://pypi.org/pypi/$PACKAGE/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))")

Get versions (using wget):

VERSIONS=$(wget -qO- https://pypi.org/pypi/$PACKAGE/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))")

Print sorted versions:

echo $VERSIONS

回答 14

我的看法是结合了几个已发布的答案,并进行了一些修改,以使其在运行中的python环境中更易于使用。

这个想法是提供一个全新的命令(在install命令之后建模),为您提供要使用的软件包查找程序的实例。好处是,它可以与pip支持并读取本地pip配置文件的任何索引一起使用并使用,因此您可以获得与普通pip安装相同的正确结果。

我已经尝试使其与pip v 9.x和10.x兼容。.但是仅在9.x上尝试过

https://gist.github.com/kaos/68511bd013fcdebe766c981f50b473d4

#!/usr/bin/env python
# When you want a easy way to get at all (or the latest) version of a certain python package from a PyPi index.

import sys
import logging

try:
    from pip._internal import cmdoptions, main
    from pip._internal.commands import commands_dict
    from pip._internal.basecommand import RequirementCommand
except ImportError:
    from pip import cmdoptions, main
    from pip.commands import commands_dict
    from pip.basecommand import RequirementCommand

from pip._vendor.packaging.version import parse as parse_version

logger = logging.getLogger('pip')

class ListPkgVersionsCommand(RequirementCommand):
    """
    List all available versions for a given package from:

    - PyPI (and other indexes) using requirement specifiers.
    - VCS project urls.
    - Local project directories.
    - Local or remote source archives.

    """
    name = "list-pkg-versions"
    usage = """
      %prog [options] <requirement specifier> [package-index-options] ...
      %prog [options] [-e] <vcs project url> ...
      %prog [options] [-e] <local project path> ...
      %prog [options] <archive url/path> ..."""

    summary = 'List package versions.'

    def __init__(self, *args, **kw):
        super(ListPkgVersionsCommand, self).__init__(*args, **kw)

        cmd_opts = self.cmd_opts

        cmd_opts.add_option(cmdoptions.install_options())
        cmd_opts.add_option(cmdoptions.global_options())
        cmd_opts.add_option(cmdoptions.use_wheel())
        cmd_opts.add_option(cmdoptions.no_use_wheel())
        cmd_opts.add_option(cmdoptions.no_binary())
        cmd_opts.add_option(cmdoptions.only_binary())
        cmd_opts.add_option(cmdoptions.pre())
        cmd_opts.add_option(cmdoptions.require_hashes())

        index_opts = cmdoptions.make_option_group(
            cmdoptions.index_group,
            self.parser,
        )

        self.parser.insert_option_group(0, index_opts)
        self.parser.insert_option_group(0, cmd_opts)

    def run(self, options, args):
        cmdoptions.resolve_wheel_no_use_binary(options)
        cmdoptions.check_install_build_global(options)

        with self._build_session(options) as session:
            finder = self._build_package_finder(options, session)

            # do what you please with the finder object here... ;)
            for pkg in args:
                logger.info(
                    '%s: %s', pkg,
                    ', '.join(
                        sorted(
                            set(str(c.version) for c in finder.find_all_candidates(pkg)),
                            key=parse_version,
                        )
                    )
                )


commands_dict[ListPkgVersionsCommand.name] = ListPkgVersionsCommand

if __name__ == '__main__':
    sys.exit(main())

输出示例

./list-pkg-versions.py list-pkg-versions pika django
pika: 0.5, 0.5.1, 0.5.2, 0.9.1a0, 0.9.2a0, 0.9.3, 0.9.4, 0.9.5, 0.9.6, 0.9.7, 0.9.8, 0.9.9, 0.9.10, 0.9.11, 0.9.12, 0.9.13, 0.9.14, 0.10.0b1, 0.10.0b2, 0.10.0, 0.11.0b1, 0.11.0, 0.11.1, 0.11.2, 0.12.0b2
django: 1.1.3, 1.1.4, 1.2, 1.2.1, 1.2.2, 1.2.3, 1.2.4, 1.2.5, 1.2.6, 1.2.7, 1.3, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7, 1.4, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.4.8, 1.4.9, 1.4.10, 1.4.11, 1.4.12, 1.4.13, 1.4.14, 1.4.15, 1.4.16, 1.4.17, 1.4.18, 1.4.19, 1.4.20, 1.4.21, 1.4.22, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.5.5, 1.5.6, 1.5.7, 1.5.8, 1.5.9, 1.5.10, 1.5.11, 1.5.12, 1.6, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, 1.6.9, 1.6.10, 1.6.11, 1.7, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9, 1.7.10, 1.7.11, 1.8a1, 1.8b1, 1.8b2, 1.8rc1, 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.8.6, 1.8.7, 1.8.8, 1.8.9, 1.8.10, 1.8.11, 1.8.12, 1.8.13, 1.8.14, 1.8.15, 1.8.16, 1.8.17, 1.8.18, 1.8.19, 1.9a1, 1.9b1, 1.9rc1, 1.9rc2, 1.9, 1.9.1, 1.9.2, 1.9.3, 1.9.4, 1.9.5, 1.9.6, 1.9.7, 1.9.8, 1.9.9, 1.9.10, 1.9.11, 1.9.12, 1.9.13, 1.10a1, 1.10b1, 1.10rc1, 1.10, 1.10.1, 1.10.2, 1.10.3, 1.10.4, 1.10.5, 1.10.6, 1.10.7, 1.10.8, 1.11a1, 1.11b1, 1.11rc1, 1.11, 1.11.1, 1.11.2, 1.11.3, 1.11.4, 1.11.5, 1.11.6, 1.11.7, 1.11.8, 1.11.9, 1.11.10, 1.11.11, 1.11.12, 2.0, 2.0.1, 2.0.2, 2.0.3, 2.0.4

My take is a combination of a couple of posted answers, with some modifications to make them easier to use from within a running python environment.

The idea is to provide a entirely new command (modeled after the install command) that gives you an instance of the package finder to use. The upside is that it works with, and uses, any indexes that pip supports and reads your local pip configuration files, so you get the correct results as you would with a normal pip install.

I’ve made an attempt at making it compatible with both pip v 9.x and 10.x.. but only tried it on 9.x

https://gist.github.com/kaos/68511bd013fcdebe766c981f50b473d4

#!/usr/bin/env python
# When you want a easy way to get at all (or the latest) version of a certain python package from a PyPi index.

import sys
import logging

try:
    from pip._internal import cmdoptions, main
    from pip._internal.commands import commands_dict
    from pip._internal.basecommand import RequirementCommand
except ImportError:
    from pip import cmdoptions, main
    from pip.commands import commands_dict
    from pip.basecommand import RequirementCommand

from pip._vendor.packaging.version import parse as parse_version

logger = logging.getLogger('pip')

class ListPkgVersionsCommand(RequirementCommand):
    """
    List all available versions for a given package from:

    - PyPI (and other indexes) using requirement specifiers.
    - VCS project urls.
    - Local project directories.
    - Local or remote source archives.

    """
    name = "list-pkg-versions"
    usage = """
      %prog [options] <requirement specifier> [package-index-options] ...
      %prog [options] [-e] <vcs project url> ...
      %prog [options] [-e] <local project path> ...
      %prog [options] <archive url/path> ..."""

    summary = 'List package versions.'

    def __init__(self, *args, **kw):
        super(ListPkgVersionsCommand, self).__init__(*args, **kw)

        cmd_opts = self.cmd_opts

        cmd_opts.add_option(cmdoptions.install_options())
        cmd_opts.add_option(cmdoptions.global_options())
        cmd_opts.add_option(cmdoptions.use_wheel())
        cmd_opts.add_option(cmdoptions.no_use_wheel())
        cmd_opts.add_option(cmdoptions.no_binary())
        cmd_opts.add_option(cmdoptions.only_binary())
        cmd_opts.add_option(cmdoptions.pre())
        cmd_opts.add_option(cmdoptions.require_hashes())

        index_opts = cmdoptions.make_option_group(
            cmdoptions.index_group,
            self.parser,
        )

        self.parser.insert_option_group(0, index_opts)
        self.parser.insert_option_group(0, cmd_opts)

    def run(self, options, args):
        cmdoptions.resolve_wheel_no_use_binary(options)
        cmdoptions.check_install_build_global(options)

        with self._build_session(options) as session:
            finder = self._build_package_finder(options, session)

            # do what you please with the finder object here... ;)
            for pkg in args:
                logger.info(
                    '%s: %s', pkg,
                    ', '.join(
                        sorted(
                            set(str(c.version) for c in finder.find_all_candidates(pkg)),
                            key=parse_version,
                        )
                    )
                )


commands_dict[ListPkgVersionsCommand.name] = ListPkgVersionsCommand

if __name__ == '__main__':
    sys.exit(main())

Example output

./list-pkg-versions.py list-pkg-versions pika django
pika: 0.5, 0.5.1, 0.5.2, 0.9.1a0, 0.9.2a0, 0.9.3, 0.9.4, 0.9.5, 0.9.6, 0.9.7, 0.9.8, 0.9.9, 0.9.10, 0.9.11, 0.9.12, 0.9.13, 0.9.14, 0.10.0b1, 0.10.0b2, 0.10.0, 0.11.0b1, 0.11.0, 0.11.1, 0.11.2, 0.12.0b2
django: 1.1.3, 1.1.4, 1.2, 1.2.1, 1.2.2, 1.2.3, 1.2.4, 1.2.5, 1.2.6, 1.2.7, 1.3, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7, 1.4, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.4.8, 1.4.9, 1.4.10, 1.4.11, 1.4.12, 1.4.13, 1.4.14, 1.4.15, 1.4.16, 1.4.17, 1.4.18, 1.4.19, 1.4.20, 1.4.21, 1.4.22, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.5.5, 1.5.6, 1.5.7, 1.5.8, 1.5.9, 1.5.10, 1.5.11, 1.5.12, 1.6, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, 1.6.9, 1.6.10, 1.6.11, 1.7, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9, 1.7.10, 1.7.11, 1.8a1, 1.8b1, 1.8b2, 1.8rc1, 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.8.6, 1.8.7, 1.8.8, 1.8.9, 1.8.10, 1.8.11, 1.8.12, 1.8.13, 1.8.14, 1.8.15, 1.8.16, 1.8.17, 1.8.18, 1.8.19, 1.9a1, 1.9b1, 1.9rc1, 1.9rc2, 1.9, 1.9.1, 1.9.2, 1.9.3, 1.9.4, 1.9.5, 1.9.6, 1.9.7, 1.9.8, 1.9.9, 1.9.10, 1.9.11, 1.9.12, 1.9.13, 1.10a1, 1.10b1, 1.10rc1, 1.10, 1.10.1, 1.10.2, 1.10.3, 1.10.4, 1.10.5, 1.10.6, 1.10.7, 1.10.8, 1.11a1, 1.11b1, 1.11rc1, 1.11, 1.11.1, 1.11.2, 1.11.3, 1.11.4, 1.11.5, 1.11.6, 1.11.7, 1.11.8, 1.11.9, 1.11.10, 1.11.11, 1.11.12, 2.0, 2.0.1, 2.0.2, 2.0.3, 2.0.4