分类目录归档:知识问答

在Python中,“ SyntaxError:调用’print’时缺少括号”是什么意思?

问题:在Python中,“ SyntaxError:调用’print’时缺少括号”是什么意思?

当我尝试print在Python中使用语句时,它给了我这个错误:

>>> print "Hello, World!"
  File "<stdin>", line 1
    print "Hello, World!"
                        ^
SyntaxError: Missing parentheses in call to 'print'

这意味着什么?

When I try to use a print statement in Python, it gives me this error:

>>> print "Hello, World!"
  File "<stdin>", line 1
    print "Hello, World!"
                        ^
SyntaxError: Missing parentheses in call to 'print'

What does that mean?


回答 0

此错误消息表示您尝试使用Python 3遵循示例或运行使用Python 2 print语句的程序:

print "Hello, World!"

上面的语句在Python 3中不起作用。在Python 3中,您需要在要打印的值周围添加括号:

print("Hello, World!")

“ SyntaxError:对’print’的调用中缺少括号”是Python 3.4.2中新增的一条错误消息,主要是为了帮助试图在运行Python 3时遵循Python 2教程的用户。

在Python 3中,打印值已从一个独特的语句变为一个普通的函数调用,因此现在需要括号:

>>> print("Hello, World!")
Hello, World!

在Python 3的早期版本中,解释器仅报告通用语法错误,而没有提供任何有用的提示来提示可能出了什么问题:

>>> print "Hello, World!"
  File "<stdin>", line 1
    print "Hello, World!"
                        ^
SyntaxError: invalid syntax

至于为什么 print在Python 3中成为普通函数,这与语句的基本形式无关,而是与如何执行更复杂的事情类似,例如将多个项目打印到带有尾部空格的stderr而不是结束行。

在Python 2中:

>>> import sys
>>> print >> sys.stderr, 1, 2, 3,; print >> sys.stderr, 4, 5, 6
1 2 3 4 5 6

在Python 3中:

>>> import sys
>>> print(1, 2, 3, file=sys.stderr, end=" "); print(4, 5, 6, file=sys.stderr)
1 2 3 4 5 6

从2017年9月的Python 3.6.3版本开始,一些与Python 2.x打印语法有关的错误消息已更新,以推荐与之对应的Python 3.x:

>>> print "Hello!"
  File "<stdin>", line 1
    print "Hello!"
                 ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Hello!")?

由于“在打印输出中缺少括号”情况是编译时语法错误,因此可以访问原始源代码,因此可以在建议的替换内容中在行的其余部分包含全文。但是,它目前并未尝试找出适合该表达式的引号(这不是不可能的,只是足够复杂以至于尚未完成)。

TypeError募投向右移位运算符也被定制:

>>> print >> sys.stderr
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for >>: 'builtin_function_or_method' and '_io.TextIOWrapper'. Did you mean "print(<message>, file=<output_stream>)"?

由于此错误是在代码运行时(而不是在编译时)引发的,因此它无法访问原始源代码,因此在建议的替换表达式中使用元变量(<message><output_stream>),而不是用户实际键入的内容。与语法错误的情况不同,在自定义右移错误消息中将引号放在Python表达式周围很简单。

This error message means that you are attempting to use Python 3 to follow an example or run a program that uses the Python 2 print statement:

print "Hello, World!"

The statement above does not work in Python 3. In Python 3 you need to add parentheses around the value to be printed:

print("Hello, World!")

“SyntaxError: Missing parentheses in call to ‘print’” is a new error message that was added in Python 3.4.2 primarily to help users that are trying to follow a Python 2 tutorial while running Python 3.

In Python 3, printing values changed from being a distinct statement to being an ordinary function call, so it now needs parentheses:

>>> print("Hello, World!")
Hello, World!

In earlier versions of Python 3, the interpreter just reports a generic syntax error, without providing any useful hints as to what might be going wrong:

>>> print "Hello, World!"
  File "<stdin>", line 1
    print "Hello, World!"
                        ^
SyntaxError: invalid syntax

As for why print became an ordinary function in Python 3, that didn’t relate to the basic form of the statement, but rather to how you did more complicated things like printing multiple items to stderr with a trailing space rather than ending the line.

In Python 2:

>>> import sys
>>> print >> sys.stderr, 1, 2, 3,; print >> sys.stderr, 4, 5, 6
1 2 3 4 5 6

In Python 3:

>>> import sys
>>> print(1, 2, 3, file=sys.stderr, end=" "); print(4, 5, 6, file=sys.stderr)
1 2 3 4 5 6

Starting with the Python 3.6.3 release in September 2017, some error messages related to the Python 2.x print syntax have been updated to recommend their Python 3.x counterparts:

>>> print "Hello!"
  File "<stdin>", line 1
    print "Hello!"
                 ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Hello!")?

Since the “Missing parentheses in call to print” case is a compile time syntax error and hence has access to the raw source code, it’s able to include the full text on the rest of the line in the suggested replacement. However, it doesn’t currently try to work out the appropriate quotes to place around that expression (that’s not impossible, just sufficiently complicated that it hasn’t been done).

The TypeError raised for the right shift operator has also been customised:

>>> print >> sys.stderr
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for >>: 'builtin_function_or_method' and '_io.TextIOWrapper'. Did you mean "print(<message>, file=<output_stream>)"?

Since this error is raised when the code runs, rather than when it is compiled, it doesn’t have access to the raw source code, and hence uses meta-variables (<message> and <output_stream>) in the suggested replacement expression instead of whatever the user actually typed. Unlike the syntax error case, it’s straightforward to place quotes around the Python expression in the custom right shift error message.


回答 1

不幸的是,旧的xkcd漫画不再完全是最新的。

https://imgs.xkcd.com/comics/python.png

从Python 3.0开始,您必须编写:

print("Hello, World!")

而且仍然有人要编写该antigravity库:(

Unfortunately, the old xkcd comic isn’t completely up to date anymore.

https://imgs.xkcd.com/comics/python.png

Since Python 3.0 you have to write:

print("Hello, World!")

And someone has still to write that antigravity library :(


回答 2

语法从Python 2更改为Python3。在Python 2中,

print "Hello, World!" 

可以使用,但是在Python 3中,使用括号作为

print("Hello, World!")

这与Scala等效,与Java差不多。

There is a change in syntax from Python 2 to Python 3. In Python 2,

print "Hello, World!" 

will work but in Python 3, use parentheses as

print("Hello, World!")

This is equivalent syntax to Scala and near to Java.


回答 3

如果您的代码在Python 2和3中都可以使用,则可以通过在程序开始时加载以下代码来实现:

from __future__ import print_function   # If code has to work in Python 2 and 3!

然后,您可以使用Python 3方式进行打印:

print("python")

如果要打印某些内容而不创建新行,则可以执行以下操作:

for number in range(0, 10):
    print(number, end=', ')

If your code should work in both Python 2 and 3, you can achieve this by loading this at the beginning of your program:

from __future__ import print_function   # If code has to work in Python 2 and 3!

Then you can print in the Python 3 way:

print("python")

If you want to print something without creating a new line – you can do this:

for number in range(0, 10):
    print(number, end=', ')

回答 4

在Python 3中,您只能将其打印为:

print("STRING")

但是在Python 2中,不需要括号。

In Python 3, you can only print as:

print("STRING")

But in Python 2, the parentheses are not necessary.


回答 5

基本上,从Python 3.x开始,您需要使用 print括号。

Python 2.x:打印“指环王”

Python 3.x:print(“指环王”)


讲解

print2.x中是一个语句,但在3.x中是一个函数。现在,有很多充分的理由。

  1. 使用Python 3.x的函数格式,当打印多个用逗号分隔的项目时,灵活性更高。
  2. 您不能在语句中使用参数展开。在3.x中,如果有要使用分隔符打印的项目列表,则可以执行以下操作:
>>> items = ['foo', 'bar', 'baz']
>>> print(*items, sep='+') 
foo+bar+baz
  1. 您不能覆盖语句。如果要更改print的行为,则可以在它是一个函数时执行此操作,但在声明时不可以。

Basically, since Python 3.x you need to use print with parenthesis.

Python 2.x: print “Lord of the Rings”

Python 3.x: print(“Lord of the Rings”)


Explaination

print was a statement in 2.x, but it’s a function in 3.x. Now, there are a number of good reasons for this.

  1. With function format of Python 3.x, more flexibility comes when printing multiple items with comman separated.
  2. You can’t use argument splatting with a statement. In 3.x if you have a list of items that you want to print with a separator, you can do this:
>>> items = ['foo', 'bar', 'baz']
>>> print(*items, sep='+') 
foo+bar+baz
  1. You can’t override a statement. If you want to change the behavior of print, you can do that when it’s a function but not when it’s a statement.

回答 6

我还可以补充一点,我知道Python2.7和之间有关语法更改的所有知识Python3,并且我的代码正确编写为as print("string")甚至 print(f"string")

但是经过一段时间的调试后,我意识到我的bash脚本正在像这样调用python:

python file_name.py

这具有默认情况下使用python调用我的python脚本的作用,从而产生python2.7了错误。因此,我将bash脚本更改为:

python3 file_name.py

哪个使用python3来运行修复了错误的脚本。

I could also just add that I knew everything about the syntax change between Python2.7 and Python3, and my code was correctly written as print("string") and even print(f"string")

But after some time of debugging I realized that my bash script was calling python like:

python file_name.py

which had the effect of calling my python script by default using python2.7 which gave the error. So I changed my bash script to:

python3 file_name.py

which of coarse uses python3 to run the script which fixed the error.


回答 7

除了这里的直接答案外,还应注意python 2和3之间的另一个主要区别。官方python Wiki涵盖了几乎所有主要区别,并着重于何时应使用这两个版本。这篇博客文章也很好地解释了当前的python宇宙以及迁移到python 3时仍未解决的难题。

据我所知,您正在开始学习python语言。在继续进行python 3路由之前,您应该考虑上述文章。您不仅需要更改某些语法,还需要考虑哪些包对您可用(python 2的优点)以及可以在代码中进行的潜在优化(python 3的优点) 。

Outside of the direct answers here, one should note the other key difference between python 2 and 3. The official python wiki goes into almost all of the major differences and focuses on when you should use either of the versions. This blog post also does a fine job of explaining the current python universe and the somehow unsolved puzzle of moving to python 3.

As far as I can tell, you are beginning to learn the python language. You should consider the aforementioned articles before you continue down the python 3 route. Not only will you have to change some of your syntax, you will also need to think about which packages will be available to you (an advantage of python 2) and potential optimizations that could be made in your code (an advantage of python 3).


如何在Python中进行相对导入?

问题:如何在Python中进行相对导入?

想象一下这个目录结构:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

我正在编码mod1,我需要从中导入一些东西mod2。我该怎么办?

我尝试过,from ..sub2 import mod2但是得到了“未打包的相对导入尝试”。

我四处搜寻,但只发现“ sys.path操纵”骇客。有没有一种干净的方法?


编辑:我所有__init__.py的当前为空

EDIT2:我想这样做,因为SUB2包含了为子包(共享类sub1subX等等)。

Edit3:我要寻找的行为与PEP 366中描述的相同(感谢John B)

Imagine this directory structure:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

I’m coding mod1, and I need to import something from mod2. How should I do it?

I tried from ..sub2 import mod2 but I’m getting an “Attempted relative import in non-package”.

I googled around but found only “sys.path manipulation” hacks. Isn’t there a clean way?


Edit: all my __init__.py‘s are currently empty

Edit2: I’m trying to do this because sub2 contains classes that are shared across sub packages (sub1, subX, etc.).

Edit3: The behaviour I’m looking for is the same as described in PEP 366 (thanks John B)


回答 0

每个人似乎都想告诉您应该做什么,而不仅仅是回答问题。

问题是您通过将mod1.py作为参数传递给解释器,从而以“ __main__”的身份运行模块。

PEP 328

相对导入使用模块的__name__属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,将其设置为“ __main__”),则相对导入将被视为模块是顶级模块,而不论该模块实际位于文件系统上的哪个位置。

在Python 2.6中,他们添加了相对于主模块引用模块的功能。 PEP 366说明了更改。

更新:根据Nick Coghlan的建议,推荐的替代方法是使用-m开关运行软件包中的模块。

Everyone seems to want to tell you what you should be doing rather than just answering the question.

The problem is that you’re running the module as ‘__main__’ by passing the mod1.py as an argument to the interpreter.

From PEP 328:

Relative imports use a module’s __name__ attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to ‘__main__’) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

In Python 2.6, they’re adding the ability to reference modules relative to the main module. PEP 366 describes the change.

Update: According to Nick Coghlan, the recommended alternative is to run the module inside the package using the -m switch.


回答 1

这是对我有效的解决方案:

我执行as的相对导入 from ..sub2 import mod2 ,然后,如果要运行,mod1.py则转到的父目录,app并使用python -m开关as运行模块 python -m app.sub1.mod1

相对导入发生此问题的真正原因是,相对导入通过获取__name__模块的属性起作用。如果模块直接运行,则__name__设置为__main__,并且不包含有关包结构的任何信息。并且,这就是为什么python抱怨该relative import in non-package错误的原因。

因此,通过使用-m开关,您可以将包结构信息提供给python,通过它可以成功解析相对导入。

在进行相对导入时,我多次遇到此问题。而且,在阅读了所有先前的答案之后,我仍然无法弄清楚如何解决此问题,而无需在所有文件中添加样板代码。(尽管有些评论确实很有帮助,这要感谢@ncoghlan和@XiongChiamiov)

希望这对正在解决相对进口问题的人有所帮助,因为通过PEP确实很有趣。

Here is the solution which works for me:

I do the relative imports as from ..sub2 import mod2 and then, if I want to run mod1.py then I go to the parent directory of app and run the module using the python -m switch as python -m app.sub1.mod1.

The real reason why this problem occurs with relative imports, is that relative imports works by taking the __name__ property of the module. If the module is being directly run, then __name__ is set to __main__ and it doesn’t contain any information about package structure. And, thats why python complains about the relative import in non-package error.

So, by using the -m switch you provide the package structure information to python, through which it can resolve the relative imports successfully.

I have encountered this problem many times while doing relative imports. And, after reading all the previous answers, I was still not able to figure out how to solve it, in a clean way, without needing to put boilerplate code in all files. (Though some of the comments were really helpful, thanks to @ncoghlan and @XiongChiamiov)

Hope this helps someone who is fighting with relative imports problem, because going through PEP is really not fun.


回答 2

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. 你跑python main.py
  2. main.py 确实: import app.package_a.module_a
  3. module_a.py 确实 import app.package_b.module_b

另外2或3可以使用: from app.package_a import module_a

只要您app在PYTHONPATH中具有此功能,便可以使用。main.py可能在那时的任何地方。

因此,您编写了一个setup.py将整个应用程序包和子包复制(安装)到目标系统的python文件夹以及main.py目标系统的脚本文件夹的代码。

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. You run python main.py.
  2. main.py does: import app.package_a.module_a
  3. module_a.py does import app.package_b.module_b

Alternatively 2 or 3 could use: from app.package_a import module_a

That will work as long as you have app in your PYTHONPATH. main.py could be anywhere then.

So you write a setup.py to copy (install) the whole app package and subpackages to the target system’s python folders, and main.py to target system’s script folders.


回答 3

“ Guido将程序包中正在运行的脚本视为反模式”(被拒绝的 PEP-3122

我花了很多时间试图找到解决方案,在Stack Overflow上阅读了相关文章,并对自己说:“一定有更好的方法!”。好像没有。

“Guido views running scripts within a package as an anti-pattern” (rejected PEP-3122)

I have spent so much time trying to find a solution, reading related posts here on Stack Overflow and saying to myself “there must be a better way!”. Looks like there is not.


回答 4

这可以100%解决:

  • 应用/
    • main.py
  • 设置/
    • local_setings.py

在app / main.py中导入settings / local_setting.py:

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')

This is solved 100%:

  • app/
    • main.py
  • settings/
    • local_setings.py

Import settings/local_setting.py in app/main.py:

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')

回答 5

def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

我正在使用此代码片段从路径导入模块,希望对您有所帮助

def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

I’m using this snippet to import modules from paths, hope that helps


回答 6

nosklo's举例说明答案

注意:所有__init__.py文件均为空。

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app / package_a / fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app / package_b / fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

如果运行,$ python main.py它将返回:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py可以: from app.package_b import fun_b
  • fun_b.py确实 from app.package_a.fun_a import print_a

所以文件夹中的文件package_b使用了文件夹中的文件package_a,这就是您想要的。对??

explanation of nosklo's answer with examples

note: all __init__.py files are empty.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app/package_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app/package_b/fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

if you run $ python main.py it returns:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py does: from app.package_b import fun_b
  • fun_b.py does from app.package_a.fun_a import print_a

so file in folder package_b used file in folder package_a, which is what you want. Right??


回答 7

不幸的是,这是一个sys.path hack,但是效果很好。

我在另一层遇到了这个问题:我已经有一个具有指定名称的模块,但这是错误的模块。

我想要做的是以下操作(我正在使用的模块是module3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

请注意,我已经安装了mymodule,但是在我的安装中我没有“ mymodule1”

而且我会收到一个ImportError,因为它试图从安装的模块中导入。

我试图做一个sys.path.append,但是没有用。起作用的是sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

有点骇客,但一切正常!因此请记住,如果要决定覆盖其他路径,则需要使用sys.path.insert(0,pathname)使其起作用!这对我来说是一个非常令人沮丧的症结所在,有人说要在sys.path中使用“ append”功能,但是如果您已经定义了一个模块,那是行不通的(我发现这是非常奇怪的行为)

This is unfortunately a sys.path hack, but it works quite well.

I encountered this problem with another layer: I already had a module of the specified name, but it was the wrong module.

what I wanted to do was the following (the module I was working from was module3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

Note that I have already installed mymodule, but in my installation I do not have “mymodule1”

and I would get an ImportError because it was trying to import from my installed modules.

I tried to do a sys.path.append, and that didn’t work. What did work was a sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

So kind of a hack, but got it all to work! So keep in mind, if you want your decision to override other paths then you need to use sys.path.insert(0, pathname) to get it to work! This was a very frustrating sticking point for me, allot of people say to use the “append” function to sys.path, but that doesn’t work if you already have a module defined (I find it very strange behavior)


回答 8

让我将其放在此处以供我自己参考。我知道这不是很好的Python代码,但是我需要一个脚本来处理我正在处理的项目,所以我想将脚本放在scripts目录中。

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

Let me just put this here for my own reference. I know that it is not good Python code, but I needed a script for a project I was working on and I wanted to put the script in a scripts directory.

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

回答 9

正如@EvgeniSergeev在对OP的注释中所说,您可以使用以下.py命令从任意位置的文件导入代码:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

这是从此SO答案中获取的

As @EvgeniSergeev says in the comments to the OP, you can import code from a .py file at an arbitrary location with:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

This is taken from this SO answer.


回答 10


回答 11

Python文档中

在Python 2.5中,您可以使用from __future__ import absolute_import指令将导入的行为切换为绝对导入。在将来的版本(可能是Python 2.7)中,此绝对导入行为将成为默认设置。一旦将绝对导入设置为默认设置,import string就将始终找到标准库的版本。建议用户应尽可能多地开始使用绝对导入,因此最好开始编写from pkg import string代码

From Python doc,

In Python 2.5, you can switch import‘s behaviour to absolute imports using a from __future__ import absolute_import directive. This absolute- import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default, import string will always find the standard library’s version. It’s suggested that users should begin using absolute imports as much as possible, so it’s preferable to begin writing from pkg import string in your code


回答 12

我发现将“ PYTHONPATH”环境变量设置为顶层文件夹更容易:

bash$ export PYTHONPATH=/PATH/TO/APP

然后:

import sub1.func1
#...more import

当然,PYTHONPATH是“全局”的,但它并没有给我带来麻烦。

I found it’s more easy to set “PYTHONPATH” enviroment variable to the top folder:

bash$ export PYTHONPATH=/PATH/TO/APP

then:

import sub1.func1
#...more import

of course, PYTHONPATH is “global”, but it didn’t raise trouble for me yet.


回答 13

除了John B所说的,似乎设置__package__变量应该有帮助,而不是更改变量__main__可能会搞砸其他事情。但是据我测试,它并不能完全正常工作。

我遇到了同样的问题sys.path,而据我所知,PEP 328或366都无法完全解决问题,因为两者在一天结束时都需要将包装的标头包括在其中。

我还要提及的是,我没有找到如何格式化应该放入这些变量的字符串的格式。是"package_head.subfolder.module_name"还是什么?

On top of what John B said, it seems like setting the __package__ variable should help, instead of changing __main__ which could screw up other things. But as far as I could test, it doesn’t completely work as it should.

I have the same problem and neither PEP 328 or 366 solve the problem completely, as both, by the end of the day, need the head of the package to be included in sys.path, as far as I could understand.

I should also mention that I did not find how to format the string that should go into those variables. Is it "package_head.subfolder.module_name" or what?


回答 14

您必须将模块的路径附加到PYTHONPATH

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

You have to append the module’s path to PYTHONPATH:

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

re.search和re.match有什么区别?

问题:re.search和re.match有什么区别?

search()Python 模块中的match()函数和有什么区别?re

我已经阅读了文档当前文档),但是我似乎从未记得它。我一直在查找并重新学习它。我希望有人会用示例清楚地回答它,以便(也许)它会贴在我的头上。或者至少我将有一个更好的地方来回答我的问题,并且重新学习它所花的时间会更少。

What is the difference between the search() and match() functions in the Python re module?

I’ve read the documentation (current documentation), but I never seem to remember it. I keep having to look it up and re-learn it. I’m hoping that someone will answer it clearly with examples so that (perhaps) it will stick in my head. Or at least I’ll have a better place to return with my question and it will take less time to re-learn it.


回答 0

re.match锚定在字符串的开头。这与换行无关,因此它与^在模式中使用的方式不同。

重新匹配文档所述

如果字符串开头的零个或多个字符 与正则表达式模式匹配,则返回相应的MatchObject实例。None如果字符串与模式不匹配,则返回;否则返回false。请注意,这与零长度匹配不同。

注意:如果要在字符串中的任何位置找到匹配项,请search() 改用。

re.search搜索整个字符串,如文档所述

扫描字符串以查找正则表达式模式产生匹配项的位置,然后返回相应的MatchObject实例。None如果字符串中没有位置与模式匹配,则返回;否则返回false。请注意,这与在字符串中的某个点找到零长度匹配不同。

因此,如果您需要匹配字符串的开头,或者匹配整个字符串,请使用match。它更快。否则使用search

该文档中有一个专门针对matchvs.的部分search,还涵盖了多行字符串:

基于正则表达式的Python提供两种不同的基本操作:match检查是否有比赛 才刚刚开始的字符串,同时search检查是否有匹配 的任何地方的字符串(这是Perl并默认情况下)。

请注意, 即使使用以:开头的正则表达式match也可能仅在字符串的开头,或者在模式下也紧接换行符之后才匹配 。仅当模式在字符串开头 无论模式如何)或在可选 参数给定的起始位置匹配(无论换行符是否在其前面)时,“ ”操作才会成功。search'^''^'MULTILINEmatchpos

现在,足够的讨论。现在来看一些示例代码:

# example code:
string_with_newlines = """something
someotherthing"""

import re

print re.match('some', string_with_newlines) # matches
print re.match('someother', 
               string_with_newlines) # won't match
print re.match('^someother', string_with_newlines, 
               re.MULTILINE) # also won't match
print re.search('someother', 
                string_with_newlines) # finds something
print re.search('^someother', string_with_newlines, 
                re.MULTILINE) # also finds something

m = re.compile('thing$', re.MULTILINE)

print m.match(string_with_newlines) # no match
print m.match(string_with_newlines, pos=4) # matches
print m.search(string_with_newlines, 
               re.MULTILINE) # also matches

re.match is anchored at the beginning of the string. That has nothing to do with newlines, so it is not the same as using ^ in the pattern.

As the re.match documentation says:

If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding MatchObject instance. Return None if the string does not match the pattern; note that this is different from a zero-length match.

Note: If you want to locate a match anywhere in string, use search() instead.

re.search searches the entire string, as the documentation says:

Scan through string looking for a location where the regular expression pattern produces a match, and return a corresponding MatchObject instance. Return None if no position in the string matches the pattern; note that this is different from finding a zero-length match at some point in the string.

So if you need to match at the beginning of the string, or to match the entire string use match. It is faster. Otherwise use search.

The documentation has a specific section for match vs. search that also covers multiline strings:

Python offers two different primitive operations based on regular expressions: match checks for a match only at the beginning of the string, while search checks for a match anywhere in the string (this is what Perl does by default).

Note that match may differ from search even when using a regular expression beginning with '^': '^' matches only at the start of the string, or in MULTILINE mode also immediately following a newline. The “match” operation succeeds only if the pattern matches at the start of the string regardless of mode, or at the starting position given by the optional pos argument regardless of whether a newline precedes it.

Now, enough talk. Time to see some example code:

# example code:
string_with_newlines = """something
someotherthing"""

import re

print re.match('some', string_with_newlines) # matches
print re.match('someother', 
               string_with_newlines) # won't match
print re.match('^someother', string_with_newlines, 
               re.MULTILINE) # also won't match
print re.search('someother', 
                string_with_newlines) # finds something
print re.search('^someother', string_with_newlines, 
                re.MULTILINE) # also finds something

m = re.compile('thing$', re.MULTILINE)

print m.match(string_with_newlines) # no match
print m.match(string_with_newlines, pos=4) # matches
print m.search(string_with_newlines, 
               re.MULTILINE) # also matches

回答 1

search ⇒在字符串中的任何地方找到东西,然后返回一个匹配对象。

match⇒ 在字符串的开头找到一些内容,然后返回匹配对象。

search ⇒ find something anywhere in the string and return a match object.

match ⇒ find something at the beginning of the string and return a match object.


回答 2

re.search 搜索 ES该模式在整个字符串,而re.match没有搜索不到的格局; 如果没有,则除了在字符串开头匹配外,别无选择。

re.search searches for the pattern throughout the string, whereas re.match does not search the pattern; if it does not, it has no other choice than to match it at start of the string.


回答 3

match比搜索快得多,因此如果不使用regex.search(“ word”),则可以执行regex.match((。*?)word(。*?)),如果您使用数百万个样品。

@ivan_bilan在上面接受的答案下的评论让我开始思考是否有这样的hack是否真的在加速任何事情,所以让我们找出您将真正获得多少性能。

我准备了以下测试套件:

import random
import re
import string
import time

LENGTH = 10
LIST_SIZE = 1000000

def generate_word():
    word = [random.choice(string.ascii_lowercase) for _ in range(LENGTH)]
    word = ''.join(word)
    return word

wordlist = [generate_word() for _ in range(LIST_SIZE)]

start = time.time()
[re.search('python', word) for word in wordlist]
print('search:', time.time() - start)

start = time.time()
[re.match('(.*?)python(.*?)', word) for word in wordlist]
print('match:', time.time() - start)

我进行了10次测量(1M,2M,…,10M个单词),得出以下图表:

匹配与搜索正则表达式速度测试线图

产生的直线令人惊讶地(实际上并不那么令人惊讶)直线。鉴于这种特定的模式组合,该search功能(略)更快。该测试的实质是避免过度优化代码。

match is much faster than search, so instead of doing regex.search(“word”) you can do regex.match((.*?)word(.*?)) and gain tons of performance if you are working with millions of samples.

This comment from @ivan_bilan under the accepted answer above got me thinking if such hack is actually speeding anything up, so let’s find out how many tons of performance you will really gain.

I prepared the following test suite:

import random
import re
import string
import time

LENGTH = 10
LIST_SIZE = 1000000

def generate_word():
    word = [random.choice(string.ascii_lowercase) for _ in range(LENGTH)]
    word = ''.join(word)
    return word

wordlist = [generate_word() for _ in range(LIST_SIZE)]

start = time.time()
[re.search('python', word) for word in wordlist]
print('search:', time.time() - start)

start = time.time()
[re.match('(.*?)python(.*?)', word) for word in wordlist]
print('match:', time.time() - start)

I made 10 measurements (1M, 2M, …, 10M words) which gave me the following plot:

match vs. search regex speedtest line plot

The resulting lines are surprisingly (actually not that surprisingly) straight. And the search function is (slightly) faster given this specific pattern combination. The moral of this test: Avoid overoptimizing your code.


回答 4

您可以参考以下示例以了解re.matchand.search 的工作原理

a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)

re.match会回来none,但是re.search会回来abc

You can refer the below example to understand the working of re.match and re.search

a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)

re.match will return none, but re.search will return abc.


回答 5

区别在于,re.match()误导习惯于Perlgrepsed正则表达式匹配的任何人,并且re.search()不会。:-)

正如约翰·D·库克(John D. Cook)所说,要更加清醒一些,re.match()“表现得好像每个模式都以^开头。” 换句话说,re.match('pattern')等于re.search('^pattern')。因此,它锚定了图案的左侧。但这也没有固定模式的右侧:仍然需要终止$

坦白地说,我认为re.match()应该弃用。我很想知道应该保留它的原因。

The difference is, re.match() misleads anyone accustomed to Perl, grep, or sed regular expression matching, and re.search() does not. :-)

More soberly, As John D. Cook remarks, re.match() “behaves as if every pattern has ^ prepended.” In other words, re.match('pattern') equals re.search('^pattern'). So it anchors a pattern’s left side. But it also doesn’t anchor a pattern’s right side: that still requires a terminating $.

Frankly given the above, I think re.match() should be deprecated. I would be interested to know reasons it should be retained.


回答 6

re.match尝试匹配字符串开头的模式。re.search尝试在整个字符串中匹配模式直到找到匹配项。

re.match attempts to match a pattern at the beginning of the string. re.search attempts to match the pattern throughout the string until it finds a match.


回答 7

矮得多:

  • search 扫描整个字符串。

  • match 仅扫描字符串的开头。

以下Ex表示:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc

Much shorter:

  • search scans through the whole string.

  • match scans only the beginning of the string.

Following Ex says it:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc

您如何从字符串列表中创建逗号分隔的字符串?

问题:您如何从字符串列表中创建逗号分隔的字符串?

您最好采用哪种方法来连接序列中的字符串,以便在每两个连续对之间添加一个逗号。也就是说,例如,您如何映射['a', 'b', 'c']'a,b,c'?(案例['s'][]应该分别映射到's'''。)

我通常最终会使用类似的东西''.join(map(lambda x: x+',',l))[:-1],但也会感到有些不满意。

What would be your preferred way to concatenate strings from a sequence such that between every two consecutive pairs a comma is added. That is, how do you map, for instance, ['a', 'b', 'c'] to 'a,b,c'? (The cases ['s'] and [] should be mapped to 's' and '', respectively.)

I usually end up using something like ''.join(map(lambda x: x+',',l))[:-1], but also feeling somewhat unsatisfied.


回答 0

my_list = ['a', 'b', 'c', 'd']
my_string = ','.join(my_list)
'a,b,c,d'

如果列表包含整数,则此方法无效


并且如果列表包含非字符串类型(例如整数,浮点数,布尔值,无),则请执行以下操作:

my_string = ','.join(map(str, my_list)) 
my_list = ['a', 'b', 'c', 'd']
my_string = ','.join(my_list)
'a,b,c,d'

This won’t work if the list contains integers


And if the list contains non-string types (such as integers, floats, bools, None) then do:

my_string = ','.join(map(str, my_list)) 

回答 1

为什么map/ lambda魔术?这不行吗?

>>> foo = ['a', 'b', 'c']
>>> print(','.join(foo))
a,b,c
>>> print(','.join([]))

>>> print(','.join(['a']))
a

如果列表中有数字,则可以使用列表理解:

>>> ','.join([str(x) for x in foo])

或生成器表达式:

>>> ','.join(str(x) for x in foo)

Why the map/lambda magic? Doesn’t this work?

>>> foo = ['a', 'b', 'c']
>>> print(','.join(foo))
a,b,c
>>> print(','.join([]))

>>> print(','.join(['a']))
a

In case if there are numbers in the list, you could use list comprehension:

>>> ','.join([str(x) for x in foo])

or a generator expression:

>>> ','.join(str(x) for x in foo)

回答 2

",".join(l)不适用于所有情况。我建议将CSV模块与StringIO一起使用

import StringIO
import csv

l = ['list','of','["""crazy"quotes"and\'',123,'other things']

line = StringIO.StringIO()
writer = csv.writer(line)
writer.writerow(l)
csvcontent = line.getvalue()
# 'list,of,"[""""""crazy""quotes""and\'",123,other things\r\n'

",".join(l) will not work for all cases. I’d suggest using the csv module with StringIO

import StringIO
import csv

l = ['list','of','["""crazy"quotes"and\'',123,'other things']

line = StringIO.StringIO()
writer = csv.writer(line)
writer.writerow(l)
csvcontent = line.getvalue()
# 'list,of,"[""""""crazy""quotes""and\'",123,other things\r\n'

回答 3

这是Python 3.0中允许非字符串列表项的替代解决方案:

>>> alist = ['a', 1, (2, 'b')]
  • 标准方式

    >>> ", ".join(map(str, alist))
    "a, 1, (2, 'b')"
  • 替代解决方案

    >>> import io
    >>> s = io.StringIO()
    >>> print(*alist, file=s, sep=', ', end='')
    >>> s.getvalue()
    "a, 1, (2, 'b')"

注意:逗号后的空格是故意的。

Here is a alternative solution in Python 3.0 which allows non-string list items:

>>> alist = ['a', 1, (2, 'b')]
  • a standard way

    >>> ", ".join(map(str, alist))
    "a, 1, (2, 'b')"
    
  • the alternative solution

    >>> import io
    >>> s = io.StringIO()
    >>> print(*alist, file=s, sep=', ', end='')
    >>> s.getvalue()
    "a, 1, (2, 'b')"
    

NOTE: The space after comma is intentional.


回答 4

你不只是想要:

",".join(l)

显然,如果您需要在值中引用/转义逗号等,它将变得更加复杂。在这种情况下,我建议您查看标准库中的csv模块:

https://docs.python.org/library/csv.html

Don’t you just want:

",".join(l)

Obviously it gets more complicated if you need to quote/escape commas etc in the values. In that case I would suggest looking at the csv module in the standard library:

https://docs.python.org/library/csv.html


回答 5

彼得·霍夫曼(Peter Hoffmann)

使用生成器表达式的好处是还可以生成迭代器,但可以节省导入itertools的时间。此外,列表推导通常首选映射,因此,我希望生成器表达式比imap首选。

>>> l = [1, "foo", 4 ,"bar"]
>>> ",".join(str(bit) for bit in l)
'1,foo,4,bar' 

@Peter Hoffmann

Using generator expressions has the benefit of also producing an iterator but saves importing itertools. Furthermore, list comprehensions are generally preferred to map, thus, I’d expect generator expressions to be preferred to imap.

>>> l = [1, "foo", 4 ,"bar"]
>>> ",".join(str(bit) for bit in l)
'1,foo,4,bar' 

回答 6

>>> my_list = ['A', '', '', 'D', 'E',]
>>> ",".join([str(i) for i in my_list if i])
'A,D,E'

my_list可以包含任何类型的变量。这样可以避免结果'A,,,D,E'

>>> my_list = ['A', '', '', 'D', 'E',]
>>> ",".join([str(i) for i in my_list if i])
'A,D,E'

my_list may contain any type of variables. This avoid the result 'A,,,D,E'.


回答 7

l=['a', 1, 'b', 2]

print str(l)[1:-1]

Output: "'a', 1, 'b', 2"
l=['a', 1, 'b', 2]

print str(l)[1:-1]

Output: "'a', 1, 'b', 2"

回答 8

使用列表推导的@ jmanning2k不利于创建新的临时列表。更好的解决方案是使用itertools.imap返回一个迭代器

from itertools import imap
l = [1, "foo", 4 ,"bar"]
",".join(imap(str, l))

@jmanning2k using a list comprehension has the downside of creating a new temporary list. The better solution would be using itertools.imap which returns an iterator

from itertools import imap
l = [1, "foo", 4 ,"bar"]
",".join(imap(str, l))

回答 9

这是清单的例子

>>> myList = [['Apple'],['Orange']]
>>> myList = ','.join(map(str, [i[0] for i in myList])) 
>>> print "Output:", myList
Output: Apple,Orange

更准确的:-

>>> myList = [['Apple'],['Orange']]
>>> myList = ','.join(map(str, [type(i) == list and i[0] for i in myList])) 
>>> print "Output:", myList
Output: Apple,Orange

示例2:

myList = ['Apple','Orange']
myList = ','.join(map(str, myList)) 
print "Output:", myList
Output: Apple,Orange

Here is an example with list

>>> myList = [['Apple'],['Orange']]
>>> myList = ','.join(map(str, [i[0] for i in myList])) 
>>> print "Output:", myList
Output: Apple,Orange

More Accurate:-

>>> myList = [['Apple'],['Orange']]
>>> myList = ','.join(map(str, [type(i) == list and i[0] for i in myList])) 
>>> print "Output:", myList
Output: Apple,Orange

Example 2:-

myList = ['Apple','Orange']
myList = ','.join(map(str, myList)) 
print "Output:", myList
Output: Apple,Orange

回答 10

我要说的csv是,库是这里唯一明智的选择,因为它是为应对所有csv用例(例如字符串中的逗号)而构建的。

要将列表输出l到.csv文件,请执行以下操作:

import csv
with open('some.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(l)  # this will output l as a single row.  

也可以用于writer.writerows(iterable)将多行输出到csv。

此示例与Python 3兼容,此处使用的另一个答案StringIO是Python 2。

I would say the csv library is the only sensible option here, as it was built to cope with all csv use cases such as commas in a string, etc.

To output a list l to a .csv file:

import csv
with open('some.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(l)  # this will output l as a single row.  

It is also possible to use writer.writerows(iterable) to output multiple rows to csv.

This example is compatible with Python 3, as the other answer here used StringIO which is Python 2.


回答 11

除非我缺少任何东西,否则','.join(foo)应该做您所要的。

>>> ','.join([''])
''
>>> ','.join(['s'])
's'
>>> ','.join(['a','b','c'])
'a,b,c'

(编辑:正如jmanning2k指出的那样,

','.join([str(x) for x in foo])

是更安全且相当Pythonic的,尽管如果元素可以包含逗号,则生成的字符串将很难解析-那时,您需要csv模块的全部功能,正如Douglas在他的回答中指出的那样。)

Unless I’m missing something, ','.join(foo) should do what you’re asking for.

>>> ','.join([''])
''
>>> ','.join(['s'])
's'
>>> ','.join(['a','b','c'])
'a,b,c'

(edit: and as jmanning2k points out,

','.join([str(x) for x in foo])

is safer and quite Pythonic, though the resulting string will be difficult to parse if the elements can contain commas — at that point, you need the full power of the csv module, as Douglas points out in his answer.)


回答 12

我的两分钱。我喜欢更简单的python单行代码:

>>> from itertools import imap, ifilter
>>> l = ['a', '', 'b', 1, None]
>>> ','.join(imap(str, ifilter(lambda x: x, l)))
a,b,1
>>> m = ['a', '', None]
>>> ','.join(imap(str, ifilter(lambda x: x, m)))
'a'

这是pythonic,适用于字符串,数字,无和空字符串。它很短并且满足要求。如果列表中不包含数字,则可以使用以下更简单的变体:

>>> ','.join(ifilter(lambda x: x, l))

同样,该解决方案不会创建新列表,而是使用迭代器,如@Peter Hoffmann指出的(谢谢)。

My two cents. I like simpler an one-line code in python:

>>> from itertools import imap, ifilter
>>> l = ['a', '', 'b', 1, None]
>>> ','.join(imap(str, ifilter(lambda x: x, l)))
a,b,1
>>> m = ['a', '', None]
>>> ','.join(imap(str, ifilter(lambda x: x, m)))
'a'

It’s pythonic, works for strings, numbers, None and empty string. It’s short and satisfies the requirements. If the list is not going to contain numbers, we can use this simpler variation:

>>> ','.join(ifilter(lambda x: x, l))

Also this solution doesn’t create a new list, but uses an iterator, like @Peter Hoffmann pointed (thanks).


如何获得字符在Python中的位置?

问题:如何获得字符在Python中的位置?

如何在python中的字符串中获取字符的位置?

How can I get the position of a character inside a string in python?


回答 0

这有两个String的方法,find()index()。两者之间的区别在于找不到搜索字符串时会发生什么。 find()回报-1index()加薪ValueError

使用 find()

>>> myString = 'Position of a character'
>>> myString.find('s')
2
>>> myString.find('x')
-1

使用 index()

>>> myString = 'Position of a character'
>>> myString.index('s')
2
>>> myString.index('x')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found

Python手册

string.find(s, sub[, start[, end]])
返回s中找到子字符串sub的最低索引,使sub完全包含在中s[start:end]-1失败返回。开始结束以及负值的解释默认值与切片相同。

和:

string.index(s, sub[, start[, end]])
喜欢,find()但是ValueError在找不到子字符串时提高。

There are two string methods for this, find() and index(). The difference between the two is what happens when the search string isn’t found. find() returns -1 and index() raises ValueError.

Using find()

>>> myString = 'Position of a character'
>>> myString.find('s')
2
>>> myString.find('x')
-1

Using index()

>>> myString = 'Position of a character'
>>> myString.index('s')
2
>>> myString.index('x')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found

From the Python manual

string.find(s, sub[, start[, end]])
Return the lowest index in s where the substring sub is found such that sub is wholly contained in s[start:end]. Return -1 on failure. Defaults for start and end and interpretation of negative values is the same as for slices.

And:

string.index(s, sub[, start[, end]])
Like find() but raise ValueError when the substring is not found.


回答 1

仅出于完整性考虑,如果需要查找字符串中字符的所有位置,可以执行以下操作:

s = 'shak#spea#e'
c = '#'
print [pos for pos, char in enumerate(s) if char == c]

它将返回 [4, 9]

Just for a sake of completeness, if you need to find all positions of a character in a string, you can do the following:

s = 'shak#spea#e'
c = '#'
print [pos for pos, char in enumerate(s) if char == c]

which will return [4, 9]


回答 2

>>> s="mystring"
>>> s.index("r")
4
>>> s.find("r")
4

“长ed”方式

>>> for i,c in enumerate(s):
...   if "r"==c: print i
...
4

得到子串,

>>> s="mystring"
>>> s[4:10]
'ring'
>>> s="mystring"
>>> s.index("r")
4
>>> s.find("r")
4

“Long winded” way

>>> for i,c in enumerate(s):
...   if "r"==c: print i
...
4

to get substring,

>>> s="mystring"
>>> s[4:10]
'ring'

回答 3

只是为了完成,如果要在文件名中找到扩展名以进行检查,则需要找到最后一个“。”,在这种情况下,请使用rfind:

path = 'toto.titi.tata..xls'
path.find('.')
4
path.rfind('.')
15

就我而言,我使用以下命令,无论完整的文件名是什么,它都可以工作:

filename_without_extension = complete_name[:complete_name.rfind('.')]

Just for completion, in the case I want to find the extension in a file name in order to check it, I need to find the last ‘.’, in this case use rfind:

path = 'toto.titi.tata..xls'
path.find('.')
4
path.rfind('.')
15

in my case, I use the following, which works whatever the complete file name is:

filename_without_extension = complete_name[:complete_name.rfind('.')]

回答 4

当字符串包含重复字符时会发生什么?从我的经验中,index()我看到重复的结果会返回相同的索引。

例如:

s = 'abccde'
for c in s:
    print('%s, %d' % (c, s.index(c)))

会返回:

a, 0
b, 1
c, 2
c, 2
d, 4

在这种情况下,您可以执行以下操作:

for i, character in enumerate(my_string):
   # i is the position of the character in the string

What happens when the string contains a duplicate character? from my experience with index() I saw that for duplicate you get back the same index.

For example:

s = 'abccde'
for c in s:
    print('%s, %d' % (c, s.index(c)))

would return:

a, 0
b, 1
c, 2
c, 2
d, 4

In that case you can do something like that:

for i, character in enumerate(my_string):
   # i is the position of the character in the string

回答 5

string.find(character)  
string.index(character)  

也许您想看一下文档,找出两者之间的区别。

string.find(character)  
string.index(character)  

Perhaps you’d like to have a look at the documentation to find out what the difference between the two is.


回答 6

一个字符可能在字符串中多次出现。例如,在字符串中sentence,位置eis是1, 4, 7(因为索引通常从零开始)。但是我发现这是两个函数,find()并且index()返回字符的第一个位置。因此,这样做可以解决此问题:

def charposition(string, char):
    pos = [] #list to store positions for each 'char' in 'string'
    for n in range(len(string)):
        if string[n] == char:
            pos.append(n)
    return pos

s = "sentence"
print(charposition(s, 'e')) 

#Output: [1, 4, 7]

A character might appear multiple times in a string. For example in a string sentence, position of e is 1, 4, 7 (because indexing usually starts from zero). but what I find is both of the functions find() and index() returns first position of a character. So, this can be solved doing this:

def charposition(string, char):
    pos = [] #list to store positions for each 'char' in 'string'
    for n in range(len(string)):
        if string[n] == char:
            pos.append(n)
    return pos

s = "sentence"
print(charposition(s, 'e')) 

#Output: [1, 4, 7]

回答 7

more_itertools.locate 是一种第三方工具,用于查找满足条件的所有项目的索引。

在这里,我们找到字母的所有索引位置"i"

import more_itertools as mit


s = "supercalifragilisticexpialidocious"
list(mit.locate(s, lambda x: x == "i"))
# [8, 13, 15, 18, 23, 26, 30]

more_itertools.locate is a third-party tool that finds all indicies of items that satisfy a condition.

Here we find all index locations of the letter "i".

import more_itertools as mit


s = "supercalifragilisticexpialidocious"
list(mit.locate(s, lambda x: x == "i"))
# [8, 13, 15, 18, 23, 26, 30]

回答 8

使用numpy的解决方案可以快速访问所有索引:

string_array = np.array(list(my_string))
char_indexes = np.where(string_array == 'C')

A solution with numpy for quick access to all indexes:

string_array = np.array(list(my_string))
char_indexes = np.where(string_array == 'C')

用户输入和命令行参数

问题:用户输入和命令行参数

我如何拥有a)可以接受用户输入的Python脚本,以及如何使b)从命令行运行时读取参数?

How do I have a Python script that a) can accept user input and how do I make it b) read in arguments if run from the command line?


回答 0

要读取用户输入,您可以尝试使用cmd模块轻松创建一个迷你命令行解释器(带有帮助文本和自动完成功能),以及raw_inputinput用于Python 3+)从用户读取一行文本的模块。

text = raw_input("prompt")  # Python 2
text = input("prompt")  # Python 3

命令行输入在中sys.argv。在脚本中尝试:

import sys
print (sys.argv)

有两个用于解析命令行选项的模块:(optparse自Python 2.7起不推荐使用,argparse而是使用)和getopt。如果只想向脚本输入文件,请注意的功能fileinput

Python库参考是你的朋友。

To read user input you can try the cmd module for easily creating a mini-command line interpreter (with help texts and autocompletion) and raw_input (input for Python 3+) for reading a line of text from the user.

text = raw_input("prompt")  # Python 2
text = input("prompt")  # Python 3

Command line inputs are in sys.argv. Try this in your script:

import sys
print (sys.argv)

There are two modules for parsing command line options: optparse (deprecated since Python 2.7, use argparse instead) and getopt. If you just want to input files to your script, behold the power of fileinput.

The Python library reference is your friend.


回答 1

var = raw_input("Please enter something: ")
print "you entered", var

或对于Python 3:

var = input("Please enter something: ")
print("You entered: " + var)
var = raw_input("Please enter something: ")
print "you entered", var

Or for Python 3:

var = input("Please enter something: ")
print("You entered: " + var)

回答 2

raw_input在Python 3.x中不再可用。但是raw_input已被重命名input,因此存在相同的功能。

input_var = input("Enter something: ")
print ("you entered " + input_var) 

变更文件

raw_input is no longer available in Python 3.x. But raw_input was renamed input, so the same functionality exists.

input_var = input("Enter something: ")
print ("you entered " + input_var) 

Documentation of the change


回答 3

处理命令行参数的最佳方法是argparse模块。

使用raw_input()来获取用户输入。如果导入,readline module您的用户将具有行编辑和历史记录。

The best way to process command line arguments is the argparse module.

Use raw_input() to get user input. If you import the readline module your users will have line editing and history.


回答 4

input除非您知道自己在做什么,否则请小心不要使用该功能。与不同raw_inputinput它将接受任何python表达式,因此有点像eval

Careful not to use the input function, unless you know what you’re doing. Unlike raw_input, input will accept any python expression, so it’s kinda like eval


回答 5

这个简单的程序可以帮助您了解如何从命令行输入用户输入以及如何显示有关传递无效参数的帮助。

import argparse
import sys

try:
     parser = argparse.ArgumentParser()
     parser.add_argument("square", help="display a square of a given number",
                type=int)
    args = parser.parse_args()

    #print the square of user input from cmd line.
    print args.square**2

    #print all the sys argument passed from cmd line including the program name.
    print sys.argv

    #print the second argument passed from cmd line; Note it starts from ZERO
    print sys.argv[1]
except:
    e = sys.exc_info()[0]
    print e

1)求5的平方根

C:\Users\Desktop>python -i emp.py 5
25
['emp.py', '5']
5

2)传递数字以外的无效参数

C:\Users\bgh37516\Desktop>python -i emp.py five
usage: emp.py [-h] square
emp.py: error: argument square: invalid int value: 'five'
<type 'exceptions.SystemExit'>

This simple program helps you in understanding how to feed the user input from command line and to show help on passing invalid argument.

import argparse
import sys

try:
     parser = argparse.ArgumentParser()
     parser.add_argument("square", help="display a square of a given number",
                type=int)
    args = parser.parse_args()

    #print the square of user input from cmd line.
    print args.square**2

    #print all the sys argument passed from cmd line including the program name.
    print sys.argv

    #print the second argument passed from cmd line; Note it starts from ZERO
    print sys.argv[1]
except:
    e = sys.exc_info()[0]
    print e

1) To find the square root of 5

C:\Users\Desktop>python -i emp.py 5
25
['emp.py', '5']
5

2) Passing invalid argument other than number

C:\Users\bgh37516\Desktop>python -i emp.py five
usage: emp.py [-h] square
emp.py: error: argument square: invalid int value: 'five'
<type 'exceptions.SystemExit'>

回答 6

使用“ raw_input”从控制台/终端输入。

如果您只想使用命令行参数,例如文件名或其他名称,例如

$ python my_prog.py file_name.txt

那么你可以使用sys.argv …

import sys
print sys.argv

sys.argv是一个列表,其中0是程序名称,因此在上面的示例中sys.argv [1]将是“ file_name.txt”

如果要使用命令行选项完整选项,请使用optparse模块。

佩夫

Use ‘raw_input’ for input from a console/terminal.

if you just want a command line argument like a file name or something e.g.

$ python my_prog.py file_name.txt

then you can use sys.argv…

import sys
print sys.argv

sys.argv is a list where 0 is the program name, so in the above example sys.argv[1] would be “file_name.txt”

If you want to have full on command line options use the optparse module.

Pev


回答 7

如果您运行的是Python <2.7,则需要optparse,如文档所述,它将创建一个接口,以连接在运行应用程序时调用的命令行参数。

但是,在python≥2.7中,不建议使用optparse,并如上所述将其替换为argparse。来自文档的快速示例…

以下代码是一个Python程序,它接收一个整数列表并产生总和或最大值:

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print args.accumulate(args.integers)

If you are running Python <2.7, you need optparse, which as the doc explains will create an interface to the command line arguments that are called when your application is run.

However, in Python ≥2.7, optparse has been deprecated, and was replaced with the argparse as shown above. A quick example from the docs…

The following code is a Python program that takes a list of integers and produces either the sum or the max:

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print args.accumulate(args.integers)

回答 8

从Python开始 3.22.7中,现在有用于处理命令行参数的argparse

As of Python 3.2 2.7, there is now argparse for processing command line arguments.


回答 9

如果是3.x版本,则只需使用:

variantname = input()

例如,您要输入8:

x = input()
8

x等于8,但是它将是一个字符串,除非您另行定义。

因此,您可以使用convert命令,例如:

a = int(x) * 1.1343
print(round(a, 2)) # '9.07'
9.07

If it’s a 3.x version then just simply use:

variantname = input()

For example, you want to input 8:

x = input()
8

x will equal 8 but it’s going to be a string except if you define it otherwise.

So you can use the convert command, like:

a = int(x) * 1.1343
print(round(a, 2)) # '9.07'
9.07

回答 10

在Python 2中:

data = raw_input('Enter something: ')
print data

在Python 3中:

data = input('Enter something: ')
print(data)

In Python 2:

data = raw_input('Enter something: ')
print data

In Python 3:

data = input('Enter something: ')
print(data)

回答 11

import six

if six.PY2:
    input = raw_input

print(input("What's your name? "))
import six

if six.PY2:
    input = raw_input

print(input("What's your name? "))

如何从虚拟环境内部更新点子本身?

问题:如何从虚拟环境内部更新点子本身?

我可以更新点子管理的软件包,但是如何更新点子本身?据介绍pip --version,我目前在virtualenv中安装了pip 1.1,我想更新到最新版本。

这是什么命令?我需要使用distribute还是本机pip或virtualenv命令?我已经尝试过pip update,并pip update pip没有成功。

I’m able to update pip-managed packages, but how do I update pip itself? According to pip --version, I currently have pip 1.1 installed in my virtualenv and I want to update to the latest version.

What’s the command for that? Do I need to use distribute or is there a native pip or virtualenv command? I’ve already tried pip update and pip update pip with no success.


回答 0

pip仅仅是一个的PyPI包像任何其他; 您可以像升级任何软件包一样使用它来升级自身:

pip install --upgrade pip

在Windows上,推荐的命令是:

python -m pip install --upgrade pip

pip is just a PyPI package like any other; you could use it to upgrade itself the same way you would upgrade any package:

pip install --upgrade pip

On Windows the recommended command is:

python -m pip install --upgrade pip

回答 1

更安全的方法是通过python模块运行pip

python -m pip install -U pip

在Windows上,尝试替换自身的二进制文件似乎存在问题,此方法可解决该限制。

The more safe method is to run pip though a python module:

python -m pip install -U pip

On windows there seem to be a problem with binaries that try to replace themselves, this method works around that limitation.


回答 2

就我而言,我的pip版本已损坏,因此更新本身无法进行。

固定:

(inside virtualenv):easy_install -U pip

In my case my pip version was broken so the update by itself would not work.

Fix:

(inside virtualenv):easy_install -U pip

回答 3

我在Debian Jessie下尝试了上面提到的所有这些解决方案。它们不起作用,因为它只需要由debian软件包管理器编译的最新版本1.5.6相当于6.0.x版本。某些使用pip作为前提条件的软件包将无法正常运行,例如spaCy(需要使用–no-cache-dir选项才能正常运行)。

因此,解决这些问题的实际最佳方法是运行从wget下载的get-pip.py,它是从网站或使用curl进行的,如下所示:

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

这将安装当前版本,在编写此解决方案时为9.0.1,这远远超出了Debian提供的功能。

 $ pip --version
 pip 9.0.1 from /home/myhomedir/myvirtualenvdir/lib/python2.7/dist-packages (python 2.7)
 $ pip3 --version
 pip 9.0.1 from /home/myhomedir/myvirtualenvdir/lib/python3.4/site-packages (python 3.4)

I tried all of these solutions mentioned above under Debian Jessie. They don’t work, because it just takes the latest version compile by the debian package manager which is 1.5.6 which equates to version 6.0.x. Some packages that use pip as prerequisites will not work as a results, such as spaCy (which needs the option –no-cache-dir to function correctly).

So the actual best way to solve these problems is to run get-pip.py downloaded using wget, from the website or using curl as follows:

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

This will install the current version which at the time of writing this solution is 9.0.1 which is way beyond what Debian provides.

 $ pip --version
 pip 9.0.1 from /home/myhomedir/myvirtualenvdir/lib/python2.7/dist-packages (python 2.7)
 $ pip3 --version
 pip 9.0.1 from /home/myhomedir/myvirtualenvdir/lib/python3.4/site-packages (python 3.4)

回答 4

由于可怕的证书问题,使用’ pip install –upgrade pip ‘ 升级pip 并不总是有效:确认ssl证书时出现问题:[SSL:TLSV1_ALERT_PROTOCOL_VERSION] tlsv1警报协议版本

我喜欢对虚拟环境使用单行命令:

curl https://bootstrap.pypa.io/get-pip.py | python -

或者,如果您想将其安装在宽盒中,则需要

curl https://bootstrap.pypa.io/get-pip.py | sudo python -

如果要在自动化脚本中运行时使输出静音,则可以给curl -s标志。

Upgrading pip using ‘pip install –upgrade pip‘ does not always work because of the dreaded cert issue: There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version

I like to use the one line command for virtual envs:

curl https://bootstrap.pypa.io/get-pip.py | python -

Or if you want to install it box wide you will need

curl https://bootstrap.pypa.io/get-pip.py | sudo python -

you can give curl a -s flag if you want to silence the output when running in an automation script.


回答 5

就我而言,这是从Debian Stable中的终端命令行执行的

python3 -m pip install --upgrade pip

In my case this worked from the terminal command line in Debian Stable

python3 -m pip install --upgrade pip

回答 6

为了使它对我有用,我必须使用Python命令提示符(在VS CODE的WIN10上)在Python目录中进行深入研究。就我而言,它位于我的“ AppData \ Local \ Programs \ Python \ python35-32”目录中。从现在开始,我执行命令…

python -m pip install --upgrade pip

这很有效,我很好。

To get this to work for me I had to drill down in the Python directory using the Python command prompt (on WIN10 from VS CODE). In my case it was in my “AppData\Local\Programs\Python\python35-32” directory. From there now I ran the command…

python -m pip install --upgrade pip

This worked and I’m good to go.


回答 7

使用管理员权限打开命令提示符,然后重复以下命令:

python -m pip install --upgrade pip

Open Command Prompt with Administrator Permissions, and repeat the command:

python -m pip install --upgrade pip

回答 8

pip版本10有问题。它将显示为错误:

ubuntu@mymachine-:~/mydir$ sudo pip install --upgrade pip
Traceback (most recent call last):
  File "/usr/bin/pip", line 9, in <module>
    from pip import main
ImportError: cannot import name main

解决方案是在要升级的venv中,然后运行:

sudo myvenv/bin/pip install --upgrade pip

而不只是

sudo pip install --upgrade pip

pip version 10 has an issue. It will manifest as the error:

ubuntu@mymachine-:~/mydir$ sudo pip install --upgrade pip
Traceback (most recent call last):
  File "/usr/bin/pip", line 9, in <module>
    from pip import main
ImportError: cannot import name main

The solution is to be in the venv you want to upgrade and then run:

sudo myvenv/bin/pip install --upgrade pip

rather than just

sudo pip install --upgrade pip

回答 9

如果您使用venv,则任何更新到pip的安装都将导致升级系统pip,而不是venv pip。您还需要升级pip引导程序包。

  python3 -m pip install --upgrade pip setuptools wheel

In case you are using venv any update to pip install will result in upgrading the system pip instead of the venv pip. You need to upgrade the pip bootstrapping packages as well.

  python3 -m pip install --upgrade pip setuptools wheel

回答 10

我已经在C:\ Python \ Python36中安装了Python,因此转到Windows命令提示符并键入“ cd C:\ Python \ Python36”以获取正确的目录。然后输入“ python -m install –upgrade pip”全部好!

I had installed Python in C:\Python\Python36 so I went to the Windows command prompt and typed “cd C:\Python\Python36 to get to the right directory. Then entered the “python -m install –upgrade pip” all good!


回答 11

在Windows 7笔记本电脑上,正确安装最新版本的pip的正确方法是:

python.exe -m pip install --upgrade pip

On my lap-top with Windows 7 the right way to install latest version of pip is:

python.exe -m pip install --upgrade pip

回答 12

单行Python程序
我发现的最好方法是编写一个单行程序,该程序可以下载并运行官方的get-pip脚本。参见下面的代码。

官方文档建议使用curl下载get-pip脚本,但是由于我在Windows上工作且未安装curl,因此我更喜欢使用python本身来下载和运行脚本。

这是可以使用Python 3通过命令行运行的单行程序:

python -c "import urllib.request; exec(urllib.request.urlopen('https://bootstrap.pypa.io/get-pip.py').read())"

根据安装说明,该行将获取官方的“ get-pip.py”脚本,并使用“ exec”命令执行该脚本。

对于Python2,您可以将“ urllib.request”替换为“ urllib2”:

python -c "import urllib2; exec(urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py').read())"

预防措施
值得注意的是,盲目运行任何python脚本本质上都是危险的。因此,官方说明建议在运行之前下载脚本并进行检查。

就是说,许多人实际上并不检查代码,而只是运行它。这一单行程序使这一过程变得更加容易。

Single Line Python Program
The best way I have found is to write a single line program that downloads and runs the official get-pip script. See below for the code.

The official docs recommend using curl to download the get-pip script, but since I work on windows and don’t have curl installed I prefer using python itself to download and run the script.

Here is the single line program that can be run via the command line using Python 3:

python -c "import urllib.request; exec(urllib.request.urlopen('https://bootstrap.pypa.io/get-pip.py').read())"

This line gets the official “get-pip.py” script as per the installation notes and executes the script with the “exec” command.

For Python2 you would replace “urllib.request” with “urllib2”:

python -c "import urllib2; exec(urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py').read())"

Precautions
It’s worth noting that running any python script blindly is inherently dangerous. For this reason, the official instructions recommend downloading the script and inspecting it before running.

That said, many people don’t actually inspect the code and just run it. This one-line program makes that easier.


回答 13

我在树莓派上遇到了类似的问题。

问题在于http需要SSL,因此我需要强制它使用https来解决此要求。

sudo pip install --upgrade pip --index-url=https://pypi.python.org/simple

要么

sudo pip-3.2 --upgrade pip --index-url=https://pypi.python.org/simple/

I had a similar problem on a raspberry pi.

The problem was that http requires SSL and so I needed to force it to use https to get around this requirement.

sudo pip install --upgrade pip --index-url=https://pypi.python.org/simple

or

sudo pip-3.2 --upgrade pip --index-url=https://pypi.python.org/simple/

回答 14

我处于类似情况,想更新urllib3软件包。对我有用的是:

pip3 install --upgrade --force-reinstall --ignore-installed urllib3==1.25.3

I was in a similar situation and wanted to update urllib3 package. What worked for me was:

pip3 install --upgrade --force-reinstall --ignore-installed urllib3==1.25.3

回答 15

很简单。只需从https://bootstrap.pypa.io/get-pip.py下载pip 。将文件保存在forlder或dekstop中。我将文件保存在D盘中,然后从命令提示符导航到下载pip的文件夹。然后在那打

python -get-pip.py

点安装屏幕截图

Very Simple. Just download pip from https://bootstrap.pypa.io/get-pip.py . Save the file in some forlder or dekstop. I saved the file in my D drive.Then from your command prompt navigate to the folder where you have downloaded pip. Then type there

python -get-pip.py

Pip installation screenshot


获取map()以在Python 3.x中返回列表

问题:获取map()以在Python 3.x中返回列表

我正在尝试将列表映射为十六进制,然后在其他地方使用该列表。在python 2.6中,这很简单:

答: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

但是,在Python 3.1中,以上代码返回一个map对象。

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

如何在Python 3.x上检索映射列表(如上面的A所示)?

另外,还有更好的方法吗?我的初始列表对象大约有45个项目,并且id喜欢将它们转换为十六进制。

I’m trying to map a list into hex, and then use the list elsewhere. In python 2.6, this was easy:

A: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

However, in Python 3.1, the above returns a map object.

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

How do I retrieve the mapped list (as in A above) on Python 3.x?

Alternatively, is there a better way of doing this? My initial list object has around 45 items and id like to convert them to hex.


回答 0

做这个:

list(map(chr,[66,53,0,94]))

在Python 3+中,许多迭代可迭代对象的进程本身都会返回迭代器。在大多数情况下,这最终会节省内存,并且应该使处理速度更快。

如果您要做的只是最终遍历此列表,则无需将其转换为列表,因为您仍然可以map像这样遍历该对象:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)

Do this:

list(map(chr,[66,53,0,94]))

In Python 3+, many processes that iterate over iterables return iterators themselves. In most cases, this ends up saving memory, and should make things go faster.

If all you’re going to do is iterate over this list eventually, there’s no need to even convert it to a list, because you can still iterate over the map object like so:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)

回答 1

Python 3.5的新功能:

[*map(chr, [66, 53, 0, 94])]

多亏了其他拆包概述

更新

一直在寻找更短的途径,我发现这也行得通:

*map(chr, [66, 53, 0, 94]),

开箱也适用于元组。注意最后的逗号。这使其成为1个元素的元组。也就是说,它相当于(*map(chr, [66, 53, 0, 94]),)

它比带有方括号的版本短一个字符,但我认为最好写,因为您从星号-扩展语法开始,所以我觉得它比较软。:)

New and neat in Python 3.5:

[*map(chr, [66, 53, 0, 94])]

Thanks to Additional Unpacking Generalizations

UPDATE

Always seeking for shorter ways, I discovered this one also works:

*map(chr, [66, 53, 0, 94]),

Unpacking works in tuples too. Note the comma at the end. This makes it a tuple of 1 element. That is, it’s equivalent to (*map(chr, [66, 53, 0, 94]),)

It’s shorter by only one char from the version with the list-brackets, but, in my opinion, better to write, because you start right ahead with the asterisk – the expansion syntax, so I feel it’s softer on the mind. :)


回答 2

您为什么不这样做:

[chr(x) for x in [66,53,0,94]]

这称为列表理解。您可以在Google上找到很多信息,但是这里是list comprehensions上的Python(2.6)文档的链接。不过,您可能对Python 3文档更感兴趣。

Why aren’t you doing this:

[chr(x) for x in [66,53,0,94]]

It’s called a list comprehension. You can find plenty of information on Google, but here’s the link to the Python (2.6) documentation on list comprehensions. You might be more interested in the Python 3 documenation, though.


回答 3

返回列表的地图功能具有保存键入的优点,尤其是在交互式会话期间。您可以定义返回列表的lmap函数(类似于python2的函数imap):

lmap = lambda func, *iterable: list(map(func, *iterable))

然后打电话 lmap而不是即可map完成工作:比 lmap(str, x)短5个字符(在这种情况下为30%),list(map(str, x))并且肯定比短[str(v) for v in x]。您也可以创建类似的功能filter

对原始问题有一条评论:

我建议重命名为Geting map()以返回Python 3. *中的列表,因为它适用于所有Python3版本。有没有办法做到这一点?– meawoppl 1月24日17:58

有可能做到这一点,但它是一个非常糟糕的主意。只是为了好玩,您可以(但不应)执行以下操作:

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator

List-returning map function has the advantage of saving typing, especially during interactive sessions. You can define lmap function (on the analogy of python2’s imap) that returns list:

lmap = lambda func, *iterable: list(map(func, *iterable))

Then calling lmap instead of map will do the job: lmap(str, x) is shorter by 5 characters (30% in this case) than list(map(str, x)) and is certainly shorter than [str(v) for v in x]. You may create similar functions for filter too.

There was a comment to the original question:

I would suggest a rename to Getting map() to return a list in Python 3.* as it applies to all Python3 versions. Is there a way to do this? – meawoppl Jan 24 at 17:58

It is possible to do that, but it is a very bad idea. Just for fun, here’s how you may (but should not) do it:

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator

回答 4

我的旧注释转换为更好的可见性:为了更好地“更好地做到这一点” map,如果您的输入已知为ASCII序数,则通常可以更快地转换为bytesla bytes(list_of_ordinals).decode('ascii')。这样就可以得到一个str值,但是如果您需要a list来实现可变性或类似功能,则可以将其转换(并且转换速度仍然更快)。例如,在微ipython基准中转换45个输入:

>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

如果您将其保留为str,则最快的map解决方案会花费大约20%的时间;即使转换回列表,它仍然不到最快map解决方案的40%。批量转换通过bytesbytes.decode然后批量转换回以list节省大量工作,但是如上所述,仅当您所有的输入都是ASCII序号(或每个字符特定于区域设置编码的字节中的序号latin-1)时,该方法才有效。

Converting my old comment for better visibility: For a “better way to do this” without map entirely, if your inputs are known to be ASCII ordinals, it’s generally much faster to convert to bytes and decode, a la bytes(list_of_ordinals).decode('ascii'). That gets you a str of the values, but if you need a list for mutability or the like, you can just convert it (and it’s still faster). For example, in ipython microbenchmarks converting 45 inputs:

>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

If you leave it as a str, it takes ~20% of the time of the fastest map solutions; even converting back to list it’s still less than 40% of the fastest map solution. Bulk convert via bytes and bytes.decode then bulk converting back to list saves a lot of work, but as noted, only works if all your inputs are ASCII ordinals (or ordinals in some one byte per character locale specific encoding, e.g. latin-1).


回答 5

list(map(chr, [66, 53, 0, 94]))

map(func,* iterables)->地图对象创建一个迭代器,该迭代器使用每个可迭代对象的参数来计算函数。当最短的迭代次数用尽时停止。

“进行迭代”

表示它将返回迭代器。

“使用每个可迭代对象的参数来计算函数”

意味着迭代器的next()函数将为每个可迭代对象取一个值,并将每个值传递给该函数的一个位置参数。

因此,您可以从map()函数中获得一个迭代器,然后jsut将其传递给内置函数list()或使用列表推导。

list(map(chr, [66, 53, 0, 94]))

map(func, *iterables) –> map object Make an iterator that computes the function using arguments from each of the iterables. Stops when the shortest iterable is exhausted.

“Make an iterator”

means it will return an iterator.

“that computes the function using arguments from each of the iterables”

means that the next() function of the iterator will take one value of each iterables and pass each of them to one positional parameter of the function.

So you get an iterator from the map() funtion and jsut pass it to the list() builtin function or use list comprehensions.


回答 6

除了上述答案外Python 3,我们还可以简单地listmapas中创建结果值a

li = []
for x in map(chr,[66,53,0,94]):
    li.append(x)

print (li)
>>>['B', '5', '\x00', '^']

我们可以通过另一个例子来概括我被打动的情况,对地图的操作也可以像regex问题中一样的方式处理,我们可以编写函数以获取list要映射的项目并同时获取结果集。例如

b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('\d+', b))):
    li.append(x)

print (li)
>>>[1, 72, 474]

In addition to above answers in Python 3, we may simply create a list of result values from a map as

li = []
for x in map(chr,[66,53,0,94]):
    li.append(x)

print (li)
>>>['B', '5', '\x00', '^']

We may generalize by another example where I was struck, operations on map can also be handled in similar fashion like in regex problem, we can write function to obtain list of items to map and get result set at the same time. Ex.

b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('\d+', b))):
    li.append(x)

print (li)
>>>[1, 72, 474]

回答 7

您可以尝试通过仅迭代对象中的每个项目并将其存储在另一个变量中来从地图对象获取列表。

a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', '\x00', '^']

You can try getting a list from the map object by just iterating each item in the object and store it in a different variable.

a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', '\x00', '^']

回答 8

使用python中的列表理解和基本的地图函数实用程序,还可以做到这一点:

chi = [x for x in map(chr,[66,53,0,94])]

Using list comprehension in python and basic map function utility, one can do this also:

chi = [x for x in map(chr,[66,53,0,94])]


创建重复N次的单个项目的列表

问题:创建重复N次的单个项目的列表

我想创建一系列长度不一的列表。每个列表将包含相同的元素e,重复n次数(其中n=列表的长度)。

如何创建列表,而不[e for number in xrange(n)]对每个列表使用列表理解?

I want to create a series of lists, all of varying lengths. Each list will contain the same element e, repeated n times (where n = length of the list).

How do I create the lists, without using a list comprehension [e for number in xrange(n)] for each list?


回答 0

您还可以编写:

[e] * n

您应该注意,例如,如果e是一个空列表,您将得到一个具有n个指向同一列表的引用的列表,而不是n个独立的空列表。

性能测试

乍看之下,似乎是重复是创建一个具有n个相同的元素列表的最快方法:

>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

但是等等-这不是一个公平的测试…

>>> itertools.repeat(0, 10)
repeat(0, 10)  # Not a list!!!

该函数itertools.repeat实际上并没有创建列表,它只是创建一个对象,您可以根据需要使用该对象来创建列表!让我们再试一次,但转换为列表:

>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

因此,如果您想要列表,请使用[e] * n。如果要延迟生成元素,请使用repeat

You can also write:

[e] * n

You should note that if e is for example an empty list you get a list with n references to the same list, not n independent empty lists.

Performance testing

At first glance it seems that repeat is the fastest way to create a list with n identical elements:

>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

But wait – it’s not a fair test…

>>> itertools.repeat(0, 10)
repeat(0, 10)  # Not a list!!!

The function itertools.repeat doesn’t actually create the list, it just creates an object that can be used to create a list if you wish! Let’s try that again, but converting to a list:

>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

So if you want a list, use [e] * n. If you want to generate the elements lazily, use repeat.


回答 1

>>> [5] * 4
[5, 5, 5, 5]

当重复的项目是列表时,请当心。该列表将不会被克隆:所有元素都将引用同一列表!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
>>> [5] * 4
[5, 5, 5, 5]

Be careful when the item being repeated is a list. The list will not be cloned: all the elements will refer to the same list!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]

回答 2

在Python中创建重复n次的单项列表

不变物品

对于不可变的项目,例如“无”,布尔值,整数,浮点数,字符串,元组或Frozensets,可以这样进行:

[e] * 4

请注意,这最好仅与列表中的不可变项(字符串,元组,frozensets)一起使用,因为它们都指向内存中同一位置的同一项。当我必须构建一个包含所有字符串的架构的表时,我会经常使用它,这样就不必提供高度冗余的一对一映射。

schema = ['string'] * len(columns)

可变项

我已经使用Python很长时间了,而且从未见过用可变实例执行上述操作的用例。相反,要获取可变的空列表,集合或字典,您应该执行以下操作:

list_of_lists = [[] for _ in columns]

在这种情况下,下划线只是一个简单的变量名。

如果只有号码,那将是:

list_of_lists = [[] for _ in range(4)]

_不是真的很特别,但你的编码环境风格检查可能会抱怨,如果你不打算使用的变量和使用的其他任何名称。


对可变项使用不可变方法的注意事项:

当心使用可变对象,当您更改其中一个对象时,它们都会更改,因为它们都是同一对象:

foo = [[]] * 4
foo[0].append('x')

foo现在返回:

[['x'], ['x'], ['x'], ['x']]

但是对于不可变的对象,您可以使其起作用,因为您可以更改引用,而不是对象:

>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]

>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

但同样,可变对象对此没有好处,因为就地操作会更改对象,而不是引用:

l = [set()] * 4
>>> l[0] |= set('abc')    
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]

Create List of Single Item Repeated n Times in Python

Immutable items

For immutable items, like None, bools, ints, floats, strings, tuples, or frozensets, you can do it like this:

[e] * 4

Note that this is best only used with immutable items (strings, tuples, frozensets, ) in the list, because they all point to the same item in the same place in memory. I use this frequently when I have to build a table with a schema of all strings, so that I don’t have to give a highly redundant one to one mapping.

schema = ['string'] * len(columns)

Mutable items

I’ve used Python for a long time now, and I have never seen a use-case where I would do the above with a mutable instance. Instead, to get, say, a mutable empty list, set, or dict, you should do something like this:

list_of_lists = [[] for _ in columns]

The underscore is simply a throwaway variable name in this context.

If you only have the number, that would be:

list_of_lists = [[] for _ in range(4)]

The _ is not really special, but your coding environment style checker will probably complain if you don’t intend to use the variable and use any other name.


Caveats for using the immutable method with mutable items:

Beware doing this with mutable objects, when you change one of them, they all change because they’re all the same object:

foo = [[]] * 4
foo[0].append('x')

foo now returns:

[['x'], ['x'], ['x'], ['x']]

But with immutable objects, you can make it work because you change the reference, not the object:

>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]

>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

But again, mutable objects are no good for this, because in-place operations change the object, not the reference:

l = [set()] * 4
>>> l[0] |= set('abc')    
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]

回答 3

Itertools具有此功能:

import itertools
it = itertools.repeat(e,n)

当然可以itertools为您提供迭代器,而不是列表。[e] * n为您提供了一个列表,但是根据您对这些序列的处理方式,itertools变体可能会更加有效。

Itertools has a function just for that:

import itertools
it = itertools.repeat(e,n)

Of course itertools gives you a iterator instead of a list. [e] * n gives you a list, but, depending on what you will do with those sequences, the itertools variant can be much more efficient.


回答 4

正如其他人指出的那样,对可变对象使用*运算符会重复引用,因此,如果更改一个,则会全部更改。如果要创建可变对象的独立实例,则xrange语法是执行此操作的最Python方式。如果您有一个从未使用过的命名变量而感到困扰,则可以使用匿名下划线变量。

[e for _ in xrange(n)]

As others have pointed out, using the * operator for a mutable object duplicates references, so if you change one you change them all. If you want to create independent instances of a mutable object, your xrange syntax is the most Pythonic way to do this. If you are bothered by having a named variable that is never used, you can use the anonymous underscore variable.

[e for _ in xrange(n)]

回答 5

[e] * n

应该管用

[e] * n

should work


从Python调用C / C ++?

问题:从Python调用C / C ++?

构造与C或C ++库的Python绑定的最快方法是什么?

(如果这很重要,我正在使用Windows。)

What would be the quickest way to construct a Python binding to a C or C++ library?

(I am using Windows if this matters.)


回答 0

您应该看看Boost.Python。以下是他们网站上的简短介绍:

Boost Python库是用于连接Python和C ++的框架。它使您可以快速而无缝地将C ++类的函数和对象暴露给Python,反之亦然,而无需使用特殊工具-仅使用C ++编译器即可。它旨在非侵入性地包装C ++接口,因此您不必为了包装而完全更改C ++代码,从而使Boost.Python成为将第三方库公开给Python的理想选择。该库对高级元编程技术的使用简化了用户的语法,因此包装代码具有一种声明性接口定义语言(IDL)的外观。

You should have a look at Boost.Python. Here is the short introduction taken from their website:

The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools — just your C++ compiler. It is designed to wrap C++ interfaces non-intrusively, so that you should not have to change the C++ code at all in order to wrap it, making Boost.Python ideal for exposing 3rd-party libraries to Python. The library’s use of advanced metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).


回答 1

ctypes模块是标准库的一部分,因此比swig更稳定和更易于使用,而swig总是会给我带来麻烦

使用ctypes时,您需要满足对python的任何编译时依赖性,并且绑定将对任何具有ctypes的python起作用,而不仅仅是针对ctypes的python。

假设您要在一个名为foo.cpp的文件中讨论一个简单的C ++示例类:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

由于ctypes只能与C函数对话,因此您需要提供将其声明为extern“ C”的那些函数

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

接下来,您必须将其编译为共享库

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

最后,您必须编写python包装器(例如,在fooWrapper.py中)

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

一旦有了,您可以像这样称呼它

f = Foo()
f.bar() #and you will see "Hello" on the screen

ctypes module is part of the standard library, and therefore is more stable and widely available than swig, which always tended to give me problems.

With ctypes, you need to satisfy any compile time dependency on python, and your binding will work on any python that has ctypes, not just the one it was compiled against.

Suppose you have a simple C++ example class you want to talk to in a file called foo.cpp:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

Since ctypes can only talk to C functions, you need to provide those declaring them as extern “C”

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

Next you have to compile this to a shared library

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

And finally you have to write your python wrapper (e.g. in fooWrapper.py)

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

Once you have that you can call it like

f = Foo()
f.bar() #and you will see "Hello" on the screen

回答 2

最快的方法是使用SWIG

来自SWIG 教程的示例

/* File : example.c */
int fact(int n) {
    if (n <= 1) return 1;
    else return n*fact(n-1);
}

接口文件:

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}

extern int fact(int n);

在Unix上构建Python模块:

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so

用法:

>>> import example
>>> example.fact(5)
120

请注意,您必须具有python-dev。同样在某些系统中,python头文件会根据您的安装方式位于/usr/include/python2.7中。

从教程中:

SWIG是一个相当完整的C ++编译器,几乎支持所有语言功能。这包括预处理,指针,类,继承,甚至C ++模板。SWIG还可以用于以目标语言将结构和类打包为代理类,从而以非常自然的方式公开基础功能。

The quickest way to do this is using SWIG.

Example from SWIG tutorial:

/* File : example.c */
int fact(int n) {
    if (n <= 1) return 1;
    else return n*fact(n-1);
}

Interface file:

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}

extern int fact(int n);

Building a Python module on Unix:

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so

Usage:

>>> import example
>>> example.fact(5)
120

Note that you have to have python-dev. Also in some systems python header files will be in /usr/include/python2.7 based on the way you have installed it.

From the tutorial:

SWIG is a fairly complete C++ compiler with support for nearly every language feature. This includes preprocessing, pointers, classes, inheritance, and even C++ templates. SWIG can also be used to package structures and classes into proxy classes in the target language — exposing the underlying functionality in a very natural manner.


回答 3

我从这一页的Python <-> C ++绑定开始了我的旅程,目的是链接高级数据类型(带有Python列表的多维STL向量):-)

尝试过基于ctypesboost.python的解决方案(并且不是软件工程师),当需要高级数据类型绑定时,我发现它们很复杂,而对于这种情况,我发现SWIG更加简单。

因此,该示例使用了SWIG,并且已经在Linux中进行了测试(但是SWIG可用,并且在Windows中也被广泛使用)。

目的是使C ++函数可用于Python,该函数采用2D STL向量形式的矩阵并返回每一行的平均值(作为1D STL向量)。

C ++中的代码(“ code.cpp”)如下:

#include <vector>
#include "code.h"

using namespace std;

vector<double> average (vector< vector<double> > i_matrix) {

  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < i_matrix.size(); r++){
    double rsum = 0.0;
    double ncols= i_matrix[r].size();
    for (int c = 0; c< i_matrix[r].size(); c++){
      rsum += i_matrix[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

等效的标头(“ code.h”)为:

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

我们首先编译C ++代码以创建目标文件:

g++ -c -fPIC code.cpp

然后,我们为C ++函数定义一个SWIG接口定义文件(“ code.i”)。

%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

使用SWIG,我们从SWIG接口定义文件生成C ++接口源代码。

swig -c++ -python code.i

最后,我们编译生成的C ++接口源文件,并将所有内容链接在一起,以生成可由Python直接导入的共享库(“ _”很重要):

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o

现在,我们可以在Python脚本中使用该函数:

#!/usr/bin/env python

import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b

I started my journey in the Python <-> C++ binding from this page, with the objective of linking high level data types (multidimensional STL vectors with Python lists) :-)

Having tried the solutions based on both ctypes and boost.python (and not being a software engineer) I have found them complex when high level datatypes binding is required, while I have found SWIG much more simple for such cases.

This example uses therefore SWIG, and it has been tested in Linux (but SWIG is available and is widely used in Windows too).

The objective is to make a C++ function available to Python that takes a matrix in form of a 2D STL vector and returns an average of each row (as a 1D STL vector).

The code in C++ (“code.cpp”) is as follow:

#include <vector>
#include "code.h"

using namespace std;

vector<double> average (vector< vector<double> > i_matrix) {

  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < i_matrix.size(); r++){
    double rsum = 0.0;
    double ncols= i_matrix[r].size();
    for (int c = 0; c< i_matrix[r].size(); c++){
      rsum += i_matrix[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

The equivalent header (“code.h”) is:

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

We first compile the C++ code to create an object file:

g++ -c -fPIC code.cpp

We then define a SWIG interface definition file (“code.i”) for our C++ functions.

%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

Using SWIG, we generate a C++ interface source code from the SWIG interface definition file..

swig -c++ -python code.i

We finally compile the generated C++ interface source file and link everything together to generate a shared library that is directly importable by Python (the “_” matters):

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o

We can now use the function in Python scripts:

#!/usr/bin/env python

import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b

回答 4

还有pybind11,就像Boost.Python的轻量级版本,并且与所有现代C ++编译器兼容:

https://pybind11.readthedocs.io/en/latest/

There is also pybind11, which is like a lightweight version of Boost.Python and compatible with all modern C++ compilers:

https://pybind11.readthedocs.io/en/latest/


回答 5

检查出pyrexCython。它们是类似于Python的语言,用于C / C ++和Python之间的接口。

Check out pyrex or Cython. They’re Python-like languages for interfacing between C/C++ and Python.


回答 6

对于现代C ++,请使用cppyy: http

它基于Cling / Clang / LLVM的C ++解释器。绑定是在运行时执行的,不需要其他中间语言。感谢Clang,它支持C ++ 17。

使用pip安装它:

    $ pip install cppyy

对于小型项目,只需加载相关的库和您感兴趣的标头。例如,从ctypes示例中获取代码就是该线程,但分为标头和代码部分:

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

编译:

    $ g++ -c -fPIC foo.cpp -o foo.o
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

并使用它:

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

大型项目通过自动加载准备的反射信息和cmake片段来创建它们而受支持,因此安装包的用户可以简单地运行:

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

多亏了LLVM,高级功能才得以实现,例如自动模板实例化。继续示例:

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

注意:我是cppyy的作者。

For modern C++, use cppyy: http://cppyy.readthedocs.io/en/latest/

It’s based on Cling, the C++ interpreter for Clang/LLVM. Bindings are at run-time and no additional intermediate language is necessary. Thanks to Clang, it supports C++17.

Install it using pip:

    $ pip install cppyy

For small projects, simply load the relevant library and the headers that you are interested in. E.g. take the code from the ctypes example is this thread, but split in header and code sections:

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

Compile it:

    $ g++ -c -fPIC foo.cpp -o foo.o
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

and use it:

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

Large projects are supported with auto-loading of prepared reflection information and the cmake fragments to create them, so that users of installed packages can simply run:

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

Thanks to LLVM, advanced features are possible, such as automatic template instantiation. To continue the example:

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

Note: I’m the author of cppyy.


回答 7

本文声称Python是科学家的全部需要,基本上说:首先用Python制作一切原型。然后,当您需要加快零件速度时,请使用SWIG并将其转换为C。

This paper, claiming Python to be all a scientist needs, basically says: First prototype everything in Python. Then when you need to speed a part up, use SWIG and translate this part to C.


回答 8

我从未使用过它,但是我听说过有关ctypes的好东西。如果您要在C ++中使用它,请确保通过来避开名称修饰extern "C"感谢弗洛里安·博斯(FlorianBösch)的评论。

I’ve never used it but I’ve heard good things about ctypes. If you’re trying to use it with C++, be sure to evade name mangling via extern "C". Thanks for the comment, Florian Bösch.


回答 9

我认为cffi for python是一个选择。

目的是从Python调用C代码。您应该能够在不学习第三语言的情况下进行操作:每种选择都要求您学习他们自己的语言(Cython,SWIG)或API(ctypes)。因此,我们尝试假设您了解Python和C,并尽量减少了您需要学习的API附加位。

http://cffi.readthedocs.org/en/release-0.7/

I think cffi for python can be an option.

The goal is to call C code from Python. You should be able to do so without learning a 3rd language: every alternative requires you to learn their own language (Cython, SWIG) or API (ctypes). So we tried to assume that you know Python and C and minimize the extra bits of API that you need to learn.

http://cffi.readthedocs.org/en/release-0.7/


回答 10

问题是,如果我理解正确的话,如何从Python调用C函数。然后最好的选择是Ctypes(BTW可在所有Python变体中移植)。

>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19

有关详细指南,您可能需要参考我的博客文章

The question is how to call a C function from Python, if I understood correctly. Then the best bet are Ctypes (BTW portable across all variants of Python).

>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19

For a detailed guide you may want to refer to my blog article.


回答 11

一份正式的Python文档包含有关使用C / C ++扩展Python的详细信息。即使不使用SWIG,它也非常简单,并且在Windows上也能很好地工作。

One of the official Python documents contains details on extending Python using C/C++. Even without the use of SWIG, it’s quite straightforward and works perfectly well on Windows.


回答 12

除非您期望编写Java包装程序,否则Cython绝对是必经之路,在这种情况下,SWIG可能更可取。

我建议使用 runcython命令行实用程序,它使使用Cython的过程非常容易。如果您需要将结构化数据传递给C ++,请查看Google的protobuf库,它非常方便。

这是我使用这两种工具的最小示例:

https://github.com/nicodjimenez/python2cpp

希望它可以是一个有用的起点。

Cython is definitely the way to go, unless you anticipate writing Java wrappers, in which case SWIG may be preferable.

I recommend using the runcython command line utility, it makes the process of using Cython extremely easy. If you need to pass structured data to C++, take a look at Google’s protobuf library, it’s very convenient.

Here is a minimal examples I made that uses both tools:

https://github.com/nicodjimenez/python2cpp

Hope it can be a useful starting point.


回答 13

首先,您应该确定自己的特定目的。上面提到有关扩展和嵌入Python解释器的官方Python文档,我可以添加一个很好的二进制扩展概述。用例可分为3类:

  • 加速器模块:运行速度比CPython中运行的等效纯Python代码更快。
  • 包装模块:将现有的C接口公开给Python代码。
  • 低级系统访问:访问CPython运行时,操作系统或底层硬件的低级功能。

为了给其他感兴趣的人提供更广阔的视野,并且由于您的最初问题有点含糊(“对C或C ++库”),我认为此信息可能对您很有趣。在上面的链接上,您可以了解使用二进制扩展名及其替代方法的缺点。

除了建议的其他答案外,如果您需要加速器模块,还可以尝试Numba。它的工作原理是“通过在导入时间,运行时或静态(使用附带的pycc工具)使用LLVM编译器基础结构生成优化的机器代码”。

First you should decide what is your particular purpose. The official Python documentation on extending and embedding the Python interpreter was mentioned above, I can add a good overview of binary extensions. The use cases can be divided into 3 categories:

  • accelerator modules: to run faster than the equivalent pure Python code runs in CPython.
  • wrapper modules: to expose existing C interfaces to Python code.
  • low level system access: to access lower level features of the CPython runtime, the operating system, or the underlying hardware.

In order to give some broader perspective for other interested and since your initial question is a bit vague (“to a C or C++ library”) I think this information might be interesting to you. On the link above you can read on disadvantages of using binary extensions and its alternatives.

Apart from the other answers suggested, if you want an accelerator module, you can try Numba. It works “by generating optimized machine code using the LLVM compiler infrastructure at import time, runtime, or statically (using the included pycc tool)”.


回答 14

我喜欢cppyy,它很容易用C ++代码扩展Python,并在需要时大大提高了性能。

它功能强大且坦率地说非常易于使用,

这是一个示例,说明如何创建numpy数组并将其传递给C ++中的类成员函数。

import cppyy
cppyy.add_include_path("include")
cppyy.include('mylib/Buffer.h')


s = cppyy.gbl.buffer.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)

在C ++中:

struct Buffer {
  void get_numpy_array(int beam, double *ad, int size) {
    // fill the array
  }
}

您还可以非常轻松地(使用CMake)创建Python模块,这样您就可以避免一直重新编译C ++代码。

I love cppyy, it makes it very easy to extend Python with C++ code, dramatically increasing performance when needed.

It is powerful and frankly very simple to use,

here it is an example of how you can create a numpy array and pass it to a class member function in C++.

import cppyy
cppyy.add_include_path("include")
cppyy.include('mylib/Buffer.h')


s = cppyy.gbl.buffer.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)

in C++ :

struct Buffer {
  void get_numpy_array(int beam, double *ad, int size) {
    // fill the array
  }
}

You can also create a Python module very easily (with CMake), this way you will avoid recompile the C++ code all the times.


回答 15

pybind11最小可运行示例

pybind11之前在https://stackoverflow.com/a/38542539/895245中提到过,但是我想在这里给出一个具体的用法示例以及有关实现的更多讨论。

总而言之,我强烈推荐pybind11,因为它确实很容易使用:您只需包含一个标头,然后pybind11使用模板魔术检查要公开给Python的C ++类并透明地进行。

这种模板魔术的缺点是,它会立即减慢编译速度,从而会给使用pybind11的任何文件增加几秒钟的时间,例如,请参见对此问题进行的调查PyTorch同意

这是一个最小的可运行示例,使您了解pybind11的出色程度:

class_test.cpp

#include <string>

#include <pybind11/pybind11.h>

struct ClassTest {
    ClassTest(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }
    std::string name;
};

namespace py = pybind11;

PYBIND11_PLUGIN(class_test) {
    py::module m("my_module", "pybind11 example plugin");
    py::class_<ClassTest>(m, "ClassTest")
        .def(py::init<const std::string &>())
        .def("setName", &ClassTest::setName)
        .def("getName", &ClassTest::getName)
        .def_readwrite("name", &ClassTest::name);
    return m.ptr();
}

class_test_main.py

#!/usr/bin/env python3

import class_test

my_class_test = class_test.ClassTest("abc");
print(my_class_test.getName())
my_class_test.setName("012")
print(my_class_test.getName())
assert(my_class_test.getName() == my_class_test.name)

编译并运行:

#!/usr/bin/env bash
set -eux
g++ `python3-config --cflags` -shared -std=c++11 -fPIC class_test.cpp \
  -o class_test`python3-config --extension-suffix` `python3-config --libs`
./class_test_main.py

此示例说明pybind11如何使您轻松地将ClassTestC ++类公开给Python!编译会产生一个名为的文件class_test.cpython-36m-x86_64-linux-gnu.so,该文件会class_test_main.py自动作为文件的定义点class_test本地定义的模块。

也许只有在您尝试使用本机Python API手动执行相同操作时,才会意识到它的强大程度,例如,请参见以下示例,该示例包含大约10倍的代码:https : //github.com /cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c在该示例上,您可以看到C代码如何痛苦地,明确地定义Python类及其所包含的所有信息(成员,方法,其他信息)。元数据…)。也可以看看:

pybind11声称与https://stackoverflow.com/a/145436/895245Boost.Python所提到的相似,但因其摆脱了Boost项目中的膨胀而变得更加微不足道:

pybind11是一个轻量级的仅标头的库,它公开了Python中的C ++类型,反之亦然,主要是创建现有C ++代码的Python绑定。它的目标和语法类似于David Abrahams出色的Boost.Python库:通过使用编译时自省来推断类型信息,从而最大程度地减少了传统扩展模块中的样板代码。

Boost.Python的主要问题以及创建类似项目的原因是Boost。Boost是庞大而复杂的实用程序套件,可与几乎所有现有的C ++编译器一起使用。这种兼容性有其代价:奥秘的模板技巧和变通办法对于支持最早的和最新的编译器标本是必需的。现在,与C ++ 11兼容的编译器已广泛可用,这种繁琐的机制已变得过大且不必要。

可以将此库视为Boost.Python的小型独立版本,其中剥离了与绑定生成无关的所有内容。没有注释,核心头文件仅需要约4K行代码,并依赖于Python(2.7或3.x,或PyPy2.7> = 5.7)和C ++标准库。由于某些新的C ++ 11语言功能(特别是:元组,lambda函数和可变参数模板),因此可以实现这种紧凑的实现。自创建以来,该库在许多方面都超越了Boost.Python,从而在许多常见情况下大大简化了绑定代码。

pybind11还是当前Microsoft Python C绑定文档中突出显示的唯一非本地替代方法,网址为:https ://docs.microsoft.com/zh-cn/visualstudio/python/working-with-c-cpp-python-in- visual-studio?view = vs-2019存档)。

已在Ubuntu 18.04,pybind11 2.0.1,Python 3.6.8,GCC 7.4.0上进行了测试。

pybind11 minimal runnable example

pybind11 was previously mentioned at https://stackoverflow.com/a/38542539/895245 but I would like to give here a concrete usage example and some further discussion about implementation.

All and all, I highly recommend pybind11 because it is really easy to use: you just include a header and then pybind11 uses template magic to inspect the C++ class you want to expose to Python and does that transparently.

The downside of this template magic is that it slows down compilation immediately adding a few seconds to any file that uses pybind11, see for example the investigation done on this issue. PyTorch agrees.

Here is a minimal runnable example to give you a feel of how awesome pybind11 is:

class_test.cpp

#include <string>

#include <pybind11/pybind11.h>

struct ClassTest {
    ClassTest(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }
    std::string name;
};

namespace py = pybind11;

PYBIND11_PLUGIN(class_test) {
    py::module m("my_module", "pybind11 example plugin");
    py::class_<ClassTest>(m, "ClassTest")
        .def(py::init<const std::string &>())
        .def("setName", &ClassTest::setName)
        .def("getName", &ClassTest::getName)
        .def_readwrite("name", &ClassTest::name);
    return m.ptr();
}

class_test_main.py

#!/usr/bin/env python3

import class_test

my_class_test = class_test.ClassTest("abc");
print(my_class_test.getName())
my_class_test.setName("012")
print(my_class_test.getName())
assert(my_class_test.getName() == my_class_test.name)

Compile and run:

#!/usr/bin/env bash
set -eux
g++ `python3-config --cflags` -shared -std=c++11 -fPIC class_test.cpp \
  -o class_test`python3-config --extension-suffix` `python3-config --libs`
./class_test_main.py

This example shows how pybind11 allows you to effortlessly expose the ClassTest C++ class to Python! Compilation produces a file named class_test.cpython-36m-x86_64-linux-gnu.so which class_test_main.py automatically picks up as the definition point for the class_test natively defined module.

Perhaps the realization of how awesome this is only sinks in if you try to do the same thing by hand with the native Python API, see for example this example of doing that, which has about 10x more code: https://github.com/cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c On that example you can see how the C code has to painfully and explicitly define the Python class bit by bit with all the information it contains (members, methods, further metadata…). See also:

pybind11 claims to be similar to Boost.Python which was mentioned at https://stackoverflow.com/a/145436/895245 but more minimal because it is freed from the bloat of being inside the Boost project:

pybind11 is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. Its goals and syntax are similar to the excellent Boost.Python library by David Abrahams: to minimize boilerplate code in traditional extension modules by inferring type information using compile-time introspection.

The main issue with Boost.Python—and the reason for creating such a similar project—is Boost. Boost is an enormously large and complex suite of utility libraries that works with almost every C++ compiler in existence. This compatibility has its cost: arcane template tricks and workarounds are necessary to support the oldest and buggiest of compiler specimens. Now that C++11-compatible compilers are widely available, this heavy machinery has become an excessively large and unnecessary dependency.

Think of this library as a tiny self-contained version of Boost.Python with everything stripped away that isn’t relevant for binding generation. Without comments, the core header files only require ~4K lines of code and depend on Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This compact implementation was possible thanks to some of the new C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has grown beyond Boost.Python in many ways, leading to dramatically simpler binding code in many common situations.

pybind11 is also the only non-native alternative hightlighted by the current Microsoft Python C binding documentation at: https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in-visual-studio?view=vs-2019 (archive).

Tested on Ubuntu 18.04, pybind11 2.0.1, Python 3.6.8, GCC 7.4.0.