标签归档:Python

Python日期时间到没有微秒组件的字符串

问题:Python日期时间到没有微秒组件的字符串

我正在将UTC时间字符串添加到当前仅包含Amsterdam(!)时间字符串的Bitbucket API响应中。为了与其他地方返回的UTC时间字符串保持一致,请使用所需的格式2011-11-03 11:07:04(后跟+00:00,但这不是紧密联系)。

什么是创建这样一个字符串(最好的方式,而不从一微秒组件)datetime的实例微秒组成部分?

>>> import datetime
>>> print unicode(datetime.datetime.now())
2011-11-03 11:13:39.278026

我会添加出现在我身上的最佳选择作为可能的答案,但是可能会有更优雅的解决方案。

编辑:我应该提一下,我实际上并不是打印当前时间-我曾经datetime.now提供一个简单的例子。因此,该解决方案不应假定datetime其接收到的任何实例都将包含微秒组件。

I’m adding UTC time strings to Bitbucket API responses that currently only contain Amsterdam (!) time strings. For consistency with the UTC time strings returned elsewhere, the desired format is 2011-11-03 11:07:04 (followed by +00:00, but that’s not germane).

What’s the best way to create such a string (without a microsecond component) from a datetime instance with a microsecond component?

>>> import datetime
>>> print unicode(datetime.datetime.now())
2011-11-03 11:13:39.278026

I’ll add the best option that’s occurred to me as a possible answer, but there may well be a more elegant solution.

Edit: I should mention that I’m not actually printing the current time – I used datetime.now to provide a quick example. So the solution should not assume that any datetime instances it receives will include microsecond components.


回答 0

如果要以datetime不同于标准格式的特定格式格式化对象,则最好明确指定该格式:

>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2011-11-03 18:21:26'

有关指令的说明,请参见的文档datetime.strftime()%

If you want to format a datetime object in a specific format that is different from the standard format, it’s best to explicitly specify that format:

>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2011-11-03 18:21:26'

See the documentation of datetime.strftime() for an explanation of the % directives.


回答 1

>>> import datetime
>>> now = datetime.datetime.now()
>>> print unicode(now.replace(microsecond=0))
2011-11-03 11:19:07
>>> import datetime
>>> now = datetime.datetime.now()
>>> print unicode(now.replace(microsecond=0))
2011-11-03 11:19:07

回答 2

在Python 3.6中:

from datetime import datetime
datetime.datetime.now().isoformat(' ', 'seconds')
'2017-01-11 14:41:33'

https://docs.python.org/3.6/library/datetime.html#datetime.datetime.isoformat

In Python 3.6:

from datetime import datetime
datetime.datetime.now().isoformat(' ', 'seconds')
'2017-01-11 14:41:33'

https://docs.python.org/3.6/library/datetime.html#datetime.datetime.isoformat


回答 3

这就是我做到的方式。ISO格式:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
# Returns: '2017-01-23T14:58:07'

如果您不想使用ISO格式,则可以替换为’T’:

datetime.datetime.now().replace(microsecond=0).isoformat(' ')
# Returns: '2017-01-23 15:05:27'

This is the way I do it. ISO format:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
# Returns: '2017-01-23T14:58:07'

You can replace the ‘T’ if you don’t want ISO format:

datetime.datetime.now().replace(microsecond=0).isoformat(' ')
# Returns: '2017-01-23 15:05:27'

回答 4

另一个选择:

>>> import time
>>> time.strftime("%Y-%m-%d %H:%M:%S")
'2011-11-03 11:31:28'

默认情况下,这使用本地时间,如果您需要UTC,则可以使用以下时间:

>>> time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
'2011-11-03 18:32:20'

Yet another option:

>>> import time
>>> time.strftime("%Y-%m-%d %H:%M:%S")
'2011-11-03 11:31:28'

By default this uses local time, if you need UTC you can use the following:

>>> time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
'2011-11-03 18:32:20'

回答 5

通过切片保留所需的前19个字符:

>>> str(datetime.datetime.now())[:19]
'2011-11-03 14:37:50'

Keep the first 19 characters that you wanted via slicing:

>>> str(datetime.datetime.now())[:19]
'2011-11-03 14:37:50'

回答 6

我通常这样做:

import datetime
now = datetime.datetime.now()
now = now.replace(microsecond=0)  # To print now without microsecond.

# To print now:
print(now)

输出:

2019-01-13 14:40:28

I usually do:

import datetime
now = datetime.datetime.now()
now = now.replace(microsecond=0)  # To print now without microsecond.

# To print now:
print(now)

output:

2019-01-13 14:40:28

回答 7

由于并非所有datetime.datetime实例都具有微秒成分(即当它为零时),因此可以将字符串划分为“”。并只取第一项,它将始终有效:

unicode(datetime.datetime.now()).partition('.')[0]

Since not all datetime.datetime instances have a microsecond component (i.e. when it is zero), you can partition the string on a “.” and take only the first item, which will always work:

unicode(datetime.datetime.now()).partition('.')[0]

回答 8

我们可以尝试如下

import datetime

date_generated = datetime.datetime.now()
date_generated.replace(microsecond=0).isoformat(' ').partition('+')[0]

We can try something like below

import datetime

date_generated = datetime.datetime.now()
date_generated.replace(microsecond=0).isoformat(' ').partition('+')[0]

回答 9

我发现这是最简单的方法。

>>> t = datetime.datetime.now()
>>> t
datetime.datetime(2018, 11, 30, 17, 21, 26, 606191)
>>> t = str(t).split('.')
>>> t
['2018-11-30 17:21:26', '606191']
>>> t = t[0]
>>> t
'2018-11-30 17:21:26'
>>> 

I found this to be the simplest way.

>>> t = datetime.datetime.now()
>>> t
datetime.datetime(2018, 11, 30, 17, 21, 26, 606191)
>>> t = str(t).split('.')
>>> t
['2018-11-30 17:21:26', '606191']
>>> t = t[0]
>>> t
'2018-11-30 17:21:26'
>>> 

回答 10

我之所以使用它,是因为我可以更好地理解并记住它(日期时间格式也可以根据您的选择进行自定义):-

import datetime
moment = datetime.datetime.now()
print("{}/{}/{} {}:{}:{}".format(moment.day, moment.month, moment.year,
                                 moment.hour, moment.minute, moment.second))

This I use because I can understand and hence remember it better (and date time format also can be customized based on your choice) :-

import datetime
moment = datetime.datetime.now()
print("{}/{}/{} {}:{}:{}".format(moment.day, moment.month, moment.year,
                                 moment.hour, moment.minute, moment.second))

使用“导入模块”还是“从模块导入”?

问题:使用“导入模块”还是“从模块导入”?

我试图找到一个综合指南,以决定是否最好使用import modulefrom module import?我刚开始使用Python,并且正在尝试着眼于最佳实践。

基本上,我希望有人能分享他们的经验,其他开发人员有什么喜好,以及避免遇到麻烦的最佳方法是什么?

I’ve tried to find a comprehensive guide on whether it is best to use import module or from module import? I’ve just started with Python and I’m trying to start off with best practices in mind.

Basically, I was hoping if anyone could share their experiences, what preferences other developers have and what’s the best way to avoid any gotchas down the road?


回答 0

import module和之间的区别from module import foo主要是主观的。选择最喜欢的一个,并在使用中保持一致。这里有一些要点可以帮助您做出决定。

import module

  • 优点:
    • 减少您的import报表维护。无需添加任何其他导入即可开始使用模块中的另一个项目
  • 缺点:
    • 输入module.foo代码可能既乏味又多余(可以通过使用import module as mo然后键入来最小化乏味mo.foo

from module import foo

  • 优点:
    • 减少打字使用 foo
    • 更好地控制可以访问模块的哪些项目
  • 缺点:
    • 要使用模块中的新项目,您必须更新import语句
    • 您会失去有关的信息foo。例如,ceil()math.ceil()

两种方法都可以接受,但不要使用from module import *

对于任何合理的大型代码集,如果您import *可能会将其固定在模块中,则无法删除。这是因为很难确定代码中使用的哪些项来自“模块”,这很容易达到您认为不再使用它们的地步,import但是很难确定。

The difference between import module and from module import foo is mainly subjective. Pick the one you like best and be consistent in your use of it. Here are some points to help you decide.

import module

  • Pros:
    • Less maintenance of your import statements. Don’t need to add any additional imports to start using another item from the module
  • Cons:
    • Typing module.foo in your code can be tedious and redundant (tedium can be minimized by using import module as mo then typing mo.foo)

from module import foo

  • Pros:
    • Less typing to use foo
    • More control over which items of a module can be accessed
  • Cons:
    • To use a new item from the module you have to update your import statement
    • You lose context about foo. For example, it’s less clear what ceil() does compared to math.ceil()

Either method is acceptable, but don’t use from module import *.

For any reasonable large set of code, if you import * you will likely be cementing it into the module, unable to be removed. This is because it is difficult to determine what items used in the code are coming from ‘module’, making it easy to get to the point where you think you don’t use the import any more but it’s extremely difficult to be sure.


回答 1

这里还有另一个细节,未提及,与写入模块有关。当然,这可能不是很常见,但是我不时需要它。

由于引用和名称绑定在Python中的工作方式,如果您想从该模块外部更新模块中的某些符号(例如foo.bar),并且要更改其他导入代码“ see”,则必须导入foo a某种方式。例如:

模块foo:

bar = "apples"

模块a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

模块b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

但是,如果导入符号名称而不是模块名称,则将无法使用。

例如,如果我在模块a中这样做:

from foo import bar
bar = "oranges"

a之外的任何代码都不会将bar视为“橙色”,因为我对bar的设置仅影响模块a中的名称“ bar”,它没有“进入” foo模块对象并更新其“ bar”。

There’s another detail here, not mentioned, related to writing to a module. Granted this may not be very common, but I’ve needed it from time to time.

Due to the way references and name binding works in Python, if you want to update some symbol in a module, say foo.bar, from outside that module, and have other importing code “see” that change, you have to import foo a certain way. For example:

module foo:

bar = "apples"

module a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

module b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

However, if you import symbol names instead of module names, this will not work.

For example, if I do this in module a:

from foo import bar
bar = "oranges"

No code outside of a will see bar as “oranges” because my setting of bar merely affected the name “bar” inside module a, it did not “reach into” the foo module object and update its “bar”.


回答 2

尽管已经有很多人对importvs进行了解释import from,但我还是想尝试多解释一些关于幕后发生的事情以及它发生的所有变化的位置。


import foo

导入foo,并在当前命名空间中创建对该模块的引用。然后,您需要定义完整的模块路径,以从模块内部访问特定的属性或方法。

例如foo.bar但不是bar

from foo import bar

导入foo,并创建对列出的所有成员(bar)的引用。不设置变量foo

例如bar但不是bazfoo.baz

from foo import *

导入foo并创建对该模块在当前命名空间中定义的所有公共对象的引用(__all__如果__all__存在,则列出的所有对象,否则所有不以开头的对象_)。不设置变量foo

例如barbaz但不是_quxfoo._qux


现在让我们看看我们何时进行操作import X.Y

>>> import sys
>>> import os.path

检查sys.modules名称osos.path

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

使用和检查globals()locals()命名空间字典:osos.path

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

从上面的示例中,我们发现仅os在本地和全局命名空间中插入了。因此,我们应该能够使用:

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

但是不是path

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

os从locals()命名空间删除后,将无法访问它们osos.path即使它们存在于sys.modules中:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

现在让我们谈谈import from

from

>>> import sys
>>> from os import path

sys.modulesos和检查os.path

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

我们发现,sys.modules通过使用与以前相同import name

OK,让我们检查一下它的外观locals()globals()命名空间字典:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

您可以使用名称访问,path而不能使用os.path

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

让我们从中删除“路径” locals()

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

最后一个使用别名的示例:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

而且没有定义路径:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

Even though many people already explained about import vs import from, I want to try to explain a bit more about what happens under the hood, and where all the places it changes are.


import foo:

Imports foo, and creates a reference to that module in the current namespace. Then you need to define completed module path to access a particular attribute or method from inside the module.

E.g. foo.bar but not bar

from foo import bar:

Imports foo, and creates references to all the members listed (bar). Does not set the variable foo.

E.g. bar but not baz or foo.baz

from foo import *:

Imports foo, and creates references to all public objects defined by that module in the current namespace (everything listed in __all__ if __all__ exists, otherwise everything that doesn’t start with _). Does not set the variable foo.

E.g. bar and baz but not _qux or foo._qux.


Now let’s see when we do import X.Y:

>>> import sys
>>> import os.path

Check sys.modules with name os and os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Check globals() and locals() namespace dicts with os and os.path:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

From the above example we found that only os is inserted in the local and global namespace. So, we should be able to use:

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

But not path.

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Once you delete the os from locals() namespace, you won’t be able to access os as well as os.path even though they exist in sys.modules:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Now let’s talk about import from:

from:

>>> import sys
>>> from os import path

Check sys.modules with os and os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

We found that in sys.modules we found as same as we did before by using import name

OK, let’s check how it looks like in locals() and globals() namespace dicts:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

You can access by using name path not by os.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Let’s delete ‘path’ from locals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

One final example using an alias:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

And no path defined:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

回答 3

两种方法都受支持是有原因的:有时候,一种方法比另一种更合适。

  • import module:当您使用模块中的许多位时很好。缺点是您需要使用模块名称来限定每个引用。

  • from module import ...:很高兴导入的项目无需模块名称前缀即可直接使用。缺点是您必须列出您使用的每件事,并且在代码中不清楚来源。

使用哪种方法取决于使代码清晰易读的方式,并且与个人喜好有关。我倾向于import module一般,因为在代码中很清楚对象或函数的来源。我在代码中大量from module import ...使用某些对象/函数时使用。

Both ways are supported for a reason: there are times when one is more appropriate than the other.

  • import module: nice when you are using many bits from the module. drawback is that you’ll need to qualify each reference with the module name.

  • from module import ...: nice that imported items are usable directly without module name prefix. The drawback is that you must list each thing you use, and that it’s not clear in code where something came from.

Which to use depends on which makes the code clear and readable, and has more than a little to do with personal preference. I lean toward import module generally because in the code it’s very clear where an object or function came from. I use from module import ... when I’m using some object/function a lot in the code.


回答 4

我个人总是使用

from package.subpackage.subsubpackage import module

然后以

module.function
module.modulevar

原因是同时有简短的调用,并且您清楚地定义了每个例程的模块命名空间,如果您必须在源代码中搜索给定模块的用法,这很有用。

不用说,不要使用import *,因为它会污染您的命名空间,并且不会告诉您给定函数的来源(来自哪个模块)

当然,如果两个不同软件包中的两个不同模块具有相同的模块名称,则可能会遇到麻烦。

from package1.subpackage import module
from package2.subpackage import module

在这种情况下,您当然会遇到麻烦,但是有一个强烈的暗示,即您的程序包布局存在缺陷,您必须重新考虑它。

I personally always use

from package.subpackage.subsubpackage import module

and then access everything as

module.function
module.modulevar

etc. The reason is that at the same time you have short invocation, and you clearly define the module namespace of each routine, something that is very useful if you have to search for usage of a given module in your source.

Needless to say, do not use the import *, because it pollutes your namespace and it does not tell you where a given function comes from (from which module)

Of course, you can run in trouble if you have the same module name for two different modules in two different packages, like

from package1.subpackage import module
from package2.subpackage import module

in this case, of course you run into troubles, but then there’s a strong hint that your package layout is flawed, and you have to rethink it.


回答 5

import module

当您将使用模块中的许多功能时,最好。

from module import function

当您只想避免使用模块中的所有函数和类型污染全局命名空间时,这是最好的选择function

import module

Is best when you will use many functions from the module.

from module import function

Is best when you want to avoid polluting the global namespace with all the functions and types from a module when you only need function.


回答 6

我刚刚发现了这两种方法之间的另一个细微差别。

如果模块foo使用以下导入:

from itertools import count

然后,模块bar可能会错误地使用count,就好像它是在中定义的foo,而不是在中定义的itertools

import foo
foo.count()

如果foo使用:

import itertools

该错误仍然可能,但不太可能发生。bar需要:

import foo
foo.itertools.count()

这给我带来了麻烦。我有一个模块,该模块错误地从未定义异常的模块导入了异常,而仅从其他模块(使用from module import SomeException)导入了异常。当不再需要导入并将其删除时,损坏的模块将被破坏。

I’ve just discovered one more subtle difference between these two methods.

If module foo uses a following import:

from itertools import count

Then module bar can by mistake use count as though it was defined in foo, not in itertools:

import foo
foo.count()

If foo uses:

import itertools

the mistake is still possible, but less likely to be made. bar needs to:

import foo
foo.itertools.count()

This caused some troubles to me. I had a module that by mistake imported an exception from a module that did not define it, only imported it from other module (using from module import SomeException). When the import was no longer needed and removed, the offending module was broken.


回答 7

这是另一个未提及的区别。这是从http://docs.python.org/2/tutorial/modules.html逐字复制的

请注意,使用时

from package import item

该项目可以是包的子模块(或子包),也可以是包中定义的其他名称,例如函数,类或变量。import语句首先测试项目是否在包装中定义;如果不是,则假定它是一个模块并尝试加载它。如果找不到它,则会引发ImportError异常。

相反,当使用类似

import item.subitem.subsubitem

除最后一个项目外,每个项目都必须是一个包装;最后一项可以是模块或包,但不能是上一项中定义的类或函数或变量。

Here is another difference not mentioned. This is copied verbatim from http://docs.python.org/2/tutorial/modules.html

Note that when using

from package import item

the item can be either a submodule (or subpackage) of the package, or some other name defined in the package, like a function, class or variable. The import statement first tests whether the item is defined in the package; if not, it assumes it is a module and attempts to load it. If it fails to find it, an ImportError exception is raised.

Contrarily, when using syntax like

import item.subitem.subsubitem

each item except for the last must be a package; the last item can be a module or a package but can’t be a class or function or variable defined in the previous item.


回答 8

由于我还是初学者,因此我将尝试以一种简单的方式来解释这一点:在Python中,我们有三种类型的import语句,它们是:

1.通用进口:

import math

这种类型的导入是我个人的最爱,这种导入技术的唯一缺点是,如果需要使用任何模块的功能,则必须使用以下语法:

math.sqrt(4)

当然,它会增加打字的工作量,但是作为一个初学者,它将帮助您跟踪与之相关的模块和功能(一个好的文本编辑器将大大减少打字的工作量,建议使用)。

使用以下import语句可以进一步减少打字工作:

import math as m

现在,math.sqrt()可以使用代替使用m.sqrt()

2.函数导入:

from math import sqrt

如果您的代码只需要访问模块中的单个或几个函数,而要使用模块中的任何新项,则必须更新import语句,则这种类型的导入最适合。

3.普遍进口:

from math import * 

尽管它可以显着减少键入工作,但是不建议这样做,因为它将用模块中的各种函数填充代码,并且它们的名称可能与用户定义函数的名称冲突。 例:

如果您有自己的名为sqrt的函数并且导入了数学运算,则该函数是安全的:存在您的sqrt和Math.sqrt。但是,如果从数学导入*进行操作,则会遇到问题:即,两个具有相同名称的不同函数。资料来源:Codecademy

Since I am also a beginner, I will be trying to explain this in a simple way: In Python, we have three types of import statements which are:

1. Generic imports:

import math

this type of import is my personal favorite, the only downside to this import technique is that if you need use any module’s function you must use the following syntax:

math.sqrt(4)

of course, it increases the typing effort but as a beginner, it will help you to keep track of module and function associated with it, (a good text editor will reduce the typing effort significantly and is recommended).

Typing effort can be further reduced by using this import statement:

import math as m

now, instead of using math.sqrt() you can use m.sqrt().

2. Function imports:

from math import sqrt

this type of import is best suited if your code only needs to access single or few functions from the module, but for using any new item from the module you have to update import statement.

3. Universal imports:

from math import * 

Although it reduces typing effort significantly but is not recommended because it will fill your code with various functions from the module and their name could conflict with the name of user-defined functions. example:

If you have a function of your very own named sqrt and you import math, your function is safe: there is your sqrt and there is math.sqrt. If you do from math import *, however, you have a problem: namely, two different functions with the exact same name. Source: Codecademy


回答 9

import package
import module

使用import,令牌必须是模块(包含Python命令的文件)或包(sys.path包含文件的文件夹__init__.py)。

有子包时:

import package1.package2.package
import package1.package2.module

为文件夹(封装)或文件(模块)的要求是相同的,但该文件夹或文件必须是内部package2必须是内部package1,并且两个package1package2必须包含__init__.py文件。https://docs.python.org/2/tutorial/modules.html

具有from导入样式:

from package1.package2 import package
from package1.package2 import module

程序包或模块将输入包含import语句的文件的命名空间用module(或package)代替package1.package2.module。您始终可以绑定到更方便的名称:

a = big_package_name.subpackage.even_longer_subpackage_name.function

只有from导入样式允许您命名特定的函数或变量:

from package3.module import some_function

被允许,但是

import package3.module.some_function 

不被允许。

import package
import module

With import, the token must be a module (a file containing Python commands) or a package (a folder in the sys.path containing a file __init__.py.)

When there are subpackages:

import package1.package2.package
import package1.package2.module

the requirements for folder (package) or file (module) are the same, but the folder or file must be inside package2 which must be inside package1, and both package1 and package2 must contain __init__.py files. https://docs.python.org/2/tutorial/modules.html

With the from style of import:

from package1.package2 import package
from package1.package2 import module

the package or module enters the namespace of the file containing the import statement as module (or package) instead of package1.package2.module. You can always bind to a more convenient name:

a = big_package_name.subpackage.even_longer_subpackage_name.function

Only the from style of import permits you to name a particular function or variable:

from package3.module import some_function

is allowed, but

import package3.module.some_function 

is not allowed.


回答 10

补充说一下from x import *:除了使人更难分辨名称的来源之外,还抛出了像Pylint这样的代码检查器。他们会将这些名称报告为未定义的变量。

To add to what people have said about from x import *: besides making it more difficult to tell where names came from, this throws off code checkers like Pylint. They will report those names as undefined variables.


回答 11

我自己的答案主要取决于首先要使用的模块数量。如果我只使用一两个,那么我将经常使用from…,import因为它使文件其余部分的击键次数减少,但是如果我要使用许多不同的模块,我更喜欢import因为这意味着每个模块引用都是自记录的。我可以看到每个符号的来源,而不必四处寻找。

通常,我更喜欢纯文本导入的自我记录样式,仅当要输入的模块名称次数超过10到20时才更改为from .. import,即使只有一个模块被导入。

My own answer to this depends mostly on first, how many different modules I’ll be using. If i’m only going to use one or two, I’ll often use fromimport since it makes for fewer keystrokes in the rest of the file, but if I’m going to make use of many different modules, I prefer just import because that means that each module reference is self-documenting. I can see where each symbol comes from without having to hunt around.

Usuaully I prefer the self documenting style of plain import and only change to from.. import when the number of times I have to type the module name grows above 10 to 20, even if there’s only one module being imported.


回答 12

其中一个显著差异,我发现它的出奇,没有人一直在谈论的是使用纯进口,您可以访问private variableprivate functions从导入模块,这是不可能的从导入语句。

图片中的代码:

setting.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

One of the significant difference I found out which surprisingly no-one has talked about is that using plain import you can access private variable and private functions from the imported module, which isn’t possible with from-import statement.

Code in image:

setting.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

回答 13

导入模块-您无需付出额外的努力即可从模块中获取其他东西。它具有诸如冗余键入之类的缺点

从模块导入-减少键入操作,更多地控制可以访问模块的项目。要使用模块中的新项目,必须更新导入语句。

Import Module – You don’t need additional efforts to fetch another thing from module. It has disadvantages such as redundant typing

Module Import From – Less typing &More control over which items of a module can be accessed.To use a new item from the module you have to update your import statement.


回答 14

有一些内置模块主要包含裸函数(base64mathosshutilsystime等),将这些裸函数绑定到某些命名空间绝对是一个好习惯,从而提高了您的可读性码。考虑没有这些命名空间的情况下,理解这些功能的含义会更加困难:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

而不是将它们绑定到某个模块时:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

有时甚至需要命名空间来避免不同模块之间的冲突(json.loadpickle.load


另一方面,有些模块主要包含类(configparserdatetimetempfilezipfile,…),其中许多模块使类名变得不言而喻:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

因此,在将这些类与代码中的其他模块命名空间一起使用时是否存在争议,是否会增加一些新信息还是仅仅是延长代码长度,就存在争议。

There are some builtin modules that contain mostly bare functions (base64, math, os, shutil, sys, time, …) and it is definitely a good practice to have these bare functions bound to some namespace and thus improve the readability of your code. Consider how more difficult is to understand the meaning of these functions without their namespace:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

than when they are bound to some module:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

Sometimes you even need the namespace to avoid conflicts between different modules (json.load vs. pickle.load)


On the other hand there are some modules that contain mostly classes (configparser, datetime, tempfile, zipfile, …) and many of them make their class names self-explanatory enough:
configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

so there can be a debate whether using these classes with the additional module namespace in your code adds some new information or just lengthens the code.


回答 15

我想补充一点,在导入调用期间需要考虑一些事项:

我有以下结构:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis显示了不同之处:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

最后,它们看起来相同(每个示例中的结果都是STORE_NAME),但是值得注意的是,如果您需要考虑以下四个循环导入:

例子1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

这有效

例子2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

没有骰子

例子3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

类似的问题…但是从x import y明显不同于与import import xy和y相同

例子4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

这个也可以

I would like to add to this, there are somethings to consider during the import calls:

I have the following structure:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis shows the difference:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

In the end they look the same (STORE_NAME is result in each example), but this is worth noting if you need to consider the following four circular imports:

example1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

This works

example2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

No dice

example3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

Similar issue… but clearly from x import y is not the same as import import x.y as y

example4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

This one also works


回答 16

这是我当前目录的目录结构:

.  
└─a  
   └─b  
     └─c
  1. import语句会记住所有中间名称
    这些名称必须是合格的:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
  2. from ... import ...语句记住导入的名称
    此名称不能为限定名称:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>

  • 注意:当然,我在步骤1和2之间重新启动了Python控制台。

This is my directory structure of my current directory:

.  
└─a  
   └─b  
     └─c
  1. The import statement remembers all intermediate names.
    These names have to be qualified:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
    
  2. The from ... import ... statement remembers only the imported name.
    This name must not be qualified:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>
    

  • Note: Of course, I restarted my Python console between steps 1 and 2.

回答 17

正如Jan Wrobel所提到的,不同进口的一个方面是进口的公开方式。

模块神话

from math import gcd
...

使用神话

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

如果我gcd仅为内部使用而导入,而不是向的用户公开mymath,可能会带来不便。我经常遇到这种情况,在大多数情况下,我想“保持模块清洁”。

除了扬·沃伯Jan Wrobel)提议通过使用import math来进一步掩盖这一点之外,我还开始使用领先的下划线来掩盖进口的隐瞒:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

在较大的项目中,这种“最佳实践”使我能够精确控制后续进口中公开的内容和未公开内容。这样可以使我的模块保持清洁,并以一定规模的项目回报。

As Jan Wrobel mentions, one aspect of the different imports is in which way the imports are disclosed.

Module mymath

from math import gcd
...

Use of mymath:

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

If I imported gcd only for internal use, not to disclose it to users of mymath, this can be inconvenient. I have this pretty often, and in most cases I want to “keep my modules clean”.

Apart from the proposal of Jan Wrobel to obscure this a bit more by using import math instead, I have started to hide imports from disclosure by using a leading underscore:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

In larger projects this “best practice” allows my to exactly control what is disclosed to subsequent imports and what isn’t. This keeps my modules clean and pays back at a certain size of project.


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

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

我在python 3中有以下代码:

class Position:

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

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

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

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

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

I have the following code in python 3:

class Position:

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

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

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

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

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


回答 0

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

我猜你有这个exceptions:

NameError: name 'Position' is not defined

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

Python 3.7+: from __future__ import annotations

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

from __future__ import annotations

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

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

Python <3.7:使用字符串

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

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

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

资料来源

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

转发参考

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

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

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

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

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

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

和PEP 563:

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

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

from __future__ import annotations

您可能会想做的事情

A.定义一个假人 Position

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

class Position(object):
    pass


class Position(object):
    ...

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

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

但是吗?

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

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

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

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

装饰者应对此负责:

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

至少看起来是正确的:

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

可能麻烦太多了。

结论

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

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

I guess you got this exception:

NameError: name 'Position' is not defined

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

Python 3.7+: from __future__ import annotations

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

from __future__ import annotations

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

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

Python <3.7: use a string

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

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

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

Sources

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

Forward references

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

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

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

To address this, we write:

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

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

and PEP 563:

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

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

from __future__ import annotations

Things that you may be tempted to do instead

A. Define a dummy Position

Before the class definition, place a dummy definition:

class Position(object):
    pass


class Position(object):
    ...

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

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

But is it?

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

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

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

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

The decorator should be responsible for the equivalent of this:

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

At least it seems right:

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

Probably too much trouble.

Conclusion

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


回答 1

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

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

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

from typing import TypeVar

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

class Position:

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

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

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

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

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

from typing import TypeVar

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

class Position:

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

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

回答 2

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

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

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

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

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

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

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

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


回答 3

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

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

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

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

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

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


Python中exit()和sys.exit()之间的区别

问题:Python中exit()和sys.exit()之间的区别

在Python中,有两个类似的函数,exit()sys.exit()。有什么区别,何时应在另一个上使用?

In Python, there are two similarly-named functions, exit() and sys.exit(). What’s the difference and when should I use one over the other?


回答 0

exit是交互式外壳的帮助sys.exit程序- 旨在在程序中使用。

site模块(启动时会自动导入,除非指定了-S命令行选项)会向内置命名空间(例如exit添加多个常量。它们对于交互式解释程序外壳很有用,不应在程序中使用


从技术上讲,它们的作用大致相同:提高SystemExitsys.exitsysmodule.c中这样

static PyObject *
sys_exit(PyObject *self, PyObject *args)
{
    PyObject *exit_code = 0;
    if (!PyArg_UnpackTuple(args, "exit", 0, 1, &exit_code))
        return NULL;
    /* Raise SystemExit so callers may catch it or clean up. */
    PyErr_SetObject(PyExc_SystemExit, exit_code);
   return NULL;
}

虽然分别exitsite.py_sitebuiltins.py中定义。

class Quitter(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Use %s() or %s to exit' % (self.name, eof)
    def __call__(self, code=None):
        # Shells like IDLE catch the SystemExit, but listen when their
        # stdin wrapper is closed.
        try:
            sys.stdin.close()
        except:
            pass
        raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')

请注意,还有第三个退出选项os._exit,它退出时不调用清除处理程序,刷新stdio缓冲区等(并且通常仅应在之后的子进程中使用fork())。

exit is a helper for the interactive shell – sys.exit is intended for use in programs.

The site module (which is imported automatically during startup, except if the -S command-line option is given) adds several constants to the built-in namespace (e.g. exit). They are useful for the interactive interpreter shell and should not be used in programs.


Technically, they do mostly the same: raising SystemExit. sys.exit does so in sysmodule.c:

static PyObject *
sys_exit(PyObject *self, PyObject *args)
{
    PyObject *exit_code = 0;
    if (!PyArg_UnpackTuple(args, "exit", 0, 1, &exit_code))
        return NULL;
    /* Raise SystemExit so callers may catch it or clean up. */
    PyErr_SetObject(PyExc_SystemExit, exit_code);
   return NULL;
}

While exit is defined in site.py and _sitebuiltins.py, respectively.

class Quitter(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Use %s() or %s to exit' % (self.name, eof)
    def __call__(self, code=None):
        # Shells like IDLE catch the SystemExit, but listen when their
        # stdin wrapper is closed.
        try:
            sys.stdin.close()
        except:
            pass
        raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')

Note that there is a third exit option, namely os._exit, which exits without calling cleanup handlers, flushing stdio buffers, etc. (and which should normally only be used in the child process after a fork()).


回答 1

如果我exit()在代码中使用并在外壳中运行它,则会显示一条消息,询问我是否要终止该程序。真是令人不安。 看这里

但是sys.exit()在这种情况下更好。它关闭程序,并且不创建任何对话框。

If I use exit() in a code and run it in the shell, it shows a message asking whether I want to kill the program or not. It’s really disturbing. See here

But sys.exit() is better in this case. It closes the program and doesn’t create any dialogue box.


如何在Flask上获取查询字符串?

问题:如何在Flask上获取查询字符串?

从烧瓶文档中关于如何获取查询字符串的知识并不明显。我是新手,看了看文档,找不到!

所以

@app.route('/')
@app.route('/data')
def data():
    query_string=??????
    return render_template("data.html")

Not obvious from the flask documention on how to get the query string. I am new, looked at the docs, could not find!

So

@app.route('/')
@app.route('/data')
def data():
    query_string=??????
    return render_template("data.html")

回答 0

from flask import request

@app.route('/data')
def data():
    # here we want to get the value of user (i.e. ?user=some-value)
    user = request.args.get('user')
from flask import request

@app.route('/data')
def data():
    # here we want to get the value of user (i.e. ?user=some-value)
    user = request.args.get('user')

回答 1

完整URL可用request.url,而查询字符串可用request.query_string

这是一个例子:

from flask import request

@app.route('/adhoc_test/')
def adhoc_test():

    return request.query_string

要访问在查询字符串中传递的单个已知参数,可以使用request.args.get('param')。据我所知,这是“正确”的方法。

ETA:在继续之前,您应该问自己为什么要查询字符串。我从来没有拉过原始字符串-Flask具有以抽象方式访问它的机制。除非您有令人信服的理由不使用,否则应使用它们。

The full URL is available as request.url, and the query string is available as request.query_string.

Here’s an example:

from flask import request

@app.route('/adhoc_test/')
def adhoc_test():

    return request.query_string

To access an individual known param passed in the query string, you can use request.args.get('param'). This is the “right” way to do it, as far as I know.

ETA: Before you go further, you should ask yourself why you want the query string. I’ve never had to pull in the raw string – Flask has mechanisms for accessing it in an abstracted way. You should use those unless you have a compelling reason not to.


回答 2

Werkzeug / Flask已经为您解析了所有内容。无需使用urlparse再次执行相同的工作:

from flask import request

@app.route('/')
@app.route('/data')
def data():
    query_string = request.query_string  ## There is it
    return render_template("data.html")

有关请求和响应对象的完整文档,请参见Werkzeug:http : //werkzeug.pocoo.org/docs/wrappers/

Werkzeug/Flask as already parsed everything for you. No need to do the same work again with urlparse:

from flask import request

@app.route('/')
@app.route('/data')
def data():
    query_string = request.query_string  ## There is it
    return render_template("data.html")

The full documentation for the request and response objects is in Werkzeug: http://werkzeug.pocoo.org/docs/wrappers/


回答 3

我们可以使用request.query_string做到这一点。

例:

让我们考虑view.py

from my_script import get_url_params

@app.route('/web_url/', methods=('get', 'post'))
def get_url_params_index():
    return Response(get_url_params())

您还可以通过使用Flask蓝图使它更具模块化-http: //flask.pocoo.org/docs/0.10/blueprints/

让我们考虑将名字作为查询字符串/ web_url /?first_name = john的一部分进行传递

## here is my_script.py

## import required flask packages
from flask import request
def get_url_params():
    ## you might further need to format the URL params through escape.    
    firstName = request.args.get('first_name') 
    return firstName

如您所见,这只是一个小例子-您可以获取多个值+为其赋值,然后使用它或将其传递到模板文件中。

We can do this by using request.query_string.

Example:

Lets consider view.py

from my_script import get_url_params

@app.route('/web_url/', methods=('get', 'post'))
def get_url_params_index():
    return Response(get_url_params())

You also make it more modular by using Flask Blueprints – http://flask.pocoo.org/docs/0.10/blueprints/

Lets consider first name is being passed as a part of query string /web_url/?first_name=john

## here is my_script.py

## import required flask packages
from flask import request
def get_url_params():
    ## you might further need to format the URL params through escape.    
    firstName = request.args.get('first_name') 
    return firstName

As you see this is just a small example – you can fetch multiple values + formate those and use it or pass it onto the template file.


回答 4

我来这里是在寻找查询字符串,而不是如何从查询字符串获取值。

request.query_string 返回URL参数作为原始字节字符串(参考文献1)。

使用示例request.query_string

from flask import Flask, request

app = Flask(__name__)

@app.route('/data', methods=['GET'])
def get_query_string():
    return request.query_string

if __name__ == '__main__':
    app.run(debug=True)

输出:

参考文献:

  1. 有关query_string的官方API文档

I came here looking for the query string, not how to get values from the query string.

request.query_string returns the URL parameters as raw byte string (Ref 1).

Example of using request.query_string:

from flask import Flask, request

app = Flask(__name__)

@app.route('/data', methods=['GET'])
def get_query_string():
    return request.query_string

if __name__ == '__main__':
    app.run(debug=True)

Output:

References:

  1. Official API documentation on query_string

回答 5

像这样尝试查询字符串:

from flask import Flask, request

app = Flask(__name__)

@app.route('/parameters', methods=['GET'])
def query_strings():

    args1 = request.args['args1']
    args2 = request.args['args2']
    args3 = request.args['args3']

    return '''<h1>The Query String are...{}:{}:{}</h1>''' .format(args1,args2,args3)


if __name__ == '__main__':

    app.run(debug=True)

输出:

Try like this for query string:

from flask import Flask, request

app = Flask(__name__)

@app.route('/parameters', methods=['GET'])
def query_strings():

    args1 = request.args['args1']
    args2 = request.args['args2']
    args3 = request.args['args3']

    return '''<h1>The Query String are...{}:{}:{}</h1>''' .format(args1,args2,args3)


if __name__ == '__main__':

    app.run(debug=True)

Output:


回答 6

O’Reilly Flask Web开发中所述,可以从烧瓶请求对象中检索每种形式的查询字符串:

O’Reilly Flask Web开发,如Manan Gouhari先前所述,首先,您需要导入请求:

from flask import request

request是Flask公开的对象,它是一个名为(您猜对了)的上下文变量request。顾名思义,它包含客户端包含在HTTP请求中的所有信息。该对象具有许多可以分别检索和调用的属性和方法。

您有很多request属性,其中包含要选择的查询字符串。在这里,我将列出以任何方式包含查询字符串的每个属性,以及O’Reilly对该书的描述。

首先args是“字典,其中所有参数都在URL的查询字符串中传递”。因此,如果要将查询字符串解析为字典,则可以执行以下操作:

from flask import request

@app.route('/'):
    queryStringDict = request.args

(正如其他人指出的,您也可以使用.get('<arg_name>')从字典中获取特定值)

然后,有form属性,它确实包含查询字符串,但它包含在另一个属性的部分包括查询字符串,我将立即上市。不过,首先form是“具有随请求一起提交的所有表单字段的字典”。我这么说是:烧瓶请求对象中还有另一个字典属性可用valuesvalues是“结合了form和中的值的字典args。” 检索将类似于以下内容:

from flask import request

@app.route('/'):
    formFieldsAndQueryStringDict = request.values

(再次,用于.get('<arg_name>')从字典中获取特定项目)

另一个选项是query_string“ URL的查询字符串部分,作为原始二进制值”。例子:

from flask import request

@app.route('/'):
    queryStringRaw = request.query_string

然后,还有一个额外的好处full_path是“ URL的路径和查询字符串部分”。通过ejemplo:

from flask import request

@app.route('/'):
    pathWithQueryString = request.full_path

最后,url“客户端请求的完整URL”(包括查询字符串):

from flask import request

@app.route('/'):
    pathWithQueryString = request.url

快乐黑客:)

Every form of the query string retrievable from flask request object as described in O’Reilly Flask Web Devleopment:

From O’Reilly Flask Web Development, and as stated by Manan Gouhari earlier, first you need to import request:

from flask import request

request is an object exposed by Flask as a context variable named (you guessed it) request. As its name suggests, it contains all the information that the client included in the HTTP request. This object has many attributes and methods that you can retrieve and call, respectively.

You have quite a few request attributes which contain the query string from which to choose. Here I will list every attribute that contains in any way the query string, as well as a description from the O’Reilly book of that attribute.

First there is args which is “a dictionary with all the arguments passed in the query string of the URL.” So if you want the query string parsed into a dictionary, you’d do something like this:

from flask import request

@app.route('/'):
    queryStringDict = request.args

(As others have pointed out, you can also use .get('<arg_name>') to get a specific value from the dictionary)

Then, there is the form attribute, which does not contain the query string, but which is included in part of another attribute that does include the query string which I will list momentarily. First, though, form is “A dictionary with all the form fields submitted with the request.” I say that to say this: there is another dictionary attribute available in the flask request object called values. values is “A dictionary that combines the values in form and args.” Retrieving that would look something like this:

from flask import request

@app.route('/'):
    formFieldsAndQueryStringDict = request.values

(Again, use .get('<arg_name>') to get a specific item out of the dictionary)

Another option is query_string which is “The query string portion of the URL, as a raw binary value.” Example of that:

from flask import request

@app.route('/'):
    queryStringRaw = request.query_string

Then as an added bonus there is full_path which is “The path and query string portions of the URL.” Por ejemplo:

from flask import request

@app.route('/'):
    pathWithQueryString = request.full_path

And finally, url, “The complete URL requested by the client” (which includes the query string):

from flask import request

@app.route('/'):
    pathWithQueryString = request.url

Happy hacking :)


回答 7

可以使用来完成request.args.get()。例如,如果您的查询字符串包含字段date,则可以使用进行访问

date = request.args.get('date')

别忘了request在烧瓶的导入列表中添加“ ”,即

from flask import request

This can be done using request.args.get(). For example if your query string has a field date, it can be accessed using

date = request.args.get('date')

Don’t forget to add “request” to list of imports from flask, i.e.

from flask import request

回答 8

如果请求为GET并且我们传递了一些查询参数,

fro`enter code here`m flask import request
@app.route('/')
@app.route('/data')
def data():
   if request.method == 'GET':
      # Get the parameters by key
      arg1 = request.args.get('arg1')
      arg2 = request.args.get('arg2')
      # Generate the query string
      query_string="?arg1={0}&arg2={1}".format(arg1, arg2)
      return render_template("data.html", query_string=query_string)

If the request if GET and we passed some query parameters then,

fro`enter code here`m flask import request
@app.route('/')
@app.route('/data')
def data():
   if request.method == 'GET':
      # Get the parameters by key
      arg1 = request.args.get('arg1')
      arg2 = request.args.get('arg2')
      # Generate the query string
      query_string="?arg1={0}&arg2={1}".format(arg1, arg2)
      return render_template("data.html", query_string=query_string)

bash:pip:找不到命令

问题:bash:pip:找不到命令

我下载了pip并运行python setup.py install,一切正常。本教程的下一步是运行,pip install <lib you want>但是甚至在尝试在线查找任何内容之前,我都会收到错误消息“ bash:pip:not found”。

这是在Mac OS X上,这也是我的新手,因此我假设有些路径设置在运行setup.py时未正确设置。我该如何进一步调查?我需要检查什么才能更好地了解问题的确切原因?

编辑:我也尝试过为Mac安装Python 2.7,希望友好的安装过程能够完成所有工作,例如编辑PATH,以及根据教程使一切正常工作所需的其他一切,但这是行不通的。安装运行后,“ python”仍然运行python 2.6,并且PATH未更新。

I downloaded pip and ran python setup.py install and everything worked just fine. The very next step in the tutorial is to run pip install <lib you want> but before it even tries to find anything online I get an error “bash: pip: command not found”.

This is on Mac OS X, which I’m new too, so I’m assuming there’s some kind of path setting that was not set correctly when I ran setup.py. How can I investigate further? What do I need to check to get a better idea of the exact cause of the problem?

EDIT: I also tried installing Python 2.7 for Mac in the hopes that the friendly install process would do any housekeeping like editing PATH and whatever else needs to happy for everything to work according to the tutorials, but this didn’t work. After installing is running ‘python’ still ran Python 2.6 and PATH was not updated.


回答 0

为什么不这样做,sudo easy_install pip或者这是否适用于python 2.6 sudo easy_install-2.6 pip

这将使用默认的python软件包安装程序系统安装pip,并同时为您节省了手动设置的麻烦。

这将允许您运行pippython软件包安装命令,因为它将与系统python一起安装。我也建议您在使用virtualenv软件包和模式时获得点子。:)

Why not just do sudo easy_install pip or if this is for python 2.6 sudo easy_install-2.6 pip?

This installs pip using the default python package installer system and saves you the hassle of manual set-up all at the same time.

This will allow you to then run the pip command for python package installation as it will be installed with the system python. I also recommend once you have pip using the virtualenv package and pattern. :)


回答 1

使用setuptools安装pip

sudo easy_install pip

(我知道答案的上面部分对于klobucar来说是多余的,但是我还不能添加评论),所以这是一个解决方案 sudo: easy_install: command not found关于Debian / Ubuntu:

sudo apt-get install python-setuptools

另外,对于python3,请使用easy_install3python3-setuptools

Use setuptools to install pip:

sudo easy_install pip

(I know the above part of my answer is redundant with klobucar’s, but I can’t add comments yet), so here’s an answer with a solution to sudo: easy_install: command not found on Debian/Ubuntu:

sudo apt-get install python-setuptools

Also, for python3, use easy_install3 and python3-setuptools.


回答 2

首先:尝试使用pip3而不是pip。例:

pip3 --version
pip 9.0.1 from /usr/local/lib/python3.6/site-packages (python 3.6)

pip3应该与Python3.x一起自动安装。该文档尚未更新,因此例如在安装Flask时,将说明中的pip替换为pip3即可。

现在,如果这不起作用,则可能必须单独安装pip。

First of all: try pip3 instead of pip. Example:

pip3 --version
pip 9.0.1 from /usr/local/lib/python3.6/site-packages (python 3.6)

pip3 should be installed automatically together with Python3.x. The documentation hasn’t been updated, so simply replace pip by pip3 in the instructions, when installing Flask for example.

Now, if this doesn’t work, you might have to install pip separately.


回答 3

更新:访问正确的pip安装以进行正确的python安装的一种更可靠的现代方法是使用语法python -m pip

原始答案

pip会将其自身安装到您的python安装位置的bin中。它还应创建一个指向更常见位置的符号链接,例如/usr/local/bin/pip

您可以编辑~/.profilePATH并将其更新为include /Library/Frameworks/Python.framework/Versions/2.6/bin,也可以在路径中的已知位置创建指向它的符号链接。

如果您执行以下操作: echo $PATH,您应该看到当前正在搜索的路径。如果/usr/local/bin位于PATH中,则可以执行以下操作:

ln -s /Library/Frameworks/Python.framework/Versions/2.6/bin/pip /usr/local/bin

我会选择将python bin添加到$ PATH变量中。

Update: A more reliable modern way to access the right pip install for the right python install is to use the syntax python -m pip.

Original Answer

pip would install itself into the bin of your python installation location. It also should create a symlink to some more common location like /usr/local/bin/pip

You can either edit your ~/.profile and update your PATH to include /Library/Frameworks/Python.framework/Versions/2.6/bin, or you could create a symlink to it in a place that you know is in your path.

If you do: echo $PATH, you should see the paths currently being searched. If /usr/local/bin is in your PATH, you can do:

ln -s /Library/Frameworks/Python.framework/Versions/2.6/bin/pip /usr/local/bin

I would opt for adding the python bin to your $PATH variable.


回答 4

按照给定安装Python最新版本 这里

它具有许多下载链接,例如numpy和scipy

然后转到终端并输入以下命令:

sudo easy_install pip

对于Python安装包,请检查此

安装软件包的要求本节介绍在安装其他Python软件包之前应遵循的步骤。

安装pip,setuptools和wheel如果从python.org安装了Python 2> = 2.7.9或Python 3> = 3.4,则已经具有pip和setuptools,但需要升级到最新版本:

在Linux或OS X上:

pip install -U pip setuptools在Windows上:

python -m pip install -U pip setuptools如果您正在Linux上使用由系统软件包管理器(例如“ yum”,“ apt-get”等)管理的Python安装,并且您想使用系统软件包管理器要安装或升级pip,请参阅使用Linux软件包管理器安装pip / setuptools / wheel

除此以外:

安全下载get-pip.py 1

运行python get-pip.py。2这将安装或升级点子。另外,如果尚未安装setuptools和wheel,它将安装setuptools和wheel。

Install Python latest version as given here

It has many download links like numpy and scipy

Then go to terminal and enter following command:-

sudo easy_install pip

For Python install packages check this

Requirements for Installing Packages This section describes the steps to follow before installing other Python packages.

Install pip, setuptools, and wheel If you have Python 2 >=2.7.9 or Python 3 >=3.4 installed from python.org, you will already have pip and setuptools, but will need to upgrade to the latest version:

On Linux or OS X:

pip install -U pip setuptools On Windows:

python -m pip install -U pip setuptools If you’re using a Python install on Linux that’s managed by the system package manager (e.g “yum”, “apt-get” etc…), and you want to use the system package manager to install or upgrade pip, then see Installing pip/setuptools/wheel with Linux Package Managers

Otherwise:

Securely Download get-pip.py 1

Run python get-pip.py. 2 This will install or upgrade pip. Additionally, it will install setuptools and wheel if they’re not installed already.


回答 5

我必须承认对python绝对是新手,我只需要一件事:awscli。我在下载python 3.xx时遇到了这个问题-pip:命令未找到

遵循下载AWS CLI的说明后,我进行了更改

pip install awscli

pip3 install awscli

运行了正确的版本。

我在计算机上做了一个别名,以在输入python的同时运行python3,这通常会运行系统版本2.7。我现在不确定这是个好主意。我想我只是按照他们想要的那样输入命令

I have to admit to being absolutely new to python, which I only need for one thing: awscli. I encountered this problem having downloaded python 3.x.x – pip: command not found

Whilst following the instructions for downloading the AWS cli I changed

pip install awscli

to

pip3 install awscli

which ran the correct version.

I’ve made an alias on my machine to run python3 whilst typing python, which would normally run the system version 2.7. I’m not sure this is a good idea now. I think I’ll just type in the commands as they intended them to be


回答 6

请参阅“ 如何安装Pip”一文,以了解更多信息。

截至2019年,

提供下载get-pip.py https://pip.pypa.io使用下面的命令:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py

使用以下命令运行get-pip.py:
sudo python get-pip.py

完成安装后,运行此命令以检查是否安装了pip。
pip --version

安装pip后,删除get-pip.py文件。
rm get-pip.py

Check out How to Install Pip article article for more information.

As of 2019,

Download get-pip.py provided by https://pip.pypa.io using the following command:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py

Run get-pip.py using the following command:
sudo python get-pip.py

After you done installing, run this command to check if pip is installed.
pip --version

Remove get-pip.py file after installing pip.
rm get-pip.py


回答 7

使用apt-get安装会在整个系统范围内安装pip,而不仅仅是为您的用户安装本地系统。尝试使用此命令使pip在您的系统上运行…

$ sudo apt-get install python-pip python-dev build-essential

然后pip将被安装而没有任何问题,您将可以使用“ sudo pip …”。

Installing using apt-get installs a system wide pip, not just a local one for your user. Try this command to get pip running on your system …

$ sudo apt-get install python-pip python-dev build-essential

Then pip will be installed without any issues and you will be able to use “sudo pip…”.


回答 8

不推荐使用大多数安装PIP的方法。这是最新的(2019)解决方案。请下载get-pip脚本

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

运行脚本

sudo python get-pip.py

Most of the methods to install PIP are deprecated. Here is the latest (2019) solution. Please download get-pip script

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

Run the script

sudo python get-pip.py

回答 9

我花了很长时间浏览本页上的所有答案,但在s-walsh对OP问题的评论中找到了一个对我有用的

答案是使用pip3:

$ pip3 install <name-of-install>

I spent ages going through all the answers on this page but found the one that worked for me in the comments of the OP question by s-walsh

The answer is to use pip3:

$ pip3 install <name-of-install>

回答 10

解决:

  1. 将此行添加到〜/ .bash_profile

    导出PATH =“ / usr / local / bin:$ PATH”

  2. 在终端窗口中,运行

    来源〜/ .bash_profile

To solve:

  1. Add this line to ~/.bash_profile

    export PATH=”/usr/local/bin:$PATH”

  2. In a terminal window, run

    source ~/.bash_profile


回答 11

它可能是root权限。我尝试退出root登录,使用

sudo su -l root
pip <command>

这对我行得通

It might be the root permission. I tried exit root login, use

sudo su -l root
pip <command>

that works for me


回答 12

安装Homebrew,打开Terminal或您喜欢的OSX终端仿真器并运行

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

将Homebrew目录插入PATH环境变量的顶部。您可以通过在〜/ .profile文件底部添加以下行来完成此操作

export PATH=/usr/local/bin:/usr/local/sbin:$PATH

现在,我们可以安装Python 2.7:

$ brew install python

获取点子存储库:

$ git clone https://github.com/pypa/pip

安装点:

$sudo easy_install pip

install Homebrew, open Terminal or your favorite OSX terminal emulator and run

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

insert the Homebrew directory at the top of your PATH environment variable. You can do this by adding the following line at the bottom of your ~/.profile file

export PATH=/usr/local/bin:/usr/local/sbin:$PATH

Now, we can install Python 2.7:

$ brew install python

Get pip repository:

$ git clone https://github.com/pypa/pip

install pip:

$sudo easy_install pip

回答 13

如果您正在运行Python 3.5,请运行以下终端命令:

sudo pip3 install -U nltk

终端中的任何其他pip命令都将类似:

pip3 install --upgrade pip
sudo pip3 install -U numpy ::

If you are running Python 3.5, run the following terminal command:

sudo pip3 install -U nltk

Any other pip commands in terminal would be similar:

pip3 install --upgrade pip
sudo pip3 install -U numpy ::

回答 14

python默认情况下安装它,但如果未安装,则可以使用以下cmd手动安装(仅适用于linux)

对于python3:

sudo apt install python3-pip 

对于python2

sudo apt install python-pip 

希望它的帮助。

python install it by default but if not install you can install it manual use following cmd (for linux only )

for python3 :

sudo apt install python3-pip 

for python2

sudo apt install python-pip 

hope its help.


回答 15

避免sudo

python <(curl https://bootstrap.pypa.io/get-pip.py) --user
echo 'export "PATH=$HOME/Library/Python/2.7/bin:$PATH"' >> ~/.bash_profile

从:

http://www.pip-command-not-found.com

Avoiding sudo:

python <(curl https://bootstrap.pypa.io/get-pip.py) --user
echo 'export "PATH=$HOME/Library/Python/2.7/bin:$PATH"' >> ~/.bash_profile

From:

http://www.pip-command-not-found.com


回答 16

CentOS 7用户可以使用:

yum install python-pip

virtualenv如果您使用的是点子,也建议使用。可以用相同的方式添加它:

yum install python-virtualenv

CentOS 7 users can just use:

yum install python-pip

Also recommend using virtualenv if you’re using pip. It can be added in the same way:

yum install python-virtualenv

回答 17

假设您有互联网,请参阅: https //pip.pypa.io/en/stable/installing/

基本上运行:

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

python get-pip.py

assuming you have internet see: https://pip.pypa.io/en/stable/installing/

basically run:

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

and

python get-pip.py

回答 18

(上下文:我的操作系统是使用AWS的Amazon linux。它看起来与RedHat类似,但看起来有所减少。)

退出外壳,然后打开一个新的外壳。pip命令现在可以使用。

这就是解决此位置问题的方法。

您可能还想知道:然后需要像下面的示例(例如jupyter)那样编写用于安装软件的pip命令,以便在我的系统上正常工作:

pip安装jupyter –user

具体来说,请注意缺少sudo以及–user的存在

如果pip文档对所有这些都说了话,那将是非常不错的,但是我猜这将需要输入更多的字符。

(Context: My OS is Amazon linux using AWS. It seems similar to RedHat but it’s stripped down a bit, it seems.)

Exit the shell, then open a new shell. The pip command now works.

That’s what solved the problem at this location.

You might want to know as well: The pip commands to install software then needed to be written like this example (jupyter for example) to work correctly on my system:

pip install jupyter –user

Specifically, note the lack of sudo, and the presence of –user

Would be real nice if pip docs had said anything about all this, but that would take typing in more characters I guess.


回答 19

不知道为什么以前没有提到过,但是唯一对我有用的(在我的NVIDIA Xavier上)是:

sudo apt-get install python3-pip

(或sudo apt-get install python-pip对于python 2)

Not sure why this wasnt mentioned before, but the only thing that worked for me (on my NVIDIA Xavier) was:

sudo apt-get install python3-pip

(or sudo apt-get install python-pip for python 2)


回答 20

通过升级python 3解决了这个问题 brew upgrade python:现在我可以这样做:

pip3 install  <package>  

==> python
Python has been installed as
  /usr/local/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have 

Solved this by upgrading python 3 brew upgrade python: Now i can just do:

pip3 install  <package>  

==> python
Python has been installed as
  /usr/local/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have 

回答 21

问题似乎是您的python版本和要安装的库yoıu版本不匹配。例如:如果Django是Django3,而您的python版本是2.7,则可能会收到此错误。

“安装运行后,’python’仍运行Python 2.6,并且PATH未更新。”

1-安装最新版本的Python 2-手动将PATH更改为python38并进行比较。3-尝试重新安装。

我解决了此问题,方法是使用最新版本的Python手动替换PATH。对于Windows:; C:\ python38 \ Scripts

The problem seems that your python version and the library yoıu want to install is not matching versionally. Ex: If Django is Django3 and your python version is 2.7, you may get this error.

“After installing is running ‘python’ still ran Python 2.6 and PATH was not updated.”

1- Install latest version of Python 2- Change your PATH manually as python38 and compare them. 3- Try to reinstall.

I solved this problem as replacing PATH manually with the latest version of Python. As for Windows: ;C:\python38\Scripts


回答 22

我为克服这个问题所做的是sudo apt install python-pip

原来我的虚拟机尚未安装pip。可以想象其他人也可能有这种情况。

What I did to overcome this was sudo apt install python-pip.

It turned out my virtual machine did not have pip installed yet. It’s conceivable that other people could have this scenario too.


回答 23

python-pip在更新pip编辑后使用过时版本的pip(9.0),当前发布的pip版本为(18.0),请/usr/bin/pip替换此导入:

from pip import main

from pip._internal import main

这适用于pip 18.0问题是pip更改main功能名称重复为/usr/bin/pip3/usr/bin/pip2

还认为/usr/local/lib/[your_python_version]/dist-packages/pip/__main__.py它应该与/usr/bin/pip

python-pip use obsolete version of pip (9.0) current post pip version is (18.0) after updating pip edit /usr/bin/pip replace this import:

from pip import main

to

from pip._internal import main

this working for pip 18.0 problem is pip change main function name repeat for /usr/bin/pip3 and /usr/bin/pip2

also view /usr/local/lib/[your_python_version]/dist-packages/pip/__main__.py It should be the same as /usr/bin/pip


回答 24

请执行以下操作:

sudo apt update
sudo apt install python3-pip
source ~/.bashrc

这肯定会安装pip及其所有依赖项。PS这是用于python 3,如果要使用python 2,请从第二个命令中将python3替换为python

sudo apt install python-pip

Do following:

sudo apt update
sudo apt install python3-pip
source ~/.bashrc

This will surely install pip with all its dependencies. PS this is for python 3 if you want for python 2 replace python3 from the second command to python

sudo apt install python-pip

回答 25

要解决Mac中的“ bash:pip:找不到命令 ”问题

在Mac 1上发现两个版本是2.7,另一个是3.7

  • 当我说sudo easy_install pip时,pip在2.7下安装

  • 当我说sudo easy_install-3.7 pip时,pip已安装在3.7下

但是,每当我需要进行pip install时,我都想在python3.7下安装该软件包,因此我在.bash_profile中设置了一个别名(alias pip = pip3)。

所以现在,每当我进行pip install时,都会在python3.7下安装

To overcome the issue “bash: pip: command not found” in Mac

Found two versions on Mac 1 is 2.7 and the other is 3.7

  • when I say sudo easy_install pip, pip got installed under 2.7

  • when I say sudo easy_install-3.7 pip, pip got installed under 3.7

But, whenever I would require to do pip install , I wanted to install the package under python3.7, so I have set an alias (alias pip=pip3)in .bash_profile

so now, whenever I do pip install , it gets installed under python3.7


回答 26

更新的安装命令为pip3

sudo apt-get install python3-pip

The updated command for installing pip3 is :

sudo apt-get install python3-pip

如何避免Python / Pandas在保存的csv中创建索引?

问题:如何避免Python / Pandas在保存的csv中创建索引?

对文件进行一些编辑后,我试图将csv保存到文件夹。

每次我使用pd.to_csv('C:/Path of file.csv')csv文件时,都有单独的索引列。我想避免将索引打印到csv。

我试过了:

pd.read_csv('C:/Path to file to edit.csv', index_col = False)

并保存文件…

pd.to_csv('C:/Path to save edited file.csv', index_col = False)

但是,我仍然得到不需要的索引列。保存文件时如何避免这种情况?

I am trying to save a csv to a folder after making some edits to the file.

Every time I use pd.to_csv('C:/Path of file.csv') the csv file has a separate column of indexes. I want to avoid printing the index to csv.

I tried:

pd.read_csv('C:/Path to file to edit.csv', index_col = False)

And to save the file…

pd.to_csv('C:/Path to save edited file.csv', index_col = False)

However, I still got the unwanted index column. How can I avoid this when I save my files?


回答 0

使用index=False

df.to_csv('your.csv', index=False)

Use index=False.

df.to_csv('your.csv', index=False)

回答 1

有两种方法可以处理我们不希望将索引存储在csv文件中的情况。

  1. 正如其他人所述,将 数据框保存到csv文件时可以使用index = False

    df.to_csv('file_name.csv',index=False)

  2. 或者,您可以使用索引保存数据框,在读取时只需删除未命名的包含先前索引的0列即可!简单!

    df.to_csv(' file_name.csv ')
    df_new = pd.read_csv('file_name.csv').drop(['unnamed 0'],axis=1)

There are two ways to handle the situation where we do not want the index to be stored in csv file.

  1. As others have stated you can use index=False while saving your
    dataframe to csv file.

    df.to_csv('file_name.csv',index=False)

  2. Or you can save your dataframe as it is with an index, and while reading you just drop the column unnamed 0 containing your previous index.Simple!

    df.to_csv(' file_name.csv ')
    df_new = pd.read_csv('file_name.csv').drop(['unnamed 0'],axis=1)


回答 2

如果不需要索引,请使用以下命令读取文件:

import pandas as pd
df = pd.read_csv('file.csv', index_col=0)

使用保存

df.to_csv('file.csv', index=False)

If you want no index, read file using:

import pandas as pd
df = pd.read_csv('file.csv', index_col=0)

save it using

df.to_csv('file.csv', index=False)

回答 3

正如其他人所说,如果您不想首先保存索引列,则可以使用 df.to_csv('processed.csv', index=False)

但是,由于您通常使用的数据本身具有某种索引,因此我们假设使用“时间戳”列,因此我将保留索引并使用该索引加载数据。

因此,要保存索引数据,请首先设置其索引,然后保存DataFrame:

df.set_index('timestamp')
df.to_csv('processed.csv')

之后,您可以读取带有索引的数据:

pd.read_csv('processed.csv', index_col='timestamp')

或读取数据,然后设置索引:

pd.read_csv('filename.csv')
pd.set_index('column_name')

As others have stated, if you don’t want to save the index column in the first place, you can use df.to_csv('processed.csv', index=False)

However, since the data you will usually use, have some sort of index themselves, let’s say a ‘timestamp’ column, I would keep the index and load the data using it.

So, to save the indexed data, first set their index and then save the DataFrame:

df.set_index('timestamp')
df.to_csv('processed.csv')

Afterwards, you can either read the data with the index:

pd.read_csv('processed.csv', index_col='timestamp')

or read the data, and then set the index:

pd.read_csv('filename.csv')
pd.set_index('column_name')

回答 4

如果要将此列保留为索引,则可以采用另一种解决方案。

pd.read_csv('filename.csv', index_col='Unnamed: 0')

Another solution if you want to keep this column as index.

pd.read_csv('filename.csv', index_col='Unnamed: 0')

回答 5

如果您想要一个好的格式,那么下一条语句是最好的:

dataframe_prediction.to_csv('filename.csv', sep=',', encoding='utf-8', index=False)

在这种情况下,您将获得一个带有’,’的csv文件,该文件在各列和utf-8格式之间分开。另外,数字索引不会出现。

If you want a good format the next statement is the best:

dataframe_prediction.to_csv('filename.csv', sep=',', encoding='utf-8', index=False)

In this case you have got a csv file with ‘,’ as separate between columns and utf-8 format. In addition, numerical index won’t appear.


实际上,Python 3.3中新的“ yield from”语法的主要用途是什么?

问题:实际上,Python 3.3中新的“ yield from”语法的主要用途是什么?

我很难缠住PEP 380

  1. 在什么情况下“产生于”有用?
  2. 什么是经典用例?
  3. 为什么与微线程相比?

[更新]

现在,我了解了造成困难的原因。我曾经使用过生成器,但从未真正使用过协程(由PEP-342引入)。尽管有一些相似之处,但生成器和协程基本上是两个不同的概念。了解协程(不仅是生成器)是了解新语法的关键。

恕我直言,协程是最晦涩的Python功能,大多数书籍使它看起来毫无用处且无趣。

感谢您做出的出色回答,特别感谢agf及其与David Beazley演讲相关的评论。大卫·罗克。

I’m having a hard time wrapping my brain around PEP 380.

  1. What are the situations where “yield from” is useful?
  2. What is the classic use case?
  3. Why is it compared to micro-threads?

[ update ]

Now I understand the cause of my difficulties. I’ve used generators, but never really used coroutines (introduced by PEP-342). Despite some similarities, generators and coroutines are basically two different concepts. Understanding coroutines (not only generators) is the key to understanding the new syntax.

IMHO coroutines are the most obscure Python feature, most books make it look useless and uninteresting.

Thanks for the great answers, but special thanks to agf and his comment linking to David Beazley presentations. David rocks.


回答 0

让我们先解决一件事。该解释yield from g就等于for v in g: yield v 甚至没有开始做正义什么yield from是一回事。因为,让我们面对现实,如果所有的事情yield from都是扩大for循环,那么它就不必添加yield from语言,也不能阻止在Python 2.x中实现一堆新功能。

什么yield from所做的就是建立主叫方和副生成器之间的透明双向连接

  • 从某种意义上说,该连接是“透明的”,它也将正确地传播所有内容,而不仅仅是所生成的元素(例如,传播异常)。

  • 该连接是在意义上是“双向”的数据可以同时寄给一个生成器。

如果我们在谈论TCP,yield from g可能意味着“现在暂时断开客户端的套接字,然后将其重新连接到该其他服务器套接字”。

顺便说一句,如果您不确定向生成器发送数据意味着什么,则需要删除所有内容并首先了解协程,它们非常有用(将它们与子例程进行对比),但是不幸的是在Python中鲜为人知。戴夫·比兹利(Dave Beazley)的《协程》好奇类是一个很好的开始。阅读幻灯片24-33以获得快速入门。

使用以下命令从生成器读取数据

def reader():
    """A generator that fakes a read from a file, socket, etc."""
    for i in range(4):
        yield '<< %s' % i

def reader_wrapper(g):
    # Manually iterate over data produced by reader
    for v in g:
        yield v

wrap = reader_wrapper(reader())
for i in wrap:
    print(i)

# Result
<< 0
<< 1
<< 2
<< 3

reader()我们可以手动完成,而不必手动进行迭代yield from

def reader_wrapper(g):
    yield from g

那行得通,我们消除了一行代码。意图可能会更清晰(或不太清楚)。但是生活没有改变。

使用第1部分中的收益将数据发送到生成器(协程)

现在,让我们做一些更有趣的事情。让我们创建一个名为coroutine的协程writer,它接受发送给它的数据并写入套接字,fd等。

def writer():
    """A coroutine that writes data *sent* to it to fd, socket, etc."""
    while True:
        w = (yield)
        print('>> ', w)

现在的问题是,包装器函数应如何处理将数据发送到编写器,以便将任何发送到包装器的数据透明地发送到writer()

def writer_wrapper(coro):
    # TBD
    pass

w = writer()
wrap = writer_wrapper(w)
wrap.send(None)  # "prime" the coroutine
for i in range(4):
    wrap.send(i)

# Expected result
>>  0
>>  1
>>  2
>>  3

包装器需要(显然)接受发送给它的数据,并且还应处理StopIterationfor循环用尽时的情况。显然只是做for x in coro: yield x不会做。这是一个有效的版本。

def writer_wrapper(coro):
    coro.send(None)  # prime the coro
    while True:
        try:
            x = (yield)  # Capture the value that's sent
            coro.send(x)  # and pass it to the writer
        except StopIteration:
            pass

或者,我们可以这样做。

def writer_wrapper(coro):
    yield from coro

这样可以节省6行代码,使其更具可读性,并且可以正常工作。魔法!

从第2部分-异常处理将数据发送到生成器收益

让我们使其更加复杂。如果我们的作者需要处理异常怎么办?假设writer句柄a 遇到一个SpamException,它将打印***

class SpamException(Exception):
    pass

def writer():
    while True:
        try:
            w = (yield)
        except SpamException:
            print('***')
        else:
            print('>> ', w)

如果我们不改变writer_wrapper怎么办?它行得通吗?我们试试吧

# writer_wrapper same as above

w = writer()
wrap = writer_wrapper(w)
wrap.send(None)  # "prime" the coroutine
for i in [0, 1, 2, 'spam', 4]:
    if i == 'spam':
        wrap.throw(SpamException)
    else:
        wrap.send(i)

# Expected Result
>>  0
>>  1
>>  2
***
>>  4

# Actual Result
>>  0
>>  1
>>  2
Traceback (most recent call last):
  ... redacted ...
  File ... in writer_wrapper
    x = (yield)
__main__.SpamException

嗯,它不起作用,因为x = (yield)只是引发了异常,一切都崩溃了。让它正常工作,但手动处理异常并将其发送或将其抛出到子生成器(writer)中

def writer_wrapper(coro):
    """Works. Manually catches exceptions and throws them"""
    coro.send(None)  # prime the coro
    while True:
        try:
            try:
                x = (yield)
            except Exception as e:   # This catches the SpamException
                coro.throw(e)
            else:
                coro.send(x)
        except StopIteration:
            pass

这可行。

# Result
>>  0
>>  1
>>  2
***
>>  4

但是,这也是!

def writer_wrapper(coro):
    yield from coro

yield from透明地处理发送值或抛出的值到副生成器。

但是,这仍然不能涵盖所有极端情况。如果外部生成器关闭,会发生什么?如果子生成器返回一个值(是的,在Python 3.3+中,生成器可以返回值),该如何处理?yield from透明地处理所有的极端案例是让人印象深刻yield from只是神奇地工作并处理了所有这些情况。

我个人认为这yield from是一个糟糕的关键字选择,因为它不会使双向性变得显而易见。提出了其他关键字(例如delegate但被拒绝了,因为向该语言添加新关键字比合并现有关键字要困难得多。

总之,最好将其yield from视为transparent two way channel调用方和子生成方之间的。

参考文献:

  1. PEP 380-委派给子生成器的语法(尤因)[v3.3,2009-02-13]
  2. PEP 342-通过增强型生成器进行协同程序(GvR,Eby)[v2.5,2005-05-10]

Let’s get one thing out of the way first. The explanation that yield from g is equivalent to for v in g: yield v does not even begin to do justice to what yield from is all about. Because, let’s face it, if all yield from does is expand the for loop, then it does not warrant adding yield from to the language and preclude a whole bunch of new features from being implemented in Python 2.x.

What yield from does is it establishes a transparent bidirectional connection between the caller and the sub-generator:

  • The connection is “transparent” in the sense that it will propagate everything correctly too, not just the elements being generated (e.g. exceptions are propagated).

  • The connection is “bidirectional” in the sense that data can be both sent from and to a generator.

(If we were talking about TCP, yield from g might mean “now temporarily disconnect my client’s socket and reconnect it to this other server socket”.)

BTW, if you are not sure what sending data to a generator even means, you need to drop everything and read about coroutines first—they’re very useful (contrast them with subroutines), but unfortunately lesser-known in Python. Dave Beazley’s Curious Course on Coroutines is an excellent start. Read slides 24-33 for a quick primer.

Reading data from a generator using yield from

def reader():
    """A generator that fakes a read from a file, socket, etc."""
    for i in range(4):
        yield '<< %s' % i

def reader_wrapper(g):
    # Manually iterate over data produced by reader
    for v in g:
        yield v

wrap = reader_wrapper(reader())
for i in wrap:
    print(i)

# Result
<< 0
<< 1
<< 2
<< 3

Instead of manually iterating over reader(), we can just yield from it.

def reader_wrapper(g):
    yield from g

That works, and we eliminated one line of code. And probably the intent is a little bit clearer (or not). But nothing life changing.

Sending data to a generator (coroutine) using yield from – Part 1

Now let’s do something more interesting. Let’s create a coroutine called writer that accepts data sent to it and writes to a socket, fd, etc.

def writer():
    """A coroutine that writes data *sent* to it to fd, socket, etc."""
    while True:
        w = (yield)
        print('>> ', w)

Now the question is, how should the wrapper function handle sending data to the writer, so that any data that is sent to the wrapper is transparently sent to the writer()?

def writer_wrapper(coro):
    # TBD
    pass

w = writer()
wrap = writer_wrapper(w)
wrap.send(None)  # "prime" the coroutine
for i in range(4):
    wrap.send(i)

# Expected result
>>  0
>>  1
>>  2
>>  3

The wrapper needs to accept the data that is sent to it (obviously) and should also handle the StopIteration when the for loop is exhausted. Evidently just doing for x in coro: yield x won’t do. Here is a version that works.

def writer_wrapper(coro):
    coro.send(None)  # prime the coro
    while True:
        try:
            x = (yield)  # Capture the value that's sent
            coro.send(x)  # and pass it to the writer
        except StopIteration:
            pass

Or, we could do this.

def writer_wrapper(coro):
    yield from coro

That saves 6 lines of code, make it much much more readable and it just works. Magic!

Sending data to a generator yield from – Part 2 – Exception handling

Let’s make it more complicated. What if our writer needs to handle exceptions? Let’s say the writer handles a SpamException and it prints *** if it encounters one.

class SpamException(Exception):
    pass

def writer():
    while True:
        try:
            w = (yield)
        except SpamException:
            print('***')
        else:
            print('>> ', w)

What if we don’t change writer_wrapper? Does it work? Let’s try

# writer_wrapper same as above

w = writer()
wrap = writer_wrapper(w)
wrap.send(None)  # "prime" the coroutine
for i in [0, 1, 2, 'spam', 4]:
    if i == 'spam':
        wrap.throw(SpamException)
    else:
        wrap.send(i)

# Expected Result
>>  0
>>  1
>>  2
***
>>  4

# Actual Result
>>  0
>>  1
>>  2
Traceback (most recent call last):
  ... redacted ...
  File ... in writer_wrapper
    x = (yield)
__main__.SpamException

Um, it’s not working because x = (yield) just raises the exception and everything comes to a crashing halt. Let’s make it work, but manually handling exceptions and sending them or throwing them into the sub-generator (writer)

def writer_wrapper(coro):
    """Works. Manually catches exceptions and throws them"""
    coro.send(None)  # prime the coro
    while True:
        try:
            try:
                x = (yield)
            except Exception as e:   # This catches the SpamException
                coro.throw(e)
            else:
                coro.send(x)
        except StopIteration:
            pass

This works.

# Result
>>  0
>>  1
>>  2
***
>>  4

But so does this!

def writer_wrapper(coro):
    yield from coro

The yield from transparently handles sending the values or throwing values into the sub-generator.

This still does not cover all the corner cases though. What happens if the outer generator is closed? What about the case when the sub-generator returns a value (yes, in Python 3.3+, generators can return values), how should the return value be propagated? That yield from transparently handles all the corner cases is really impressive. yield from just magically works and handles all those cases.

I personally feel yield from is a poor keyword choice because it does not make the two-way nature apparent. There were other keywords proposed (like delegate but were rejected because adding a new keyword to the language is much more difficult than combining existing ones.

In summary, it’s best to think of yield from as a transparent two way channel between the caller and the sub-generator.

References:

  1. PEP 380 – Syntax for delegating to a sub-generator (Ewing) [v3.3, 2009-02-13]
  2. PEP 342 – Coroutines via Enhanced Generators (GvR, Eby) [v2.5, 2005-05-10]

回答 1

在什么情况下“产生于”是有用的?

您遇到这样的循环的每种情况:

for x in subgenerator:
  yield x

作为PEP介绍,这是一个相当幼稚企图在使用子发生器,它缺少几个方面,特别是妥善处理.throw()/ .send()/ .close()通过引进机制PEP 342。要正确执行此操作,需要相当复杂的代码。

什么是经典用例?

考虑您要从递归数据结构中提取信息。假设我们要获取树中的所有叶节点:

def traverse_tree(node):
  if not node.children:
    yield node
  for child in node.children:
    yield from traverse_tree(child)

更重要的是,直到之前yield from,还没有简单的重构生成器代码的方法。假设您有一个(无意义的)生成器,如下所示:

def get_list_values(lst):
  for item in lst:
    yield int(item)
  for item in lst:
    yield str(item)
  for item in lst:
    yield float(item)

现在,您决定将这些循环分解为单独的生成器。不带yield from,这是很丑陋的,直到您是否真的想这样做三思。使用yield from,实际上看起来很不错:

def get_list_values(lst):
  for sub in [get_list_values_as_int, 
              get_list_values_as_str, 
              get_list_values_as_float]:
    yield from sub(lst)

为什么与微线程相比?

我认为PEP中的这一部分谈论的是,每个生成器确实都有其自己的隔离执行上下文。以及使用yield和来在生成者迭代器和调用者之间切换执行的事实__next__()分别,这类似于线程,其中操作系统会不时切换执行线程以及执行上下文(堆栈,寄存器, …)。

其效果也相当:生成器迭代器和调用者都同时在其执行状态中进行,它们的执行是交错的。例如,如果生成器进行某种计算,并且调用方打印出结果,则结果可用时,您将立即看到它们。这是一种并发形式。

这种类比不是特定于的yield from-而是Python中生成器的一般属性。

What are the situations where “yield from” is useful?

Every situation where you have a loop like this:

for x in subgenerator:
  yield x

As the PEP describes, this is a rather naive attempt at using the subgenerator, it’s missing several aspects, especially the proper handling of the .throw()/.send()/.close() mechanisms introduced by PEP 342. To do this properly, rather complicated code is necessary.

What is the classic use case?

Consider that you want to extract information from a recursive data structure. Let’s say we want to get all leaf nodes in a tree:

def traverse_tree(node):
  if not node.children:
    yield node
  for child in node.children:
    yield from traverse_tree(child)

Even more important is the fact that until the yield from, there was no simple method of refactoring the generator code. Suppose you have a (senseless) generator like this:

def get_list_values(lst):
  for item in lst:
    yield int(item)
  for item in lst:
    yield str(item)
  for item in lst:
    yield float(item)

Now you decide to factor out these loops into separate generators. Without yield from, this is ugly, up to the point where you will think twice whether you actually want to do it. With yield from, it’s actually nice to look at:

def get_list_values(lst):
  for sub in [get_list_values_as_int, 
              get_list_values_as_str, 
              get_list_values_as_float]:
    yield from sub(lst)

Why is it compared to micro-threads?

I think what this section in the PEP is talking about is that every generator does have its own isolated execution context. Together with the fact that execution is switched between the generator-iterator and the caller using yield and __next__(), respectively, this is similar to threads, where the operating system switches the executing thread from time to time, along with the execution context (stack, registers, …).

The effect of this is also comparable: Both the generator-iterator and the caller progress in their execution state at the same time, their executions are interleaved. For example, if the generator does some kind of computation and the caller prints out the results, you’ll see the results as soon as they’re available. This is a form of concurrency.

That analogy isn’t anything specific to yield from, though – it’s rather a general property of generators in Python.


回答 2

无论您从生成器内部调用生成器的哪个位置,都需要一个“泵”来重新yield设置值: for v in inner_generator: yield v。正如PEP所指出的那样,大多数人都忽略了这一点的微妙复杂性。throw()PEP中提供了一个示例,例如非本地流控制。yield from inner_generator无论您for之前编写了显式循环的地方,都将使用新语法。但是,它不仅是语法糖,它还处理了for循环忽略的所有极端情况。成为“丑闻”会鼓励人们使用它,从而获得正确的行为。

讨论线程中的此消息讨论了以下复杂性:

有了PEP 342引入的其他生成器功能,情况已不再如此:如Greg的PEP中所述,简单的迭代不正确地支持send()和throw()。当分解它们时,支持send()和throw()所需的体操实际上并不那么复杂,但是它们也不是简单的。

除了观察到生成器是一种平行论之外,我无法与微线程进行比较。您可以将挂起的生成器视为通过以下方式发送值的线程:yield到使用者线程的线程。实际的实现可能并非如此(Python开发人员显然对实际的实现非常感兴趣),但这与用户无关。

新的yield from语法不会在线程方面为语言增加任何其他功能,而只是使正确使用现有功能更加容易。或更准确地说,它使专家编写的复杂内部生成器的新手消费者可以更轻松地通过该生成器,而不会破坏其任何复杂功能。

Wherever you invoke a generator from within a generator you need a “pump” to re-yield the values: for v in inner_generator: yield v. As the PEP points out there are subtle complexities to this which most people ignore. Non-local flow-control like throw() is one example given in the PEP. The new syntax yield from inner_generator is used wherever you would have written the explicit for loop before. It’s not merely syntactic sugar, though: It handles all of the corner cases that are ignored by the for loop. Being “sugary” encourages people to use it and thus get the right behaviors.

This message in the discussion thread talks about these complexities:

With the additional generator features introduced by PEP 342, that is no longer the case: as described in Greg’s PEP, simple iteration doesn’t support send() and throw() correctly. The gymnastics needed to support send() and throw() actually aren’t that complex when you break them down, but they aren’t trivial either.

I can’t speak to a comparison with micro-threads, other than to observe that generators are a type of paralellism. You can consider the suspended generator to be a thread which sends values via yield to a consumer thread. The actual implementation may be nothing like this (and the actual implementation is obviously of great interest to the Python developers) but this does not concern the users.

The new yield from syntax does not add any additional capability to the language in terms of threading, it just makes it easier to use existing features correctly. Or more precisely it makes it easier for a novice consumer of a complex inner generator written by an expert to pass through that generator without breaking any of its complex features.


回答 3

一个简短的示例将帮助您理解的一个yield from用例:从另一个生成器获取价值

def flatten(sequence):
    """flatten a multi level list or something
    >>> list(flatten([1, [2], 3]))
    [1, 2, 3]
    >>> list(flatten([1, [2], [3, [4]]]))
    [1, 2, 3, 4]
    """
    for element in sequence:
        if hasattr(element, '__iter__'):
            yield from flatten(element)
        else:
            yield element

print(list(flatten([1, [2], [3, [4]]])))

A short example will help you understand one of yield from‘s use case: get value from another generator

def flatten(sequence):
    """flatten a multi level list or something
    >>> list(flatten([1, [2], 3]))
    [1, 2, 3]
    >>> list(flatten([1, [2], [3, [4]]]))
    [1, 2, 3, 4]
    """
    for element in sequence:
        if hasattr(element, '__iter__'):
            yield from flatten(element)
        else:
            yield element

print(list(flatten([1, [2], [3, [4]]])))

回答 4

yield from 基本上以有效的方式链接迭代器:

# chain from itertools:
def chain(*iters):
    for it in iters:
        for item in it:
            yield item

# with the new keyword
def chain(*iters):
    for it in iters:
        yield from it

如您所见,它删除了一个纯Python循环。这几乎就是它的全部工作,但是链接迭代器是Python中很常见的模式。

线程基本上是一种功能,使您可以在完全随机的点跳出函数,然后跳回另一个函数的状态。线程管理器经常执行此操作,因此该程序似乎可以同时运行所有这些功能。问题是这些点是随机的,因此您需要使用锁定来防止主管在有问题的点停止该功能。

在这种意义上,生成器与线程非常相似:它们允许您指定特定点(无论何时, yield),您可以在其中跳入和跳出。当以这种方式使用时,生成器称为协程。

阅读有关Python中协程的出色教程,以了解更多详细信息

yield from basically chains iterators in a efficient way:

# chain from itertools:
def chain(*iters):
    for it in iters:
        for item in it:
            yield item

# with the new keyword
def chain(*iters):
    for it in iters:
        yield from it

As you can see it removes one pure Python loop. That’s pretty much all it does, but chaining iterators is a pretty common pattern in Python.

Threads are basically a feature that allow you to jump out of functions at completely random points and jump back into the state of another function. The thread supervisor does this very often, so the program appears to run all these functions at the same time. The problem is that the points are random, so you need to use locking to prevent the supervisor from stopping the function at a problematic point.

Generators are pretty similar to threads in this sense: They allow you to specify specific points (whenever they yield) where you can jump in and out. When used this way, generators are called coroutines.

Read this excellent tutorials about coroutines in Python for more details


回答 5

在应用的使用为异步IO协程yield from也有类似的行为作为await协程功能。两者都用于中止协程的执行。

对于Asyncio,如果不需要支持较旧的Python版本(即> 3.5),则建议使用async def/ await作为定义协程的语法。因此yield from,协程中不再需要。

但通常在asyncio之外,如先前答案中所述,yield from <sub-generator>在迭代子生成器方面还有其他用途。

In applied usage for the Asynchronous IO coroutine, yield from has a similar behavior as await in a coroutine function. Both of which is used to suspend the execution of coroutine.

For Asyncio, if there’s no need to support an older Python version (i.e. >3.5), async def/await is the recommended syntax to define a coroutine. Thus yield from is no longer needed in a coroutine.

But in general outside of asyncio, yield from <sub-generator> has still some other usage in iterating the sub-generator as mentioned in the earlier answer.


回答 6

该代码定义了一个函数,该函数fixed_sum_digits返回一个生成器,该生成器枚举所有六个数字的数字,以使数字的总和为20。

def iter_fun(sum, deepness, myString, Total):
    if deepness == 0:
        if sum == Total:
            yield myString
    else:  
        for i in range(min(10, Total - sum + 1)):
            yield from iter_fun(sum + i,deepness - 1,myString + str(i),Total)

def fixed_sum_digits(digits, Tot):
    return iter_fun(0,digits,"",Tot) 

试着不用来写yield from。如果您找到有效的方法,请告诉我。

我认为对于这种情况:访问树yield from使代码更简单,更清晰。

This code defines a function fixed_sum_digits returning a generator enumerating all six digits numbers such that the sum of digits is 20.

def iter_fun(sum, deepness, myString, Total):
    if deepness == 0:
        if sum == Total:
            yield myString
    else:  
        for i in range(min(10, Total - sum + 1)):
            yield from iter_fun(sum + i,deepness - 1,myString + str(i),Total)

def fixed_sum_digits(digits, Tot):
    return iter_fun(0,digits,"",Tot) 

Try to write it without yield from. If you find an effective way to do it let me know.

I think that for cases like this one: visiting trees, yield from makes the code simpler and cleaner.


回答 7

简而言之,为迭代器函数yield from提供尾递归

Simply put, yield from provides tail recursion for iterator functions.


获取Python中当前脚本的名称

问题:获取Python中当前脚本的名称

我正在尝试获取当前正在运行的Python脚本的名称。

我有一个名为的脚本foo.py,我想做这样的事情以获得脚本名称:

print Scriptname

I’m trying to get the name of the Python script that is currently running.

I have a script called foo.py and I’d like to do something like this in order to get the script name:

print Scriptname

回答 0

您可以使用__file__获取当前文件的名称。在主模块中使用时,这是最初调用的脚本的名称。

如果要省略目录部分(可能存在),可以使用os.path.basename(__file__)

You can use __file__ to get the name of the current file. When used in the main module, this is the name of the script that was originally invoked.

If you want to omit the directory part (which might be present), you can use os.path.basename(__file__).


回答 1

import sys
print sys.argv[0]

这将打印foo.pypython foo.pydir/foo.pypython dir/foo.py等,这是第一个参数python。(请注意,在py2exe之后将会是foo.exe。)

import sys
print sys.argv[0]

This will print foo.py for python foo.py, dir/foo.py for python dir/foo.py, etc. It’s the first argument to python. (Note that after py2exe it would be foo.exe.)


回答 2

为了完整起见,我认为值得总结各种可能的结果,并为每种结果的确切行为提供参考:

  • __file__是当前正在执行的文件,如官方文档中所述

    __file__是从中加载模块的文件的路径名(如果它是从文件加载的)。所述__file__属性可以是缺少某些类型的模块,如Ç静态链接到解释器模块; 对于从共享库动态加载的扩展模块,它是共享库文件的路径名。

    从Python3.4起,每发行18416__file__始终是一个绝对路径,除非当前正在执行的文件是已经被直接执行(不通过与解释脚本-m使用相对路径命令行选项)。

  • __main__.__file__(需要import __main__)仅访问主模块的上述__file__属性,例如,从命令行调用的脚本的属性。

  • sys.argv[0](需要import sys)是从命令行调用的脚本名称,并且可能是绝对路径,如官方文档中所述

    argv[0]是脚本名称(是否为完整路径名取决于操作系统)。如果命令是使用-c解释器的命令行选项执行的,argv[0]则将其设置为字符串'-c'。如果没有脚本名称传递给Python解释器,argv[0]则为空字符串。

    正如提到的另一个回答这个问题Python的是被通过的工具,如转换成独立的可执行程序的脚本py2exePyInstaller可能不会显示预期的结果使用这种方法的时候(也就是sys.argv[0]将持有的可执行文件的名称,而不是名称该可执行文件中主要Python文件的名称)。

  • 如果上述选项似乎都不起作用,可能是由于不规则的导入操作造成的,那么检查模块可能会证明是有用的。特别是,在调用inspect.getfile(...)inspect.currentframe()可以工作,尽管后者将返回None没有实现运行时的Python堆栈帧。


处理符号链接

如果当前脚本是符号链接,则以上所有内容都将返回符号链接的路径,而不是真实文件的路径,因此os.path.realpath(...)应调用它们以提取后者。


提取实际文件名的进一步操作

os.path.basename(...)可以在上述任何方法上调用以便提取实际的文件名,os.path.splitext(...)也可以在实际的文件名上调用以便截断其后缀,如中所示os.path.splitext(os.path.basename(...))

Python的3.4起,每PEP 428中,PurePath的的pathlib模块可以用作以及任何上述的。具体来说,pathlib.PurePath(...).name提取实际文件名并pathlib.PurePath(...).stem提取不带后缀的实际文件名。

For completeness’ sake, I thought it would be worthwhile summarizing the various possible outcomes and supplying references for the exact behaviour of each:

  • __file__ is the currently executing file, as detailed in the official documentation:

    __file__ is the pathname of the file from which the module was loaded, if it was loaded from a file. The __file__ attribute may be missing for certain types of modules, such as C modules that are statically linked into the interpreter; for extension modules loaded dynamically from a shared library, it is the pathname of the shared library file.

    From Python3.4 onwards, per issue 18416, __file__ is always an absolute path, unless the currently executing file is a script that has been executed directly (not via the interpreter with the -m command line option) using a relative path.

  • __main__.__file__ (requires importing __main__) simply accesses the aforementioned __file__ attribute of the main module, e.g. of the script that was invoked from the command line.

  • sys.argv[0] (requires importing sys) is the script name that was invoked from the command line, and might be an absolute path, as detailed in the official documentation:

    argv[0] is the script name (it is operating system dependent whether this is a full pathname or not). If the command was executed using the -c command line option to the interpreter, argv[0] is set to the string '-c'. If no script name was passed to the Python interpreter, argv[0] is the empty string.

    As mentioned in another answer to this question, Python scripts that were converted into stand-alone executable programs via tools such as py2exe or PyInstaller might not display the desired result when using this approach (i.e. sys.argv[0] would hold the name of the executable rather than the name of the main Python file within that executable).

  • If none of the aforementioned options seem to work, probably due to an irregular import operation, the inspect module might prove useful. In particular, invoking inspect.getfile(...) on inspect.currentframe() could work, although the latter would return None when running in an implementation without Python stack frame.


Handling symbolic links

If the current script is a symbolic link, then all of the above would return the path of the symbolic link rather than the path of the real file and os.path.realpath(...) should be invoked in order to extract the latter.


Further manipulations that extract the actual file name

os.path.basename(...) may be invoked on any of the above in order to extract the actual file name and os.path.splitext(...) may be invoked on the actual file name in order to truncate its suffix, as in os.path.splitext(os.path.basename(...)).

From Python 3.4 onwards, per PEP 428, the PurePath class of the pathlib module may be used as well on any of the above. Specifically, pathlib.PurePath(...).name extracts the actual file name and pathlib.PurePath(...).stem extracts the actual file name without its suffix.


回答 3

注意 __file__将提供此代码所在的文件,该文件可以导入,并且与要解释的主文件不同。要获取主文件,可以使用特殊的__main__模块:

import __main__ as main
print(main.__file__)

注意 __main__.__file__在Python 2.7中有效,但在3.2中无效,因此请使用上述import-as语法使其具有可移植性。

Note that __file__ will give the file where this code resides, which can be imported and different from the main file being interpreted. To get the main file, the special __main__ module can be used:

import __main__ as main
print(main.__file__)

Note that __main__.__file__ works in Python 2.7 but not in 3.2, so use the import-as syntax as above to make it portable.


回答 4

上述答案是好的。但是我发现使用上面的结果这种方法更有效。
这导致实际的脚本文件名不是路径。

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])

The Above answers are good . But I found this method more efficient using above results.
This results in actual script file name not a path.

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])

回答 5

对于现代Python版本(3.4+),Path(__file__).name应该更加惯用。另外,Path(__file__).stem为您提供不带.py扩展名的脚本名称。

For modern Python versions (3.4+), Path(__file__).name should be more idiomatic. Also, Path(__file__).stem gives you the script name without the .py extension.


回答 6

尝试这个:

print __file__

Try this:

print __file__

回答 7

注意:如果您使用的是Python 3+,则应改用print()函数

假设文件名为foo.py,则以下代码段

import sys
print sys.argv[0][:-3]

要么

import sys
print sys.argv[0][::-1][3:][::-1]

至于具有更多字符的其他扩展名,例如文件名 foo.pypy

import sys
print sys.argv[0].split('.')[0]

如果要从绝对路径中提取

import sys
print sys.argv[0].split('/')[-1].split('.')[0]

将输出 foo

Note: If you are using Python 3+, then you should use the print() function instead

Assuming that the filename is foo.py, the below snippet

import sys
print sys.argv[0][:-3]

or

import sys
print sys.argv[0][::-1][3:][::-1]

As for other extentions with more characters, for example the filename foo.pypy

import sys
print sys.argv[0].split('.')[0]

If you want to extract from an absolute path

import sys
print sys.argv[0].split('/')[-1].split('.')[0]

will output foo


回答 8

sys中的第一个参数将是当前文件名,因此它将起作用

   import sys
   print sys.argv[0] # will print the file name

The first argument in sys will be the current file name so this will work

   import sys
   print sys.argv[0] # will print the file name

回答 9

如果您执行的是异常导入(例如,这是一个选项文件),请尝试:

import inspect
print (inspect.getfile(inspect.currentframe()))

请注意,这将返回文件的绝对路径。

If you’re doing an unusual import (e.g., it’s an options file), try:

import inspect
print (inspect.getfile(inspect.currentframe()))

Note that this will return the absolute path to the file.


回答 10

我们可以尝试使用此命令来获取当前脚本名称(不带扩展名)。

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]

we can try this to get current script name without extension.

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]

回答 11

由于OP要求提供当前脚本文件的名称,所以我希望

import os
os.path.split(sys.argv[0])[1]

Since the OP asked for the name of the current script file I would prefer

import os
os.path.split(sys.argv[0])[1]

回答 12

我快速的肮脏解决方案:

__file__.split('/')[-1:][0]

My fast dirty solution:

__file__.split('/')[-1:][0]

回答 13

os.path.abspath(__file__)将为您提供一条绝对路径(也relpath()可用)。

sys.argv[-1] 会给你一个相对的路径。

os.path.abspath(__file__) will give you an absolute path (relpath() available as well).

sys.argv[-1] will give you a relative path.


回答 14

所有这些答案都很不错,但是有一些问题,您乍一看可能看不到。

让我们定义我们想要的-我们想要执行的脚本的名称,而不是当前模块的名称-因此,__file__只有在已执行的脚本中使用了它,而不是在导入的模块中使用它时,它才起作用。 sys.argv也是可疑的-如果您的程序被pytest调用了怎么办?还是pydocRunner?还是被uwsgi调用?

-还有第三种获取脚本名称的方法,我在答案中没有看到-您可以检查堆栈。

另一个问题是,您(或某些其他程序)可以篡改sys.argv并且__main__.__file__-它可能存在,但可能不存在。它可能有效或无效。至少您可以检查脚本(所需结果)是否存在!

我在github上的库bitranox / lib_programname确实做到了:

  • 检查是否__main__存在
  • 检查是否__main__.__file__存在
  • 确实给 __main__.__file__有效结果(该脚本是否存在?)
  • 如果不是,请检查sys.argv:
  • sys.argv中是否有pytest,docrunner等?->如果是,请忽略
  • 我们可以在这里得到有效的结果吗?
  • 如果不是:检查堆栈并从那里获取结果
  • 如果堆栈也未给出有效结果,则抛出异常。

通过这种方式,我的解决方案正在到目前为止有setup.py testuwsgipytestpycharm pytestpycharm docrunner (doctest)dreampieeclipse

Dough Hellman也有一篇关于该问题的不错的博客文章,“用Python确定进程的名称”。

all that answers are great, but have some problems You might not see at the first glance.

lets define what we want – we want the name of the script that was executed, not the name of the current module – so __file__ will only work if it is used in the executed script, not in an imported module. sys.argv is also questionable – what if your program was called by pytest ? or pydoc runner ? or if it was called by uwsgi ?

and – there is a third method of getting the script name, I havent seen in the answers – You can inspect the stack.

Another problem is, that You (or some other program) can tamper around with sys.argv and __main__.__file__ – it might be present, it might be not. It might be valid, or not. At least You can check if the script (the desired result) exists !

my library bitranox/lib_programname at github does exactly that :

  • check if __main__ is present
  • check if __main__.__file__ is present
  • does give __main__.__file__ a valid result (does that script exist ?)
  • if not: check sys.argv:
  • is there pytest, docrunner, etc in the sys.argv ? –> if yes, ignore that
  • can we get a valid result here ?
  • if not: inspect the stack and get the result from there possibly
  • if also the stack does not give a valid result, then throw an Exception.

by that way, my solution is working so far with setup.py test, uwsgi, pytest, pycharm pytest , pycharm docrunner (doctest), dreampie, eclipse

there is also a nice blog article about that problem from Dough Hellman, “Determining the Name of a Process from Python”


回答 15

从Python 3.5开始,您可以简单地执行以下操作:

from pathlib import Path
Path(__file__).stem

在此处查看更多信息:https : //docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

例如,我的用户目录下有一个文件,test.py里面是这个文件:

from pathlib import Path

print(Path(__file__).stem)
print(__file__)

运行此输出:

>>> python3.6 test.py
test
test.py

As of Python 3.5 you can simply do:

from pathlib import Path
Path(__file__).stem

See more here: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

For example, I have a file under my user directory named test.py with this inside:

from pathlib import Path

print(Path(__file__).stem)
print(__file__)

running this outputs:

>>> python3.6 test.py
test
test.py

如何获取Python函数的源代码?

问题:如何获取Python函数的源代码?

假设我有如下定义的Python函数:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

我可以使用获取函数的名称foo.func_name。如上所述,我如何以编程方式获取其源代码?

Suppose I have a Python function as defined below:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

I can get the name of the function using foo.func_name. How can I programmatically get its source code, as I typed above?


回答 0

如果该功能来自文件系统上可用的源文件,那么inspect.getsource(foo)可能会有帮助:

如果foo定义为:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a  

然后:

import inspect
lines = inspect.getsource(foo)
print(lines)

返回值:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a                

但是我相信,如果函数是从字符串,流中编译的,或者是从编译文件中导入的,那么您将无法检索其源代码。

If the function is from a source file available on the filesystem, then inspect.getsource(foo) might be of help:

If foo is defined as:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a  

Then:

import inspect
lines = inspect.getsource(foo)
print(lines)

Returns:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a                

But I believe that if the function is compiled from a string, stream or imported from a compiled file, then you cannot retrieve its source code.


回答 1

检查模块具有用于从Python对象中检索的源代码的方法。貌似它仅在源位于文件中时才起作用。如果有的话,我想您就不需要从对象中获取源代码。

The inspect module has methods for retrieving source code from python objects. Seemingly it only works if the source is located in a file though. If you had that I guess you wouldn’t need to get the source from the object.


回答 2

dis 如果源代码不可用,您是您的朋友吗:

>>> import dis
>>> def foo(arg1,arg2):
...     #do something with args
...     a = arg1 + arg2
...     return a
...
>>> dis.dis(foo)
  3           0 LOAD_FAST                0 (arg1)
              3 LOAD_FAST                1 (arg2)
              6 BINARY_ADD
              7 STORE_FAST               2 (a)

  4          10 LOAD_FAST                2 (a)
             13 RETURN_VALUE

dis is your friend if the source code is not available:

>>> import dis
>>> def foo(arg1,arg2):
...     #do something with args
...     a = arg1 + arg2
...     return a
...
>>> dis.dis(foo)
  3           0 LOAD_FAST                0 (arg1)
              3 LOAD_FAST                1 (arg2)
              6 BINARY_ADD
              7 STORE_FAST               2 (a)

  4          10 LOAD_FAST                2 (a)
             13 RETURN_VALUE

回答 3

如果使用的是IPython,则需要输入“ foo ??”

In [19]: foo??
Signature: foo(arg1, arg2)
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

File:      ~/Desktop/<ipython-input-18-3174e3126506>
Type:      function

If you are using IPython, then you need to type “foo??”

In [19]: foo??
Signature: foo(arg1, arg2)
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

File:      ~/Desktop/<ipython-input-18-3174e3126506>
Type:      function

回答 4

虽然我通常会认为这inspect是一个很好的答案,但我不同意您无法获得解释器中定义的对象的源代码。如果使用dill.source.getsourcefrom dill,即使它们是交互式定义的,也可以获取函数和lambda的来源。它也可以从咖喱中定义的绑定或未绑定类方法和函数中获取代码……但是,如果没有封闭对象的代码,您可能无法编译该代码。

>>> from dill.source import getsource
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getsource(add)
def add(x,y):
  return x+y

>>> print getsource(squared)
squared = lambda x:x**2

>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getsource(f.bar)
def bar(self, x):
    return x*x+x

>>> 

While I’d generally agree that inspect is a good answer, I’d disagree that you can’t get the source code of objects defined in the interpreter. If you use dill.source.getsource from dill, you can get the source of functions and lambdas, even if they are defined interactively. It also can get the code for from bound or unbound class methods and functions defined in curries… however, you might not be able to compile that code without the enclosing object’s code.

>>> from dill.source import getsource
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getsource(add)
def add(x,y):
  return x+y

>>> print getsource(squared)
squared = lambda x:x**2

>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getsource(f.bar)
def bar(self, x):
    return x*x+x

>>> 

回答 5

扩展runeh的答案:

>>> def foo(a):
...    x = 2
...    return x + a

>>> import inspect

>>> inspect.getsource(foo)
u'def foo(a):\n    x = 2\n    return x + a\n'

print inspect.getsource(foo)
def foo(a):
   x = 2
   return x + a

编辑:正如@ 0sh所指出的,此示例使用ipython但不是plain可以工作python。但是,从源文件导入代码时,两者都应该很好。

To expand on runeh’s answer:

>>> def foo(a):
...    x = 2
...    return x + a

>>> import inspect

>>> inspect.getsource(foo)
u'def foo(a):\n    x = 2\n    return x + a\n'

print inspect.getsource(foo)
def foo(a):
   x = 2
   return x + a

EDIT: As pointed out by @0sh this example works using ipython but not plain python. It should be fine in both, however, when importing code from source files.


回答 6

您可以使用inspect模块来获取完整的源代码。你必须使用getsource()方法为从inspect模块。例如:

import inspect

def get_my_code():
    x = "abcd"
    return x

print(inspect.getsource(get_my_code))

您可以在下面的链接中查看更多选项。 检索您的python代码

You can use inspect module to get full source code for that. You have to use getsource() method for that from the inspect module. For example:

import inspect

def get_my_code():
    x = "abcd"
    return x

print(inspect.getsource(get_my_code))

You can check it out more options on the below link. retrieve your python code


回答 7

由于此帖子被标记为与其他帖子重复,因此我在这里针对“ lambda”案例回答,尽管OP与lambda无关。

因此,对于未在自己的行中定义的lambda函数:除了marko.ristin的答案,您可能希望使用mini-lambda此答案中建议的使用SymPy

  • mini-lambda 更轻巧,支持任何类型的操作,但仅适用于单个变量
  • SymPy较重,但配备了数学/微积分运算。特别是它可以简化您的表达。它还在同一表达式中支持多个变量。

您可以使用以下方法进行操作mini-lambda

from mini_lambda import x, is_mini_lambda_expr
import inspect

def get_source_code_str(f):
    if is_mini_lambda_expr(f):
        return f.to_string()
    else:
        return inspect.getsource(f)

# test it

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

print(get_source_code_str(foo))
print(get_source_code_str(x ** 2))

它正确产生

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

x ** 2

有关详细信息,请参见mini-lambda 文档。我是作者;)

Since this post is marked as the duplicate of this other post, I answer here for the “lambda” case, although the OP is not about lambdas.

So, for lambda functions that are not defined in their own lines: in addition to marko.ristin‘s answer, you may wish to use mini-lambda or use SymPy as suggested in this answer.

  • mini-lambda is lighter and supports any kind of operation, but works only for a single variable
  • SymPy is heavier but much more equipped with mathematical/calculus operations. In particular it can simplify your expressions. It also supports several variables in the same expression.

Here is how you can do it using mini-lambda:

from mini_lambda import x, is_mini_lambda_expr
import inspect

def get_source_code_str(f):
    if is_mini_lambda_expr(f):
        return f.to_string()
    else:
        return inspect.getsource(f)

# test it

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

print(get_source_code_str(foo))
print(get_source_code_str(x ** 2))

It correctly yields

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

x ** 2

See mini-lambda documentation for details. I’m the author by the way ;)


回答 8

请注意,只有在单独的行上给出lambda时,可接受的答案才有效。如果将其作为参数传递给函数,并希望将lambda的代码作为对象进行检索,则问题将变得有些棘手,因为这inspect将为您提供整行内容。

例如,考虑一个文件test.py

import inspect

def main():
    x, f = 3, lambda a: a + 1
    print(inspect.getsource(f))

if __name__ == "__main__":
    main()

执行它会给你(注意缩进!):

    x, f = 3, lambda a: a + 1

我认为,要检索lambda的源代码,最好的办法是重新解析整个源文件(使用f.__code__.co_filename),并通过行号及其上下文匹配lambda AST节点。

我们必须在按合同设计的库icontract中做到这一点,因为我们必须解析作为装饰器参数传入的lambda函数。在此处粘贴太多代码,因此请看一下此函数的实现

Please mind that the accepted answers work only if the lambda is given on a separate line. If you pass it in as an argument to a function and would like to retrieve the code of the lambda as object, the problem gets a bit tricky since inspect will give you the whole line.

For example, consider a file test.py:

import inspect

def main():
    x, f = 3, lambda a: a + 1
    print(inspect.getsource(f))

if __name__ == "__main__":
    main()

Executing it gives you (mind the indention!):

    x, f = 3, lambda a: a + 1

To retrieve the source code of the lambda, your best bet, in my opinion, is to re-parse the whole source file (by using f.__code__.co_filename) and match the lambda AST node by the line number and its context.

We had to do precisely that in our design-by-contract library icontract since we had to parse the lambda functions we pass in as arguments to decorators. It is too much code to paste here, so have a look at the implementation of this function.


回答 9

如果您要严格定义函数,并且定义相对简短,那么没有依赖性的解决方案是在字符串中定义函数并将表达式的eval()分配给函数。

例如

funcstring = 'lambda x: x> 5'
func = eval(funcstring)

然后可以选择将原始代码附加到该函数:

func.source = funcstring

If you’re strictly defining the function yourself and it’s a relatively short definition, a solution without dependencies would be to define the function in a string and assign the eval() of the expression to your function.

E.g.

funcstring = 'lambda x: x> 5'
func = eval(funcstring)

then optionally to attach the original code to the function:

func.source = funcstring

回答 10

总结一下:

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))

to summarize :

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))

回答 11

相信变量名称不会存储在pyc / pyd / pyo文件中,因此,如果没有源文件,则无法检索确切的代码行。

I believe that variable names aren’t stored in pyc/pyd/pyo files, so you can not retrieve the exact code lines if you don’t have source files.