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?
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.
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:
>>> 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’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?
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.
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:
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”.
>>>del locals()['os']>>> os
Traceback(most recent call last):File"<stdin>", line 1,in<module>NameError: name 'os'isnot defined
>>> os.path
Traceback(most recent call last):File"<stdin>", line 1,in<module>NameError: name 'os'isnot defined
>>>
>>> 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'isnot defined
>>>
让我们从中删除“路径” locals():
>>>del locals()['path']>>> path
Traceback(most recent call last):File"<stdin>", line 1,in<module>NameError: name 'path'isnot 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 ...:很高兴导入的项目无需模块名称前缀即可直接使用。缺点是您必须列出您使用的每件事,并且在代码中不清楚来源。
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
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.
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.
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.
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
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.
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 from … import 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.
public_variable =42
_private_variable =141def 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 workprint(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
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.
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:
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:
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
>>>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
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
In[1]:from a.b import c
In[2]: a
NameError: name 'a'isnot defined
In[2]: a.b
NameError: name 'a'isnot defined
In[3]: a.b.c
NameError: name 'a'isnot defined
In[4]: c
Out[4]:<module 'a.b.c'(namespace)>
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
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.
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.
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.
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:
>>> 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:
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:
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:
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.
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.
staticPyObject*
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;}
classQuitter(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:passraiseSystemExit(code)
__builtin__.quit =Quitter('quit')
__builtin__.exit =Quitter('exit')
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;
}
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()).
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.
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
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.
from flask import request
@app.route('/')@app.route('/data')def data():
query_string = request.query_string ## There is itreturn render_template("data.html")
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")
## here is my_script.py## import required flask packagesfrom 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
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 importFlask, request
app =Flask(__name__)@app.route('/data', methods=['GET'])def get_query_string():return request.query_string
if __name__ =='__main__':
app.run(debug=True)
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
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.
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:
(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.
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.
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:
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
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
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
(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.
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
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
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
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
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:
I’m having a hard time wrapping my brain around PEP 380.
What are the situations where “yield from” is useful?
What is the classic use case?
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中实现一堆新功能。
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 readerfor v in g:yield v
wrap = reader_wrapper(reader())for i in wrap:print(i)# Result<<0<<1<<2<<3
def writer_wrapper(coro):# TBDpass
w = writer()
wrap = writer_wrapper(w)
wrap.send(None)# "prime" the coroutinefor 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 corowhileTrue:try:
x =(yield)# Capture the value that's sent
coro.send(x)# and pass it to the writerexceptStopIteration:pass
classSpamException(Exception):passdef writer():whileTrue:try:
w =(yield)exceptSpamException:print('***')else:print('>> ', w)
如果我们不改变writer_wrapper怎么办?它行得通吗?我们试试吧
# writer_wrapper same as above
w = writer()
wrap = writer_wrapper(w)
wrap.send(None)# "prime" the coroutinefor 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>>2Traceback(most recent call last):... redacted ...File...in writer_wrapper
x =(yield)
__main__.SpamException
def writer_wrapper(coro):"""Works. Manually catches exceptions and throws them"""
coro.send(None)# prime the corowhileTrue:try:try:
x =(yield)exceptExceptionas e:# This catches the SpamException
coro.throw(e)else:
coro.send(x)exceptStopIteration:pass
Let’s get one thing out of the way first. The explanation that yield from g is equivalent to for v in g: yield vdoes 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:
PEP 380 – Syntax for delegating to a sub-generator (Ewing) [v3.3, 2009-02-13]
PEP 342 –
Coroutines via Enhanced Generators (GvR, Eby) [v2.5, 2005-05-10]
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循环忽略的所有极端情况。成为“丑闻”会鼓励人们使用它,从而获得正确的行为。
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.
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__'):yieldfrom 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 keyworddef chain(*iters):for it in iters:yieldfrom it
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.
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.
await is used for async def coroutine. (since Python 3.5+)
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.
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.
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.)
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 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(...)).
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])
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.
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”
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.
In[19]: foo??Signature: foo(arg1, arg2)Source:def foo(arg1,arg2):#do something with args
a = arg1 + arg2return aFile:~/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
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.
>>>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 =2return x + a
>>> 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.
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 itdef 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
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-lambdadocumentation for details. I’m the author by the way ;)
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.
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.