分类目录归档:知识问答

Python中抽象类和接口之间的区别

问题:Python中抽象类和接口之间的区别

Python中的抽象类和接口有什么区别?

What is the difference between abstract class and interface in Python?


回答 0

有时您会看到以下内容:

class Abstract1( object ):
    """Some description that tells you it's abstract,
    often listing the methods you're expected to supply."""
    def aMethod( self ):
        raise NotImplementedError( "Should have implemented this" )

由于Python没有(也不需要)正式的Interface协定,因此不存在抽象和接口之间的Java风格区别。如果有人努力定义一个正式的接口,它也将是一个抽象类。唯一的区别在于文档字符串中所述的意图。

当您进行鸭类打字时,抽象和接口之间的区别是令人不解的事情。

Java使用接口是因为它没有多重继承。

由于Python具有多重继承,因此您可能还会看到类似这样的内容

class SomeAbstraction( object ):
    pass # lots of stuff - but missing something

class Mixin1( object ):
    def something( self ):
        pass # one implementation

class Mixin2( object ):
    def something( self ):
        pass # another

class Concrete1( SomeAbstraction, Mixin1 ):
    pass

class Concrete2( SomeAbstraction, Mixin2 ):
    pass

这使用一种带有混合类的抽象超类来创建不相交的具体子类。

What you’ll see sometimes is the following:

class Abstract1( object ):
    """Some description that tells you it's abstract,
    often listing the methods you're expected to supply."""
    def aMethod( self ):
        raise NotImplementedError( "Should have implemented this" )

Because Python doesn’t have (and doesn’t need) a formal Interface contract, the Java-style distinction between abstraction and interface doesn’t exist. If someone goes through the effort to define a formal interface, it will also be an abstract class. The only differences would be in the stated intent in the docstring.

And the difference between abstract and interface is a hairsplitting thing when you have duck typing.

Java uses interfaces because it doesn’t have multiple inheritance.

Because Python has multiple inheritance, you may also see something like this

class SomeAbstraction( object ):
    pass # lots of stuff - but missing something

class Mixin1( object ):
    def something( self ):
        pass # one implementation

class Mixin2( object ):
    def something( self ):
        pass # another

class Concrete1( SomeAbstraction, Mixin1 ):
    pass

class Concrete2( SomeAbstraction, Mixin2 ):
    pass

This uses a kind of abstract superclass with mixins to create concrete subclasses that are disjoint.


回答 1

Python中的抽象类和接口有什么区别?

对象的接口是该对象上的一组方法和属性。

在Python中,我们可以使用抽象基类来定义和执行接口。

使用抽象基类

例如,假设我们要使用collections模块中的抽象基类之一:

import collections
class MySet(collections.Set):
    pass

如果尝试使用它,则会得到一个,TypeError因为我们创建的类不支持集合的预期行为:

>>> MySet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__

因此,我们必须执行在至少 __contains____iter____len__。让我们使用文档中的实现示例:

class ListBasedSet(collections.Set):
    """Alternate set implementation favoring space over speed
    and not requiring the set elements to be hashable. 
    """
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2

实现:创建抽象基类

我们可以通过将元类设置为abc.ABCMetaabc.abstractmethod在相关方法上使用装饰器来创建自己的抽象基类。元类将被装饰的函数添加到__abstractmethods__属性中,从而防止实例化直到定义它们。

import abc

例如,“有效的”被定义为可以用词表达的东西。假设我们想在Python 2中定义一个有效的抽象基类:

class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

或在Python 3中,在元类声明中稍有变化:

class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

现在,如果我们尝试在不实现接口的情况下创建有效对象:

class MyEffable(Effable): 
    pass

并尝试实例化它:

>>> MyEffable()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__

我们被告知我们尚未完成工作。

现在,如果我们通过提供预期的接口来遵守:

class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

然后,我们可以使用从抽象类派生的类的具体版本:

>>> me = MyEffable()
>>> print(me)
expressable!

我们可以做其他事情,例如注册已经实现这些接口的虚拟子类,但是我认为这超出了这个问题的范围。但是,此处演示的其他方法必须使用abc模块来适应此方法。

结论

我们已经证明了抽象基类的创建为Python中的自定义对象定义了接口。

What is the difference between abstract class and interface in Python?

An interface, for an object, is a set of methods and attributes on that object.

In Python, we can use an abstract base class to define and enforce an interface.

Using an Abstract Base Class

For example, say we want to use one of the abstract base classes from the collections module:

import collections
class MySet(collections.Set):
    pass

If we try to use it, we get an TypeError because the class we created does not support the expected behavior of sets:

>>> MySet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__

So we are required to implement at least __contains__, __iter__, and __len__. Let’s use this implementation example from the documentation:

class ListBasedSet(collections.Set):
    """Alternate set implementation favoring space over speed
    and not requiring the set elements to be hashable. 
    """
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2

Implementation: Creating an Abstract Base Class

We can create our own Abstract Base Class by setting the metaclass to abc.ABCMeta and using the abc.abstractmethod decorator on relevant methods. The metaclass will be add the decorated functions to the __abstractmethods__ attribute, preventing instantiation until those are defined.

import abc

For example, “effable” is defined as something that can be expressed in words. Say we wanted to define an abstract base class that is effable, in Python 2:

class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

Or in Python 3, with the slight change in metaclass declaration:

class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

Now if we try to create an effable object without implementing the interface:

class MyEffable(Effable): 
    pass

and attempt to instantiate it:

>>> MyEffable()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__

We are told that we haven’t finished the job.

Now if we comply by providing the expected interface:

class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

we are then able to use the concrete version of the class derived from the abstract one:

>>> me = MyEffable()
>>> print(me)
expressable!

There are other things we could do with this, like register virtual subclasses that already implement these interfaces, but I think that is beyond the scope of this question. The other methods demonstrated here would have to adapt this method using the abc module to do so, however.

Conclusion

We have demonstrated that the creation of an Abstract Base Class defines interfaces for custom objects in Python.


回答 2

Python> = 2.6具有抽象基类

当诸如hasattr()之类的其他技术笨拙时,抽象基类(缩写为ABC)通过提供一种定义接口的方式来补充鸭式输入。Python随附了许多内置的ABC,用于数据结构(在collections模块中),数字(在numbers模块中)和流(在io模块中)。您可以使用abc模块创建自己的ABC。

还有一个Zope接口模块,该模块由zope外部的项目使用,例如扭曲。我不是很熟悉,但有一个wiki页面在这里可能会有帮助。

通常,您不需要抽象类或python中的接口的概念(已编辑-有关详细信息,请参见S.Lott的答案)。

Python >= 2.6 has Abstract Base Classes.

Abstract Base Classes (abbreviated ABCs) complement duck-typing by providing a way to define interfaces when other techniques like hasattr() would be clumsy. Python comes with many builtin ABCs for data structures (in the collections module), numbers (in the numbers module), and streams (in the io module). You can create your own ABC with the abc module.

There is also the Zope Interface module, which is used by projects outside of zope, like twisted. I’m not really familiar with it, but there’s a wiki page here that might help.

In general, you don’t need the concept of abstract classes, or interfaces in python (edited – see S.Lott’s answer for details).


回答 3

Python实际上没有任何一个概念。

它使用鸭子类型,从而消除了对接口的需求(至少对于计算机:-)。

Python <= 2.5:基类显然存在,但是没有明确的方法将方法标记为“纯虚拟”,因此该类并不是真正的抽象。

Python> = 2.6:确实存在抽象基类(http://docs.python.org/library/abc.html)。并允许您指定必须在子类中实现的方法。我不太喜欢语法,但是功能在那里。在大多数情况下,最好从“使用”客户端使用鸭子类型。

Python doesn’t really have either concept.

It uses duck typing, which removed the need for interfaces (at least for the computer :-))

Python <= 2.5: Base classes obviously exist, but there is no explicit way to mark a method as ‘pure virtual’, so the class isn’t really abstract.

Python >= 2.6: Abstract base classes do exist (http://docs.python.org/library/abc.html). And allow you to specify methods that must be implemented in subclasses. I don’t much like the syntax, but the feature is there. Most of the time it’s probably better to use duck typing from the ‘using’ client side.


回答 4

用更基本的方式解释:接口有点像一个空的松饼锅。这是一个类文件,带有一组没有代码的方法定义。

抽象类是一回事,但并非所有功能都必须为空。有些可以有代码。并非严格意义上是空的。

为什么要区分:Python并没有太大的实际区别,但是在大型项目的计划级别上,谈论接口可能更常见,因为没有代码。尤其是在您与习惯该术语的Java程序员一起工作时。

In a more basic way to explain: An interface is sort of like an empty muffin pan. It’s a class file with a set of method definitions that have no code.

An abstract class is the same thing, but not all functions need to be empty. Some can have code. It’s not strictly empty.

Why differentiate: There’s not much practical difference in Python, but on the planning level for a large project, it could be more common to talk about interfaces, since there’s no code. Especially if you’re working with Java programmers who are accustomed to the term.


回答 5

通常,仅在使用单继承类模型的语言中使用接口。在这些单继承语言中,如果任何类可以使用特定方法或方法集,则通常使用接口。同样在这些单继承语言中,抽象类用于除了没有一个或多个方法之外还具有定义的类变量,或者用于利用单继承模型来限制可以使用一组方法的类的范围。

支持多重继承模型的语言倾向于仅使用类或抽象基类,而不使用接口。由于Python支持多重继承,因此它不使用接口,而您想使用基类或抽象基类。

http://docs.python.org/library/abc.html

In general, interfaces are used only in languages that use the single-inheritance class model. In these single-inheritance languages, interfaces are typically used if any class could use a particular method or set of methods. Also in these single-inheritance languages, abstract classes are used to either have defined class variables in addition to none or more methods, or to exploit the single-inheritance model to limit the range of classes that could use a set of methods.

Languages that support the multiple-inheritance model tend to use only classes or abstract base classes and not interfaces. Since Python supports multiple inheritance, it does not use interfaces and you would want to use base classes or abstract base classes.

http://docs.python.org/library/abc.html


回答 6

抽象类是包含一个或多个抽象方法的类。除抽象方法外,抽象类还可以具有静态方法,类方法和实例方法。但是在接口的情况下,它将仅具有抽象方法,而没有其他方法。因此,继承抽象类不是强制性的,但是继承接口是强制性的。

Abstract classes are classes that contain one or more abstract methods. Along with abstract methods, Abstract classes can have static, class and instance methods. But in case of interface, it will only have abstract methods not other. Hence it is not compulsory to inherit abstract class but it is compulsory to inherit interface.


回答 7

为了完整起见,我们应该提到PEP3119 ,其中引入了ABC并与接口进行了比较,还有原始的塔林评论。

抽象类不是完美的接口:

  • 属于继承层次
  • 易变

但是,如果您考虑以自己的方式编写它:

def some_function(self):
     raise NotImplementedError()

interface = type(
    'your_interface', (object,),
    {'extra_func': some_function,
     '__slots__': ['extra_func', ...]
     ...
     '__instancecheck__': your_instance_checker,
     '__subclasscheck__': your_subclass_checker
     ...
    }
)

ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...

您会很快意识到自己正在发明轮子以最终实现 abc.ABCMeta

abc.ABCMeta 被提议作为缺少接口功能的有用补充,并且在像python这样的语言中已经足够了。

当然,在编写版本3并添加新语法和不可变接口概念时,它可以得到更好的增强。

结论:

The abc.ABCMeta IS "pythonic" interface in python

For completeness, we should mention PEP3119 where ABC was introduced and compared with interfaces, and original Talin’s comment.

The abstract class is not perfect interface:

  • belongs to the inheritance hierarchy
  • is mutable

But if you consider writing it your own way:

def some_function(self):
     raise NotImplementedError()

interface = type(
    'your_interface', (object,),
    {'extra_func': some_function,
     '__slots__': ['extra_func', ...]
     ...
     '__instancecheck__': your_instance_checker,
     '__subclasscheck__': your_subclass_checker
     ...
    }
)

ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...

you’ll quite fast realize that you’re inventing the wheel to eventually achieve abc.ABCMeta

abc.ABCMeta was proposed as a useful addition of the missing interface functionality, and that’s fair enough in a language like python.

Certainly, it was able to be enhanced better whilst writing version 3, and adding new syntax and immutable interface concept …

Conclusion:

The abc.ABCMeta IS "pythonic" interface in python

如何遍历给定目录中的文件?

问题:如何遍历给定目录中的文件?

我需要遍历.asm给定目录内的所有文件并对它们执行一些操作。

如何有效地做到这一点?

I need to iterate through all .asm files inside a given directory and do some actions on them.

How can this be done in a efficient way?


回答 0

原始答案:

import os

for filename in os.listdir(directory):
    if filename.endswith(".asm") or filename.endswith(".py"): 
         # print(os.path.join(directory, filename))
        continue
    else:
        continue

上面答案的Python 3.6版本,使用os-假设您将目录路径作为str对象包含在名为的变量中directory_in_str

import os

directory = os.fsencode(directory_in_str)

for file in os.listdir(directory):
     filename = os.fsdecode(file)
     if filename.endswith(".asm") or filename.endswith(".py"): 
         # print(os.path.join(directory, filename))
         continue
     else:
         continue

或递归使用pathlib

from pathlib import Path

pathlist = Path(directory_in_str).glob('**/*.asm')
for path in pathlist:
     # because path is object not string
     path_in_str = str(path)
     # print(path_in_str)

Original answer:

import os

for filename in os.listdir(directory):
    if filename.endswith(".asm") or filename.endswith(".py"): 
         # print(os.path.join(directory, filename))
        continue
    else:
        continue

Python 3.6 version of the above answer, using os – assuming that you have the directory path as a str object in a variable called directory_in_str:

import os

directory = os.fsencode(directory_in_str)

for file in os.listdir(directory):
     filename = os.fsdecode(file)
     if filename.endswith(".asm") or filename.endswith(".py"): 
         # print(os.path.join(directory, filename))
         continue
     else:
         continue

Or recursively, using pathlib:

from pathlib import Path

pathlist = Path(directory_in_str).glob('**/*.asm')
for path in pathlist:
     # because path is object not string
     path_in_str = str(path)
     # print(path_in_str)

回答 1

这将遍历所有后代文件,而不仅仅是目录的直接子级:

import os

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        #print os.path.join(subdir, file)
        filepath = subdir + os.sep + file

        if filepath.endswith(".asm"):
            print (filepath)

This will iterate over all descendant files, not just the immediate children of the directory:

import os

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        #print os.path.join(subdir, file)
        filepath = subdir + os.sep + file

        if filepath.endswith(".asm"):
            print (filepath)

回答 2

您可以尝试使用glob模块:

import glob

for filepath in glob.iglob('my_dir/*.asm'):
    print(filepath)

从Python 3.5开始,您还可以搜索子目录:

glob.glob('**/*.txt', recursive=True) # => ['2.txt', 'sub/3.txt']

从文档:

glob模块根据Unix shell使用的规则查找与指定模式匹配的所有路径名,尽管结果以任意顺序返回。没有波浪符号扩展,但是* 、?和用[]表示的字符范围将正确匹配。

You can try using glob module:

import glob

for filepath in glob.iglob('my_dir/*.asm'):
    print(filepath)

and since Python 3.5 you can search subdirectories as well:

glob.glob('**/*.txt', recursive=True) # => ['2.txt', 'sub/3.txt']

From the docs:

The glob module finds all the pathnames matching a specified pattern according to the rules used by the Unix shell, although results are returned in arbitrary order. No tilde expansion is done, but *, ?, and character ranges expressed with [] will be correctly matched.


回答 3

从Python 3.5开始,使用os.scandir()可以轻松得多

with os.scandir(path) as it:
    for entry in it:
        if entry.name.endswith(".asm") and entry.is_file():
            print(entry.name, entry.path)

使用scandir()而不是listdir()可以显着提高还需要文件类型或文件属性信息的代码的性能,因为如果操作系统在扫描目录时提供了os.DirEntry对象,则os.DirEntry对象将公开此信息。所有的os.DirEntry方法都可以执行系统调用,但是is_dir()和is_file()通常只需要系统调用即可进行符号链接。os.DirEntry.stat()在Unix上始终需要系统调用,而在Windows上只需要一个系统调用即可。

Since Python 3.5, things are much easier with os.scandir()

with os.scandir(path) as it:
    for entry in it:
        if entry.name.endswith(".asm") and entry.is_file():
            print(entry.name, entry.path)

Using scandir() instead of listdir() can significantly increase the performance of code that also needs file type or file attribute information, because os.DirEntry objects expose this information if the operating system provides it when scanning a directory. All os.DirEntry methods may perform a system call, but is_dir() and is_file() usually only require a system call for symbolic links; os.DirEntry.stat() always requires a system call on Unix but only requires one for symbolic links on Windows.


回答 4

Python 3.4和更高版本在标准库中提供pathlib。您可以这样做:

from pathlib import Path

asm_pths = [pth for pth in Path.cwd().iterdir()
            if pth.suffix == '.asm']

或者,如果您不喜欢列表推导:

asm_paths = []
for pth in Path.cwd().iterdir():
    if pth.suffix == '.asm':
        asm_pths.append(pth)

Path 对象可以轻松转换为字符串。

Python 3.4 and later offer pathlib in the standard library. You could do:

from pathlib import Path

asm_pths = [pth for pth in Path.cwd().iterdir()
            if pth.suffix == '.asm']

Or if you don’t like list comprehensions:

asm_paths = []
for pth in Path.cwd().iterdir():
    if pth.suffix == '.asm':
        asm_pths.append(pth)

Path objects can easily be converted to strings.


回答 5

这是我遍历Python中文件的方式:

import os

path = 'the/name/of/your/path'

folder = os.fsencode(path)

filenames = []

for file in os.listdir(folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ): # whatever file types you're using...
        filenames.append(filename)

filenames.sort() # now you have the filenames and can do something with them

这些技术均无法保证任何迭代顺序

是的,超级变幻莫测。请注意,我对文件名进行了排序,这在文件顺序很重要的情况下很重要,例如,对于视频帧或与时间有关的数据收集。不过,请务必在文件名中添加索引!

Here’s how I iterate through files in Python:

import os

path = 'the/name/of/your/path'

folder = os.fsencode(path)

filenames = []

for file in os.listdir(folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ): # whatever file types you're using...
        filenames.append(filename)

filenames.sort() # now you have the filenames and can do something with them

NONE OF THESE TECHNIQUES GUARANTEE ANY ITERATION ORDERING

Yup, super unpredictable. Notice that I sort the filenames, which is important if the order of the files matters, i.e. for video frames or time dependent data collection. Be sure to put indices in your filenames though!


回答 6

您可以使用glob来引用目录和列表:

import glob
import os

#to get the current working directory name
cwd = os.getcwd()
#Load the images from images folder.
for f in glob.glob('images\*.jpg'):   
    dir_name = get_dir_name(f)
    image_file_name = dir_name + '.jpg'
    #To print the file name with path (path will be in string)
    print (image_file_name)

要获取数组中所有目录的列表,可以使用os

os.listdir(directory)

You can use glob for referring the directory and the list :

import glob
import os

#to get the current working directory name
cwd = os.getcwd()
#Load the images from images folder.
for f in glob.glob('images\*.jpg'):   
    dir_name = get_dir_name(f)
    image_file_name = dir_name + '.jpg'
    #To print the file name with path (path will be in string)
    print (image_file_name)

To get the list of all directory in array you can use os :

os.listdir(directory)

回答 7

我对该实现还不太满意,我想拥有一个自定义构造函数,DirectoryIndex._make(next(os.walk(input_path)))该构造函数可以使您只传递要为其列出文件的路径。欢迎编辑!

import collections
import os

DirectoryIndex = collections.namedtuple('DirectoryIndex', ['root', 'dirs', 'files'])

for file_name in DirectoryIndex(*next(os.walk('.'))).files:
    file_path = os.path.join(path, file_name)

I’m not quite happy with this implementation yet, I wanted to have a custom constructor that does DirectoryIndex._make(next(os.walk(input_path))) such that you can just pass the path you want a file listing for. Edits welcome!

import collections
import os

DirectoryIndex = collections.namedtuple('DirectoryIndex', ['root', 'dirs', 'files'])

for file_name in DirectoryIndex(*next(os.walk('.'))).files:
    file_path = os.path.join(path, file_name)

回答 8

我真的很喜欢使用库中scandir内置的指令os。这是一个工作示例:

import os

i = 0
with os.scandir('/usr/local/bin') as root_dir:
    for path in root_dir:
        if path.is_file():
            i += 1
            print(f"Full path is: {path} and just the name is: {path.name}")
print(f"{i} files scanned successfully.")

I really like using the scandir directive that is built into the os library. Here is a working example:

import os

i = 0
with os.scandir('/usr/local/bin') as root_dir:
    for path in root_dir:
        if path.is_file():
            i += 1
            print(f"Full path is: {path} and just the name is: {path.name}")
print(f"{i} files scanned successfully.")

如何在Python 3中使用raw_input

问题:如何在Python 3中使用raw_input

import sys
print(sys.platform)
print(2**100)
raw_input()

我正在使用Python 3.1,无法raw_input“冻结” dos弹出窗口。我正在阅读的书是针对Python 2.5的,而我正在使用Python 3.1

我应该怎么做才能解决这个问题?

import sys
print(sys.platform)
print(2**100)
raw_input()

I am using Python 3.1 and can’t get the raw_input to “freeze” the dos pop-up. The book I’m reading is for Python 2.5 and I’m using Python 3.1

What should I do to fix this?


回答 0

从Python 3开始,raw_input()已重命名为input()

摘自Python 3.0的新增功能,“内置”部分的第二项。

Starting with Python 3, raw_input() was renamed to input().

From What’s New In Python 3.0, Builtins section second item.


回答 1

这适用于Python 3.x和2.x:

# Fix Python 2.x.
try: input = raw_input
except NameError: pass
print("Hi " + input("Say something: "))

This works in Python 3.x and 2.x:

# Fix Python 2.x.
try: input = raw_input
except NameError: pass
print("Hi " + input("Say something: "))

回答 2

解决此问题的可靠方法是

from six.moves import input

是一个模块,可修补许多2/3通用代码基础痛点。

A reliable way to address this is

from six.moves import input

six is a module which patches over many of the 2/3 common code base pain points.


回答 3

正如其他人所指出的那样,该raw_input函数已input在Python 3.0中重命名为,确实可以得到一本更新的书来更好地服务,但我想指出的是,有更好的方法可以查看脚本的输出。

根据您的描述,我认为您正在使用Windows,已经保存了一个.py文件,然后双击它来运行它。程序结束后,弹出的终端窗口将立即关闭,因此您看不到程序的结果是什么。为了解决这个问题,您的书建议添加raw_input/input语句,直到用户按下Enter键。但是,正如您所看到的,如果出现问题(例如程序中的错误),则该语句将不会执行,并且在您看不到问题出在哪里之前,该窗口将关闭。您可能会发现使用命令提示符或IDLE更容易。

使用命令提示符

当您查看包含Python程序的文件夹窗口时,请按住shift键并右键单击窗口白色背景区域中的任意位置。弹出的菜单应包含“此处打开命令窗口”条目。(我认为这适用于Windows Vista和Windows7。)这将打开一个命令提示符窗口,如下所示:

    Microsoft Windows [Version 6.1.7601]
    Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

    C:\Users\Weeble\My Python Program>_

要运行您的程序,请键入以下内容(替换您的脚本名称):

    python myscript.py

…然后按Enter。(如果收到“ python”不是可识别的命令的错误,请参阅http://showmedo.com/videotutorials/video?name=960000&fromSeriesID=96)当程序完成运行时,无论是否成功完成,该窗口将保持打开状态,并且命令提示符将再次出现,以供您键入其他命令。如果要再次运行程序,则可以按向上箭头以调出您输入的上一个命令,然后按Enter键再次运行它,而不必每次都键入文件名。

使用IDLE

IDLE是随Python一起安装的简单程序编辑器。除其他功能外,它还可以在窗口中运行程序。右键单击您的.py文件,然后选择“在IDLE中编辑”。当您的程序出现在编辑器中时,按F5或从“运行”菜单中选择“运行模块”。程序将在程序结束后的窗口中运行,您可以在其中输入Python命令以立即运行。

As others have indicated, the raw_input function has been renamed to input in Python 3.0, and you really would be better served by a more up-to-date book, but I want to point out that there are better ways to see the output of your script.

From your description, I think you’re using Windows, you’ve saved a .py file and then you’re double-clicking on it to run it. The terminal window that pops up closes as soon as your program ends, so you can’t see what the result of your program was. To solve this, your book recommends adding a raw_input / input statement to wait until the user presses enter. However, as you’ve seen, if something goes wrong, such as an error in your program, that statement won’t be executed and the window will close without you being able to see what went wrong. You might find it easier to use a command-prompt or IDLE.

Use a command-prompt

When you’re looking at the folder window that contains your Python program, hold down shift and right-click anywhere in the white background area of the window. The menu that pops up should contain an entry “Open command window here”. (I think this works on Windows Vista and Windows 7.) This will open a command-prompt window that looks something like this:

    Microsoft Windows [Version 6.1.7601]
    Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

    C:\Users\Weeble\My Python Program>_

To run your program, type the following (substituting your script name):

    python myscript.py

…and press enter. (If you get an error that “python” is not a recognized command, see http://showmedo.com/videotutorials/video?name=960000&fromSeriesID=96 ) When your program finishes running, whether it completes successfully or not, the window will remain open and the command-prompt will appear again for you to type another command. If you want to run your program again, you can press the up arrow to recall the previous command you entered and press enter to run it again, rather than having to type out the file name every time.

Use IDLE

IDLE is a simple program editor that comes installed with Python. Among other features it can run your programs in a window. Right-click on your .py file and choose “Edit in IDLE”. When your program appears in the editor, press F5 or choose “Run module” from the “Run” menu. Your program will run in a window that stays open after your program ends, and in which you can enter Python commands to run immediately.


回答 4

Timmerman的解决方案在运行代码时效果很好,但是如果您不想Undefined name在使用pyflakes或类似的linter时出错,则可以使用以下代码:

try:
    import __builtin__
    input = getattr(__builtin__, 'raw_input')
except (ImportError, AttributeError):
    pass

Timmerman’s solution works great when running the code, but if you don’t want to get Undefined name errors when using pyflakes or a similar linter you could use the following instead:

try:
    import __builtin__
    input = getattr(__builtin__, 'raw_input')
except (ImportError, AttributeError):
    pass

回答 5

这是我在脚本中输入的一段代码,我不想在与py2 / 3无关的环境中运行:

# Thank you, python2-3 team, for making such a fantastic mess with
# input/raw_input :-)
real_raw_input = vars(__builtins__).get('raw_input',input)

现在,您可以使用real_raw_input。它相当昂贵,但简短易读。使用原始输入通常很耗时(等待输入),因此并不重要。

从理论上讲,您甚至可以分配raw_input而不是real_raw_input,但是可能会有一些模块检查raw_input的存在并相应地运行。最好保持安全。

Here’s a piece of code I put in my scripts that I wan’t to run in py2/3-agnostic environment:

# Thank you, python2-3 team, for making such a fantastic mess with
# input/raw_input :-)
real_raw_input = vars(__builtins__).get('raw_input',input)

Now you can use real_raw_input. It’s quite expensive but short and readable. Using raw input is usually time expensive (waiting for input), so it’s not important.

In theory, you can even assign raw_input instead of real_raw_input but there might be modules that check existence of raw_input and behave accordingly. It’s better stay on the safe side.


回答 6

可能不是最好的解决方案,但是在我来这里之前,我只是在不停学习的情况下即时进行此操作以保持工作状态。

def raw_input(x):
  input(x)

然后,当我raw_input('Enter your first name: ')在我正在处理的脚本上运行时,它会捕获它input()

可能有一个原因,我还没有遇到呢!

Probably not the best solution, but before I came here I just made this on the fly to keep working without having a quick break from study.

def raw_input(x):
  input(x)

Then when I run raw_input('Enter your first name: ') on the script I was working on, it captures it as does input() would.

There may be a reason not to do this, that I haven’t come across yet!


如何使用Python 3安装pip?

问题:如何使用Python 3安装pip?

我要安装pip。它应支持Python 3,但需要setuptools,该工具仅适用于Python 2。

如何使用Python 3安装pip?

I want to install pip. It should support Python 3, but it requires setuptools, which is available only for Python 2.

How can I install pip with Python 3?


回答 0

编辑:手动安装和使用setuptools不再是标准过程。

如果您运行的是Python 2.7.9+或Python 3.4+

恭喜,您应该已经pip安装了。如果您不这样做,请继续阅读。

如果您正在运行类似Unix的系统

pip如果您的Python版本低于2.7.9或3.4,或者您的系统出于任何原因未包含该软件包,通常可以通过软件包管理器进行安装。

以下是一些更常见发行版的说明。

在适用于Python 2.x的Debian(Wheezy和更高版本)和Ubuntu(Trusty Tahr和更高版本)上安装

从终端运行以下命令:

sudo apt-get install python-pip 

在适用于Python 3.x的Debian(Wheezy和更高版本)和Ubuntu(Trusty Tahr和更高版本)上安装

从终端运行以下命令:

sudo apt-get install python3-pip
注意:

在全新安装的Debian / Ubuntu中,只有在执行以下操作后才能找到该软件包:

sudo apt-get update

pip在适用于Python 2.x的CentOS 7上安装

在CentOS 7上,您必须先安装设置工具,然后再使用它来安装pip,因为它没有直接的软件包。

sudo yum install python-setuptools
sudo easy_install pip

pip在适用于Python 3.x的CentOS 7上安装

假设您从EPEL安装了Python 3.4 ,则可以安装Python 3的设置工具并使用它进行安装pip

# First command requires you to have enabled EPEL for CentOS7
sudo yum install python34-setuptools
sudo easy_install pip

如果您的Unix / Linux发行版未在软件包repos中包含它

使用下面详细介绍的手动方法进行安装。

手动方式

如果您想手动进行操作,现在推荐的方法是使用安装说明中get-pip.py脚本进行pip安装

安装点子

要安装pip,请安全下载 get-pip.py

然后运行以下命令(可能需要管理员访问权限):

python get-pip.py 

如果setuptools尚未安装,get-pip.py将为您安装setuptools。

edit: Manual installation and use of setuptools is not the standard process anymore.

If you’re running Python 2.7.9+ or Python 3.4+

Congrats, you should already have pip installed. If you do not, read onward.

If you’re running a Unix-like System

You can usually install the package for pip through your package manager if your version of Python is older than 2.7.9 or 3.4, or if your system did not include it for whatever reason.

Instructions for some of the more common distros follow.

Installing on Debian (Wheezy and newer) and Ubuntu (Trusty Tahr and newer) for Python 2.x

Run the following command from a terminal:

sudo apt-get install python-pip 

Installing on Debian (Wheezy and newer) and Ubuntu (Trusty Tahr and newer) for Python 3.x

Run the following command from a terminal:

sudo apt-get install python3-pip
Note:

On a fresh Debian/Ubuntu install, the package may not be found until you do:

sudo apt-get update

Installing pip on CentOS 7 for Python 2.x

On CentOS 7, you have to install setup tools first, and then use that to install pip, as there is no direct package for it.

sudo yum install python-setuptools
sudo easy_install pip

Installing pip on CentOS 7 for Python 3.x

Assuming you installed Python 3.4 from EPEL, you can install Python 3’s setup tools and use it to install pip.

# First command requires you to have enabled EPEL for CentOS7
sudo yum install python34-setuptools
sudo easy_install pip

If your Unix/Linux distro doesn’t have it in package repos

Install using the manual way detailed below.

The manual way

If you want to do it the manual way, the now-recommended method is to install using the get-pip.py script from pip‘s installation instructions.

Install pip

To install pip, securely download get-pip.py

Then run the following (which may require administrator access):

python get-pip.py 

If setuptools is not already installed, get-pip.py will install setuptools for you.


回答 1

我可以通过运行Ubuntu在python 3上安装pip sudo apt-get install python3-pip

I was able to install pip for python 3 on Ubuntu just by running sudo apt-get install python3-pip.


回答 2

Python 3.4以上和Python 2.7.9以上

好消息!Pip随附了Python 3.4(2014年3月发布)。这是所有Python版本中的最佳功能。它使每个人都可以访问社区丰富的图书馆。新手不再因安装的困难而被排除在外。在与软件包管理器一起交付时,Python加入了Ruby,Nodejs,Haskell,Perl,Go以及几乎所有其他具有主流开源社区的当代语言。谢谢Python。

当然,这并不意味着Python打包已解决问题。经验仍然令人沮丧。我在Python是否有软件包/模块管理系统中讨论了这一点

las惜使用早期Python的每个人。遵循手册说明。

Python≤2.7.8和Python≤3.3

按照我的详细说明在 https://stackoverflow.com/a/12476379/284795。实质上

官方指示

根据https://pip.pypa.io/en/stable/installing.html

下载时get-pip.py,请小心保存为.py文件而不是文件.txt。然后,在命令提示符下运行它。

python get-pip.py

您可能需要管理员命令提示符才能执行此操作。遵循http://technet.microsoft.com/en-us/library/cc947813(v=ws.10).aspx

对我来说,此安装点位于C:\Python27\Scripts\pip.exepip.exe在您的计算机上查找,然后将其文件夹(例如C:\Python27\Scripts)添加 到您的路径(开始/编辑环境变量)。现在,您应该可以从命令行运行pip了。尝试安装软件包:

pip install httpie

你去了(希望)!

Python 3.4+ and Python 2.7.9+

Good news! Python 3.4 (released March 2014) ships with Pip. This is the best feature of any Python release. It makes the community’s wealth of libraries accessible to everyone. Newbies are no longer excluded by the prohibitive difficulty of setup. In shipping with a package manager, Python joins Ruby, Nodejs, Haskell, Perl, Go–almost every other contemporary language with a majority open-source community. Thank you Python.

Of course, that doesn’t mean Python packaging is problem solved. The experience remains frustrating. I discuss this at Does Python have a package/module management system?

Alas for everyone using an earlier Python. Manual instructions follow.

Python ≤ 2.7.8 and Python ≤ 3.3

Follow my detailed instructions at https://stackoverflow.com/a/12476379/284795 . Essentially

Official instructions

Per https://pip.pypa.io/en/stable/installing.html

Download get-pip.py, being careful to save it as a .py file rather than .txt. Then, run it from the command prompt.

python get-pip.py

You possibly need an administrator command prompt to do this. Follow http://technet.microsoft.com/en-us/library/cc947813(v=ws.10).aspx

For me, this installed Pip at C:\Python27\Scripts\pip.exe. Find pip.exe on your computer, then add its folder (eg. C:\Python27\Scripts) to your path (Start / Edit environment variables). Now you should be able to run pip from the command line. Try installing a package:

pip install httpie

There you go (hopefully)!


回答 3

对于Ubuntu 12.04或更旧版本,

sudo apt-get install python3-pip

将无法正常工作。而是使用:

sudo apt-get install python3-setuptools ca-certificates
sudo easy_install3 pip

For Ubuntu 12.04 or older,

sudo apt-get install python3-pip

won’t work. Instead, use:

sudo apt-get install python3-setuptools ca-certificates
sudo easy_install3 pip

回答 4

如果您使用的是python 3.4+

只需输入:

python3 -m pip

if you’re using python 3.4+

just type:

python3 -m pip

回答 5

2015年1月20日更新:

根据https://pip.pypa.io/en/latest/installing.html,当前方式为:

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

我认为这适用于任何版本


原始答案:

wget http://python-distribute.org/distribute_setup.py
python distribute_setup.py
easy_install pip

Update 2015-01-20:

As per https://pip.pypa.io/en/latest/installing.html the current way is:

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

I think that should work for any version


Original Answer:

wget http://python-distribute.org/distribute_setup.py
python distribute_setup.py
easy_install pip

回答 6

系统中的单个Python

要在Python中安装软件包,请始终遵循以下步骤:

  1. 如果包装是用于python 2.xsudo python -m pip install [package]
  2. 如果包装是用于python 3.xsudo python3 -m pip install [package]

注意:这是假设未为设置别名 python

通过这种方法,将不会混淆哪个Python版本正在接收该软件包。

多个Python

假设你有python3 ↔ python3.6python3.7 ↔ python3.7

  1. 要安装python3.6sudo python3 -m pip install [package]
  2. 要安装python3.7sudo python3.7 -m pip install [package]

这基本上与前面显示的方法相同。

注1

如何找到您的python3命令产生的python :

ganesh@Ganesh:~$ python3 # Type in terminal
Python 3.6.6 (default, Sep 12 2018, 18:26:19) # Your python3 version
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

注意第二行中的python 3.6.6

笔记2

更改python3python指向以下内容:https : //askubuntu.com/questions/320996/how-to-make-python-program-command-execute-python-3

Single Python in system

To install packages in Python always follow these steps:

  1. If the package is for python 2.x: sudo python -m pip install [package]
  2. If the package is for python 3.x: sudo python3 -m pip install [package]

Note: This is assuming no alias is set for python

Through this method, there will be no confusion regarding which python version is receiving the package.

Multiple Pythons

Say you have python3 ↔ python3.6 and python3.7 ↔ python3.7

  1. To install for python3.6: sudo python3 -m pip install [package]
  2. To instal for python3.7: sudo python3.7 -m pip install [package]

This is essentially the same method as shown previously.

Note 1

How to find which python, your python3 command spawns:

ganesh@Ganesh:~$ python3 # Type in terminal
Python 3.6.6 (default, Sep 12 2018, 18:26:19) # Your python3 version
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Notice python 3.6.6 in the second line.

Note 2

Change what python3 or python points to: https://askubuntu.com/questions/320996/how-to-make-python-program-command-execute-python-3


回答 7

python3 -m ensurepip

我不确定何时确切引入此功能,但尚不存在时会为我安装pip3。

python3 -m ensurepip

I’m not sure when exactly this was introduced, but it’s installed pip3 for me when it didn’t already exist.


回答 8

旧版的Homebrew

如果您使用的是macOS,请使用homebrew

brew install python3 # this installs python only
brew postinstall python3 # this command installs pip

另请注意,如果安装成功完成,则应检查控制台。有时没有(例如由于所有权引起的错误),但是人们只是忽略了日志。


更新-1.5之后的自制软件版本

根据官方的Homebrew页面

在2018年3月1日,python公式将升级到Python 3.x,并且将添加python @ 2公式以安装Python 2.7(尽管这仅是小桶,因此默认情况下,不将python和python2添加到PATH中,而无需手动冲泡链接–force)。我们将维护python2,python3和python @ 3别名。

因此,要安装Python 3,请运行以下命令:

brew install python3

然后,pip会自动安装,您可以通过来安装任何软件包pip install <package>

Older version of Homebrew

If you are on macOS, use homebrew.

brew install python3 # this installs python only
brew postinstall python3 # this command installs pip

Also note that you should check the console if the install finished successfully. Sometimes it doesn’t (e.g. an error due to ownership), but people simply overlook the log.


UPDATED – Homebrew version after 1.5

According to the official Homebrew page:

On 1st March 2018 the python formula will be upgraded to Python 3.x and a python@2 formula will be added for installing Python 2.7 (although this will be keg-only so neither python nor python2 will be added to the PATH by default without a manual brew link –force). We will maintain python2, python3 and python@3 aliases.

So to install Python 3, run the following command:

brew install python3

Then, the pip is installed automatically, and you can install any package by pip install <package>.


回答 9

如果您使用多个不同版本的python,请尝试使用virtualenv http://www.virtualenv.org/en/latest/virtualenv.html#installation

具有pip针对每个本地环境的优势。

然后通过以下方式在当前目录中安装本地环境:

virtualenv -p /usr/local/bin/python3.3 ENV --verbose

请注意,您指定了系统上已安装的python二进制文件的路径。

然后在该文件夹中有一个本地pythonenvironment。 ./ENV

现在应该有 ./ENV/pip-3.3

用于 ./ENV/pip-3.3 freeze列出本地安装的库。

用于./ENV/pip-3.3 install packagename在本地环境中安装。

用于./ENV/python3.3 pythonfile.py运行您的python脚本。

If you use several different versions of python try using virtualenv http://www.virtualenv.org/en/latest/virtualenv.html#installation

With the advantage of pip for each local environment.

Then install a local environment in the current directory by:

virtualenv -p /usr/local/bin/python3.3 ENV --verbose

Note that you specify the path to a python binary you have installed on your system.

Then there are now an local pythonenvironment in that folder. ./ENV

Now there should be ./ENV/pip-3.3

use ./ENV/pip-3.3 freeze to list the local installed libraries.

use ./ENV/pip-3.3 install packagename to install at the local environment.

use ./ENV/python3.3 pythonfile.py to run your python script.


回答 10

这是我在ubuntu 12.04上解决此问题的方法:

sudo apt-get install build-essential libncursesw5-dev libssl-dev libgdbm-dev libc6-dev libsqlite3-dev tk-dev

然后从源代码安装python3:

wget https://www.python.org/ftp/python/3.4.0/Python-3.4.0.tar.xz
tar xvf Python-3.4.0.tar.xz
cd Python-3.4.0
./configure
make
make test
sudo make install

当您全部安装完后,pip3将自动安装。

Here is my way to solve this problem at ubuntu 12.04:

sudo apt-get install build-essential libncursesw5-dev libssl-dev libgdbm-dev libc6-dev libsqlite3-dev tk-dev

Then install the python3 from source code:

wget https://www.python.org/ftp/python/3.4.0/Python-3.4.0.tar.xz
tar xvf Python-3.4.0.tar.xz
cd Python-3.4.0
./configure
make
make test
sudo make install

When you finished installing all of them, pip3 will get installed automatically.


回答 11

这就是我在OS X Mavericks上所做的工作,以使其正常工作。

首先,冲泡安装了

安装python 3.4

brew install python3

然后,我得到了最新版本的distribution:

wget https://pypi.python.org/packages/source/d/distribute/distribute-0.7.3.zip#md5=c6c59594a7b180af57af8a0cc0cf5b4a

unzip distribute-0.7.3.zip
cd distribute-0.7.3
sudo setup.py install
sudo easy_install-3.4 pip
sudo pip3.4 install virtualenv
sudo pip3.4 install virtualenvwrapper

mkvirtualenv py3 

python --version
Python 3.4.1

我希望这有帮助。

This is what I did on OS X Mavericks to get this to work.

Firstly, have brew installed

Install python 3.4

brew install python3

Then I get the latest version of distribute:

wget https://pypi.python.org/packages/source/d/distribute/distribute-0.7.3.zip#md5=c6c59594a7b180af57af8a0cc0cf5b4a

unzip distribute-0.7.3.zip
cd distribute-0.7.3
sudo setup.py install
sudo easy_install-3.4 pip
sudo pip3.4 install virtualenv
sudo pip3.4 install virtualenvwrapper

mkvirtualenv py3 

python --version
Python 3.4.1

I hope this helps.


回答 12

Python 3.4新增功能

点子应该总是可用

默认情况下,命令pipX和pipX.Y将连同pip Python软件包及其依赖项一起安装在所有平台上(其中XY代表Python安装的版本)。

https://docs.python.org/3/whatsnew/3.4.html#whatsnew-pep-453

因此,如果您安装了python 3.4,则可以: sudo pip3 install xxx

What’s New In Python 3.4

pip should always be available

By default, the commands pipX and pipX.Y will be installed on all platforms (where X.Y stands for the version of the Python installation), along with the pip Python package and its dependencies.

https://docs.python.org/3/whatsnew/3.4.html#whatsnew-pep-453

so if you have python 3.4 installed, you can just: sudo pip3 install xxx


回答 13

对于python3,请尝试以下操作:

wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python

好消息是它还将检测您拥有的python版本(即使它是您自定义位置中的python环境)。之后,您可以正常进行操作(例如)

pip install numpy

资源: https //pypi.python.org/pypi/setuptools/1.1.6#upgrading-from-setuptools-0-6

For python3 try this:

wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python

The good thing is that It will also detect what version of python you have (even if it’s an environment of python in your custom location). After this you can proceed normally with (for example)

pip install numpy

source: https://pypi.python.org/pypi/setuptools/1.1.6#upgrading-from-setuptools-0-6


回答 14

假设您处于高度受限的计算机环境中(例如我本人),而没有root访问权限或无法安装软件包…

在发布本文之前,我从未设置过Python / virtualenv的新/独立/原始/非根实例。我已经做了很多谷歌搜索工作。

  1. 确定您使用的是python(python2)还是python3,并正确设置PATH。(我严格是python3用户。)如果您是python2用户python3python则下面的所有命令都可以代替。
  2. wget https://pypi.python.org/packages/source/v/virtualenv/virtualenv-x.y.z.tar.gz
  3. tar -xzvf virtualenv-x.y.z.tar.gz
  4. python3 virtualenv-x.y.z/virtualenv.py --python $(which python3) /path/to/new/virtualenv
  5. source /path/to/new/virtualenv/bin/activate
    • 假设您使用的是兼容Bourne的外壳,例如bash
    • 出色的是,此virtualenv软件包包括的独立版本,pip并且setuptools会自动神奇地安装到每个新的virtualenv中。这解决了鸡肉和鸡蛋的问题。
    • 您可能想为此最终命令创建一个别名(或更新〜/ .bashrc等),以在每次登录时激活python virtualenv。记住所有这些路径和命令可能很痛苦。
  6. 现在检查您的python版本:which python3应该给出:/path/to/new/virtualenv/bin/python3
  7. pip也可以通过以下命令在virtualenv中进行检查which pip:应该给出:/path/to/new/virtualenv/bin/pip

然后…点,点,点!

给新手Pythoneers的最后提示:开始时您不需要虚拟环境,但是以后会很高兴的。帮助开源/共享软件包的“假设情况”安装/升级方案。

参考:https : //virtualenv.pypa.io/en/latest/installation.html

Assuming you are in a highly restricted computer env (such as myself) without root access or ability to install packages…

I had never setup a fresh/standalone/raw/non-root instance of Python+virtualenv before this post. I had do quite a bit of Googling to make this work.

  1. Decide if you are using python (python2) or python3 and set your PATH correctly. (I am strictly a python3 user.) All commands below can substitute python3 for python if you are python2 user.
  2. wget https://pypi.python.org/packages/source/v/virtualenv/virtualenv-x.y.z.tar.gz
  3. tar -xzvf virtualenv-x.y.z.tar.gz
  4. python3 virtualenv-x.y.z/virtualenv.py --python $(which python3) /path/to/new/virtualenv
  5. source /path/to/new/virtualenv/bin/activate
    • Assumes you are using a Bourne-compatible shell, e.g., bash
    • Brilliantly, this virtualenv package includes a standalone version of pip and setuptools that are auto-magically installed into each new virtualenv. This solves the chicken and egg problem.
    • You may want to create an alias (or update your ~/.bashrc, etc.) for this final command to activate the python virtualenv during each login. It can be a pain to remember all these paths and commands.
  6. Check your version of python now: which python3 should give: /path/to/new/virtualenv/bin/python3
  7. Check pip is also available in the virtualenv via which pip… should give: /path/to/new/virtualenv/bin/pip

Then… pip, pip, pip!

Final tip to newbie Pythoneers: You don’t think you need virtualenv when you start, but you will be happy to have it later. Helps with “what if” installation / upgrade scenarios for open source / shared packages.

Ref: https://virtualenv.pypa.io/en/latest/installation.html


回答 15

pip在您安装Python时一起安装。您可以使用 sudo pip install (module)python3 -m pip install (module)

pip is installed together when you install Python. You can use sudo pip install (module) or python3 -m pip install (module).


回答 16

要安装pip,请安全下载get-pip.py

然后运行以下命令:

python get-pip.py

如果您使用的是由操作系统或其他程序包管理器管理的Python安装,请务必谨慎。get-pip.py与这些工具不协调,可能会使您的系统处于不一致状态。

参考:PIP安装

To install pip, securely download get-pip.py.

Then run the following:

python get-pip.py

Be cautious if you’re using a Python install that’s managed by your operating system or another package manager. get-pip.py does not coordinate with those tools, and may leave your system in an inconsistent state.

Refer: PIP Installation


回答 17

对于Windows 8.1 / 10 OS用户,只需打开 cmd(命令提示符)

写这个: C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python36-32\Scripts

然后

只需这样写:pip3 install{软件包名称}

提示:Python36-32对于新的python 3.x版本,文件夹的位置可能会有所不同

And for Windows 8.1/10 OS Users just open cmd (command prompt)

write this : C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python36-32\Scripts

then

just write this : pip3 install {name of package}

Hint: the location of folder Python36-32 may get different for new python 3.x versions


回答 18

如果您的Linux发行版中已经安装了Python,则应该可以使用系统的软件包管理器来安装PIP。这是可取的,因为系统安装的Python版本无法与Windows和Mac上使用的get-pip.py脚本很好地配合使用。

高级打包工具(Python 2.x)

sudo apt-get install python-pip

进阶套件工具(Python 3.x)

sudo apt-get install python3-pip

pacman软件包管理器(Python 2.x)

sudo pacman -S python2-pip

pacman软件包管理器(Python 3.x)

sudo pacman -S python-pip

Yum软件包管理器(Python 2.x)

sudo yum upgrade python-setuptools
sudo yum install python-pip python-wheel

Yum软件包管理器(Python 3.x)

sudo yum install python3 python3-wheel

Dandified Yum(Python 2.x)

sudo dnf upgrade python-setuptools
sudo dnf install python-pip python-wheel

Dandified Yum(Python 3.x)

sudo dnf install python3 python3-wheel

Zypper软件包管理器(Python 2.x)

sudo zypper install python-pip python-setuptools python-wheel

Zypper软件包管理器(Python 3.x)

sudo zypper install python3-pip python3-setuptools python3-wheel

If your Linux distro came with Python already installed, you should be able to install PIP using your system’s package manager. This is preferable since system-installed versions of Python do not play nicely with the get-pip.py script used on Windows and Mac.

Advanced Package Tool (Python 2.x)

sudo apt-get install python-pip

Advanced Package Tool (Python 3.x)

sudo apt-get install python3-pip

pacman Package Manager (Python 2.x)

sudo pacman -S python2-pip

pacman Package Manager (Python 3.x)

sudo pacman -S python-pip

Yum Package Manager (Python 2.x)

sudo yum upgrade python-setuptools
sudo yum install python-pip python-wheel

Yum Package Manager (Python 3.x)

sudo yum install python3 python3-wheel

Dandified Yum (Python 2.x)

sudo dnf upgrade python-setuptools
sudo dnf install python-pip python-wheel

Dandified Yum (Python 3.x)

sudo dnf install python3 python3-wheel

Zypper Package Manager (Python 2.x)

sudo zypper install python-pip python-setuptools python-wheel

Zypper Package Manager (Python 3.x)

sudo zypper install python3-pip python3-setuptools python3-wheel

回答 19

请按照以下步骤使用pip安装python 3:

步骤1:从此处下载安装Python

步骤2:您需要下载 get-pip.py

步骤3:下载get-pip.py之后,打开命令提示符,然后转到保存get-pip.py文件的目录。

步骤4:输入命令 python get-pip.py在cmd中。

步骤5:Pip安装成功,通过cmd中的type命令验证pip安装 pip --version

Please follow below steps to install python 3 with pip:

Step 1 : Install Python from download here

Step 2 : you’ll need to download get-pip.py

Step 3 : After download get-pip.py , open your commant prompt and go to directory where your get-pip.py file saved .

Step 4 : Enter command python get-pip.py in cmd.

Step 5 : Pip installed successfully , Verify pip installation by type command in cmd pip --version


回答 20

这是我复制粘贴的单线。

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

使用get-pip.py安装

要安装pip,请get-pip.py通过以下链接安全下载: get-pip.py。或者,使用curl:

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

然后在下载了get-pip.py的文件夹中运行以下命令:

python get-pip.py

警告:如果您使用的是由操作系统或其他程序包管理器管理的Python安装,请务必谨慎。get-pip.py与这些工具不协调,可能会使您的系统处于不一致状态。

This is the one-liner I copy-and-paste.

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

From Installing with get-pip.py:

To install pip, securely download get-pip.py by following this link: get-pip.py. Alternatively, use curl:

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

Then run the following command in the folder where you have downloaded get-pip.py:

python get-pip.py

Warning: Be cautious if you are using a Python install that is managed by your operating system or another package manager. get-pip.py does not coordinate with those tools, and may leave your system in an inconsistent state.


__init__和__call__有什么区别?

问题:__init__和__call__有什么区别?

我想知道其中的差别之间__init____call__方法。

例如:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

I want to know the difference between __init__ and __call__ methods.

For example:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

回答 0

第一个用于初始化新创建的对象,并接收用于执行此操作的参数:

class Foo:
    def __init__(self, a, b, c):
        # ...

x = Foo(1, 2, 3) # __init__

第二个实现函数调用运算符。

class Foo:
    def __call__(self, a, b, c):
        # ...

x = Foo()
x(1, 2, 3) # __call__

The first is used to initialise newly created object, and receives arguments used to do that:

class Foo:
    def __init__(self, a, b, c):
        # ...

x = Foo(1, 2, 3) # __init__

The second implements function call operator.

class Foo:
    def __call__(self, a, b, c):
        # ...

x = Foo()
x(1, 2, 3) # __call__

回答 1

__call__()在元类中定义自定义方法允许将类的实例作为函数调用,而不必总是修改实例本身。

In [1]: class A:
   ...:     def __init__(self):
   ...:         print "init"
   ...:         
   ...:     def __call__(self):
   ...:         print "call"
   ...:         
   ...:         

In [2]: a = A()
init

In [3]: a()
call

Defining a custom __call__() method in the meta-class allows the class’s instance to be called as a function, not always modifying the instance itself.

In [1]: class A:
   ...:     def __init__(self):
   ...:         print "init"
   ...:         
   ...:     def __call__(self):
   ...:         print "call"
   ...:         
   ...:         

In [2]: a = A()
init

In [3]: a()
call

回答 2

在Python中,函数是一流的对象,这意味着:函数引用可以在输入中传递给其他函数和/或方法,并可以在它们内部执行。

可以将类的实例(也称为对象)当作函数来对待:将它们传递给其他方法/函数并调用它们。为了实现这一点,必须对__call__类函数进行专门化处理。

def __call__(self, [args ...]) 它以可变数量的参数作为输入。假定x是Class的实例Xx.__call__(1, 2)类似于调用实例x(1,2)将实例本身作为函数

在Python中,__init__()正确定义为Class Constructor(以及__del__()Class Destructor)。因此,__init__()和之间有一个净的区别__call__():第一个建立一个Class的实例,第二个使该实例作为一个函数可调用而不会影响对象本身的生命周期(即__call__,不影响构造/销毁生命周期),但是它可以修改其内部状态(如下所示)。

例。

class Stuff(object):

    def __init__(self, x, y, range):
        super(Stuff, self).__init__()
        self.x = x
        self.y = y
        self.range = range

    def __call__(self, x, y):
        self.x = x
        self.y = y
        print '__call__ with (%d,%d)' % (self.x, self.y)

    def __del__(self):
        del self.x
        del self.y
        del self.range

>>> s = Stuff(1, 2, 3)
>>> s.x
1
>>> s(7, 8)
__call__ with (7,8)
>>> s.x
7

In Python, functions are first-class objects, this means: function references can be passed in inputs to other functions and/or methods, and executed from inside them.

Instances of Classes (aka Objects), can be treated as if they were functions: pass them to other methods/functions and call them. In order to achieve this, the __call__ class function has to be specialized.

def __call__(self, [args ...]) It takes as an input a variable number of arguments. Assuming x being an instance of the Class X, x.__call__(1, 2) is analogous to calling x(1,2) or the instance itself as a function.

In Python, __init__() is properly defined as Class Constructor (as well as __del__() is the Class Destructor). Therefore, there is a net distinction between __init__() and __call__(): the first builds an instance of Class up, the second makes such instance callable as a function would be without impacting the lifecycle of the object itself (i.e. __call__ does not impact the construction/destruction lifecycle) but it can modify its internal state (as shown below).

Example.

class Stuff(object):

    def __init__(self, x, y, range):
        super(Stuff, self).__init__()
        self.x = x
        self.y = y
        self.range = range

    def __call__(self, x, y):
        self.x = x
        self.y = y
        print '__call__ with (%d,%d)' % (self.x, self.y)

    def __del__(self):
        del self.x
        del self.y
        del self.range

>>> s = Stuff(1, 2, 3)
>>> s.x
1
>>> s(7, 8)
__call__ with (7,8)
>>> s.x
7

回答 3

__call__使类的实例可调用。为什么会要求它?

从技术上讲__init____new__创建对象时会调用一次,以便可以对其进行初始化。

但是在许多情况下,您可能想重新定义对象,例如您已经完成了对象的工作,并可能需要一个新的对象。使用,__call__您可以像重新定义一样重新定义相同的对象。

这只是一种情况,可能还有更多。

__call__ makes the instance of a class callable. Why would it be required?

Technically __init__ is called once by __new__ when object is created, so that it can be initialized.

But there are many scenarios where you might want to redefine your object, say you are done with your object, and may find a need for a new object. With __call__ you can redefine the same object as if it were new.

This is just one case, there can be many more.


回答 4

>>> class A:
...     def __init__(self):
...         print "From init ... "
... 
>>> a = A()
From init ... 
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
>>> 
>>> class B:
...     def __init__(self):
...         print "From init ... "
...     def __call__(self):
...         print "From call ... "
... 
>>> b = B()
From init ... 
>>> b()
From call ... 
>>> 
>>> class A:
...     def __init__(self):
...         print "From init ... "
... 
>>> a = A()
From init ... 
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
>>> 
>>> class B:
...     def __init__(self):
...         print "From init ... "
...     def __call__(self):
...         print "From call ... "
... 
>>> b = B()
From init ... 
>>> b()
From call ... 
>>> 

回答 5

__init__将被视为构造函数,其中as __call__方法可以多次用对象调用。这两个__init____call__功能做采取默认参数。

__init__ would be treated as Constructor where as __call__ methods can be called with objects any number of times. Both __init__ and __call__ functions do take default arguments.


回答 6

我将尝试通过一个示例来说明这一点,假设您要打印斐波那契数列中的固定数量的术语。请记住,斐波那契数列的前2个项是1。例如:1、1、2、3、5、8、13 …

您希望包含斐波那契数字的列表仅被初始化一次,然后更新。现在我们可以使用该__call__功能。阅读@mudit verma的答案。就像您希望该对象可作为一个函数来调用,而不是在每次调用时都重新初始化。

例如:

class Recorder:
    def __init__(self):
        self._weights = []
        for i in range(0, 2):
            self._weights.append(1)
        print self._weights[-1]
        print self._weights[-2]
        print "no. above is from __init__"

    def __call__(self, t):
        self._weights = [self._weights[-1], self._weights[-1] + self._weights[-2]]
        print self._weights[-1]
        print "no. above is from __call__"

weight_recorder = Recorder()
for i in range(0, 10):
    weight_recorder(i)

输出为:

1
1
no. above is from __init__
2
no. above is from __call__
3
no. above is from __call__
5
no. above is from __call__
8
no. above is from __call__
13
no. above is from __call__
21
no. above is from __call__
34
no. above is from __call__
55
no. above is from __call__
89
no. above is from __call__
144
no. above is from __call__

如果观察到__init__在第一次实例化该类时仅一次调用了输出,则稍后调用该对象而无需重新初始化。

I will try to explain this using an example, suppose you wanted to print a fixed number of terms from fibonacci series. Remember that the first 2 terms of fibonacci series are 1s. Eg: 1, 1, 2, 3, 5, 8, 13….

You want the list containing the fibonacci numbers to be initialized only once and after that it should update. Now we can use the __call__ functionality. Read @mudit verma’s answer. It’s like you want the object to be callable as a function but not re-initialized every time you call it.

Eg:

class Recorder:
    def __init__(self):
        self._weights = []
        for i in range(0, 2):
            self._weights.append(1)
        print self._weights[-1]
        print self._weights[-2]
        print "no. above is from __init__"

    def __call__(self, t):
        self._weights = [self._weights[-1], self._weights[-1] + self._weights[-2]]
        print self._weights[-1]
        print "no. above is from __call__"

weight_recorder = Recorder()
for i in range(0, 10):
    weight_recorder(i)

The output is:

1
1
no. above is from __init__
2
no. above is from __call__
3
no. above is from __call__
5
no. above is from __call__
8
no. above is from __call__
13
no. above is from __call__
21
no. above is from __call__
34
no. above is from __call__
55
no. above is from __call__
89
no. above is from __call__
144
no. above is from __call__

If you observe the output __init__ was called only one time that’s when the class was instantiated for the first time, later on the object was being called without re-initializing.


回答 7

您也可以使用__call__方法来实现装饰器

本示例摘自Python 3 Patterns,Recipes和Idioms

class decorator_without_arguments(object):
    def __init__(self, f):
        """
        If there are no decorator arguments, the function
        to be decorated is passed to the constructor.
        """
        print("Inside __init__()")
        self.f = f

    def __call__(self, *args):
        """
        The __call__ method is not called until the
        decorated function is called.
        """
        print("Inside __call__()")
        self.f(*args)
        print("After self.f( * args)")


@decorator_without_arguments
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)


print("After decoration")
print("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print("After first sayHello() call")
sayHello("a", "different", "set of", "arguments")
print("After second sayHello() call")

输出

在此处输入图片说明

You can also use __call__ method in favor of implementing decorators.

This example taken from Python 3 Patterns, Recipes and Idioms

class decorator_without_arguments(object):
    def __init__(self, f):
        """
        If there are no decorator arguments, the function
        to be decorated is passed to the constructor.
        """
        print("Inside __init__()")
        self.f = f

    def __call__(self, *args):
        """
        The __call__ method is not called until the
        decorated function is called.
        """
        print("Inside __call__()")
        self.f(*args)
        print("After self.f( * args)")


@decorator_without_arguments
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)


print("After decoration")
print("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print("After first sayHello() call")
sayHello("a", "different", "set of", "arguments")
print("After second sayHello() call")

Output:

enter image description here


回答 8

因此,__init__在创建任何类的实例并初始化实例变量时也会调用。

例:

class User:

    def __init__(self,first_n,last_n,age):
        self.first_n = first_n
        self.last_n = last_n
        self.age = age

user1 = User("Jhone","Wrick","40")

__call__当你调用像任何其他函数的对象被调用。

例:

class USER:
    def __call__(self,arg):
        "todo here"
         print(f"I am in __call__ with arg : {arg} ")


user1=USER()
user1("One") #calling the object user1 and that's gonna call __call__ dunder functions

So, __init__ is called when you are creating an instance of any class and initializing the instance variable also.

Example:

class User:

    def __init__(self,first_n,last_n,age):
        self.first_n = first_n
        self.last_n = last_n
        self.age = age

user1 = User("Jhone","Wrick","40")

And __call__ is called when you call the object like any other function.

Example:

class USER:
    def __call__(self,arg):
        "todo here"
         print(f"I am in __call__ with arg : {arg} ")


user1=USER()
user1("One") #calling the object user1 and that's gonna call __call__ dunder functions

回答 9

__init__是Python类中的一种特殊方法,它是类的构造方法。每当构造该类的对象时,就可以调用它,或者可以说它初始化了一个新对象。例:

    In [4]: class A:
   ...:     def __init__(self, a):
   ...:         print(a)
   ...:
   ...: a = A(10) # An argument is necessary
10

如果我们使用A(),它将给出一个错误 TypeError: __init__() missing 1 required positional argument: 'a'a由于,它将需要1个参数__init__

……..

__call__ 在Class中实现时,可帮助我们将Class实例作为函数调用来调用。

例:

In [6]: class B:
   ...:     def __call__(self,b):
   ...:         print(b)
   ...:
   ...: b = B() # Note we didn't pass any arguments here
   ...: b(20)   # Argument passed when the object is called
   ...:
20

在这里,如果我们使用B(),它就可以正常运行,因为这里没有__init__函数。

__init__ is a special method in Python classes, it is the constructor method for a class. It is called whenever an object of the class is constructed or we can say it initialises a new object. Example:

    In [4]: class A:
   ...:     def __init__(self, a):
   ...:         print(a)
   ...:
   ...: a = A(10) # An argument is necessary
10

If we use A(), it will give an error TypeError: __init__() missing 1 required positional argument: 'a' as it requires 1 argument a because of __init__ .

……..

__call__ when implemented in the Class helps us invoke the Class instance as a function call.

Example:

In [6]: class B:
   ...:     def __call__(self,b):
   ...:         print(b)
   ...:
   ...: b = B() # Note we didn't pass any arguments here
   ...: b(20)   # Argument passed when the object is called
   ...:
20

Here if we use B(), it runs just fine because it doesn’t have an __init__ function here.


回答 10

__call__允许返回任意值,而__init__作为构造函数则隐式返回类的实例。正如其他答案正确指出的那样,__init__它仅被调用一次,而__call__如果已初始化的实例被分配给中间变量,则可以多次调用。

>>> class Test:
...     def __init__(self):
...         return 'Hello'
... 
>>> Test()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>> class Test2:
...     def __call__(self):
...         return 'Hello'
... 
>>> Test2()()
'Hello'
>>> 
>>> Test2()()
'Hello'
>>> 

__call__ allows to return arbitrary values, while __init__ being an constructor returns the instance of class implicitly. As other answers properly pointed out, __init__ is called just once, while it’s possible to call __call__ multiple times, in case the initialized instance is assigned to intermediate variable.

>>> class Test:
...     def __init__(self):
...         return 'Hello'
... 
>>> Test()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>> class Test2:
...     def __call__(self):
...         return 'Hello'
... 
>>> Test2()()
'Hello'
>>> 
>>> Test2()()
'Hello'
>>> 

回答 11

上面已经提供了简短的答案。与Java相比,我想提供一些实际的实现。

 class test(object):
        def __init__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c
        def __call__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c


    instance1 = test(1, 2, 3)
    print(instance1.a) #prints 1

    #scenario 1
    #creating new instance instance1
    #instance1 = test(13, 3, 4)
    #print(instance1.a) #prints 13


    #scenario 2
    #modifying the already created instance **instance1**
    instance1(13,3,4)
    print(instance1.a)#prints 13

注意:场景1和场景2在结果输出方面似乎相同。但是在方案1中,我们再次创建另一个新实例instance1。在方案2中,我们只需修改已创建的instance1即可__call__这是有益的,因为系统不需要创建新实例。

在Java中等效

public class Test {

    public static void main(String[] args) {
        Test.TestInnerClass testInnerClass = new Test(). new TestInnerClass(1, 2, 3);
        System.out.println(testInnerClass.a);

        //creating new instance **testInnerClass**
        testInnerClass = new Test().new TestInnerClass(13, 3, 4);
        System.out.println(testInnerClass.a);

        //modifying already created instance **testInnerClass**
        testInnerClass.a = 5;
        testInnerClass.b = 14;
        testInnerClass.c = 23;

        //in python, above three lines is done by testInnerClass(5, 14, 23). For this, we must define __call__ method

    }

    class TestInnerClass /* non-static inner class */{

        private int a, b,c;

        TestInnerClass(int a, int b, int c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }
}

Short and sweet answers are already provided above. I wanna provide some practical implementation as compared with Java.

 class test(object):
        def __init__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c
        def __call__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c


    instance1 = test(1, 2, 3)
    print(instance1.a) #prints 1

    #scenario 1
    #creating new instance instance1
    #instance1 = test(13, 3, 4)
    #print(instance1.a) #prints 13


    #scenario 2
    #modifying the already created instance **instance1**
    instance1(13,3,4)
    print(instance1.a)#prints 13

Note: scenario 1 and scenario 2 seems same in terms of result output. But in scenario1, we again create another new instance instance1. In scenario2, we simply modify already created instance1. __call__ is beneficial here as the system doesn’t need to create new instance.

Equivalent in Java

public class Test {

    public static void main(String[] args) {
        Test.TestInnerClass testInnerClass = new Test(). new TestInnerClass(1, 2, 3);
        System.out.println(testInnerClass.a);

        //creating new instance **testInnerClass**
        testInnerClass = new Test().new TestInnerClass(13, 3, 4);
        System.out.println(testInnerClass.a);

        //modifying already created instance **testInnerClass**
        testInnerClass.a = 5;
        testInnerClass.b = 14;
        testInnerClass.c = 23;

        //in python, above three lines is done by testInnerClass(5, 14, 23). For this, we must define __call__ method

    }

    class TestInnerClass /* non-static inner class */{

        private int a, b,c;

        TestInnerClass(int a, int b, int c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }
}

回答 12

我们可以使用call方法将其他类方法用作静态方法。

class _Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

class Model:

    def get_instance(conn, table_name):

        """ do something"""

    get_instance = _Callable(get_instance)

provs_fac = Model.get_instance(connection, "users")  

We can use call method to use other class methods as static methods.

class _Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

class Model:

    def get_instance(conn, table_name):

        """ do something"""

    get_instance = _Callable(get_instance)

provs_fac = Model.get_instance(connection, "users")  

Tensorflow:如何保存/恢复模型?

问题:Tensorflow:如何保存/恢复模型?

在Tensorflow中训练模型后:

  1. 您如何保存经过训练的模型?
  2. 您以后如何还原此保存的模型?

After you train a model in Tensorflow:

  1. How do you save the trained model?
  2. How do you later restore this saved model?

回答 0

文件

从文档:

# Create some variables.
v1 = tf.get_variable("v1", shape=[3], initializer = tf.zeros_initializer)
v2 = tf.get_variable("v2", shape=[5], initializer = tf.zeros_initializer)

inc_v1 = v1.assign(v1+1)
dec_v2 = v2.assign(v2-1)

# Add an op to initialize the variables.
init_op = tf.global_variables_initializer()

# Add ops to save and restore all the variables.
saver = tf.train.Saver()

# Later, launch the model, initialize the variables, do some work, and save the
# variables to disk.
with tf.Session() as sess:
  sess.run(init_op)
  # Do some work with the model.
  inc_v1.op.run()
  dec_v2.op.run()
  # Save the variables to disk.
  save_path = saver.save(sess, "/tmp/model.ckpt")
  print("Model saved in path: %s" % save_path)

恢复

tf.reset_default_graph()

# Create some variables.
v1 = tf.get_variable("v1", shape=[3])
v2 = tf.get_variable("v2", shape=[5])

# Add ops to save and restore all the variables.
saver = tf.train.Saver()

# Later, launch the model, use the saver to restore variables from disk, and
# do some work with the model.
with tf.Session() as sess:
  # Restore variables from disk.
  saver.restore(sess, "/tmp/model.ckpt")
  print("Model restored.")
  # Check the values of the variables
  print("v1 : %s" % v1.eval())
  print("v2 : %s" % v2.eval())

Tensorflow 2

这仍然是beta版,因此我建议不要使用。如果您仍然想走那条路,这里就是tf.saved_model使用指南

Tensorflow <2

simple_save

许多好答案,为完整性起见,我将加2美分:simple_save。也是使用tf.data.DatasetAPI 的独立代码示例。

Python 3; Tensorflow 1.14

import tensorflow as tf
from tensorflow.saved_model import tag_constants

with tf.Graph().as_default():
    with tf.Session() as sess:
        ...

        # Saving
        inputs = {
            "batch_size_placeholder": batch_size_placeholder,
            "features_placeholder": features_placeholder,
            "labels_placeholder": labels_placeholder,
        }
        outputs = {"prediction": model_output}
        tf.saved_model.simple_save(
            sess, 'path/to/your/location/', inputs, outputs
        )

恢复:

graph = tf.Graph()
with restored_graph.as_default():
    with tf.Session() as sess:
        tf.saved_model.loader.load(
            sess,
            [tag_constants.SERVING],
            'path/to/your/location/',
        )
        batch_size_placeholder = graph.get_tensor_by_name('batch_size_placeholder:0')
        features_placeholder = graph.get_tensor_by_name('features_placeholder:0')
        labels_placeholder = graph.get_tensor_by_name('labels_placeholder:0')
        prediction = restored_graph.get_tensor_by_name('dense/BiasAdd:0')

        sess.run(prediction, feed_dict={
            batch_size_placeholder: some_value,
            features_placeholder: some_other_value,
            labels_placeholder: another_value
        })

独立示例

原始博客文章

为了演示,以下代码生成随机数据。

  1. 我们首先创建占位符。它们将在运行时保存数据。根据它们,我们创建Dataset然后Iterator。我们得到迭代器的生成张量,称为input_tensor,它将用作模型的输入。
  2. 模型本身是从 input_tensor基于:基于GRU的双向RNN,然后是密集分类器。因为为什么不。
  3. 损耗为softmax_cross_entropy_with_logits,优化为Adam。在2个时期(每个2批次)之后,我们使用保存了“训练”模型tf.saved_model.simple_save。如果按原样运行代码,则模型将保存在名为simple/当前工作目录下中。
  4. 在新的图形中,然后使用还原保存的模型tf.saved_model.loader.load。我们使用来抢占占位符并登录,graph.get_tensor_by_name并使用进行Iterator初始化操作graph.get_operation_by_name
  5. 最后,我们对数据集中的两个批次进行推断,并检查保存和恢复的模型是否产生相同的值。他们是这样!

码:

import os
import shutil
import numpy as np
import tensorflow as tf
from tensorflow.python.saved_model import tag_constants


def model(graph, input_tensor):
    """Create the model which consists of
    a bidirectional rnn (GRU(10)) followed by a dense classifier

    Args:
        graph (tf.Graph): Tensors' graph
        input_tensor (tf.Tensor): Tensor fed as input to the model

    Returns:
        tf.Tensor: the model's output layer Tensor
    """
    cell = tf.nn.rnn_cell.GRUCell(10)
    with graph.as_default():
        ((fw_outputs, bw_outputs), (fw_state, bw_state)) = tf.nn.bidirectional_dynamic_rnn(
            cell_fw=cell,
            cell_bw=cell,
            inputs=input_tensor,
            sequence_length=[10] * 32,
            dtype=tf.float32,
            swap_memory=True,
            scope=None)
        outputs = tf.concat((fw_outputs, bw_outputs), 2)
        mean = tf.reduce_mean(outputs, axis=1)
        dense = tf.layers.dense(mean, 5, activation=None)

        return dense


def get_opt_op(graph, logits, labels_tensor):
    """Create optimization operation from model's logits and labels

    Args:
        graph (tf.Graph): Tensors' graph
        logits (tf.Tensor): The model's output without activation
        labels_tensor (tf.Tensor): Target labels

    Returns:
        tf.Operation: the operation performing a stem of Adam optimizer
    """
    with graph.as_default():
        with tf.variable_scope('loss'):
            loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
                    logits=logits, labels=labels_tensor, name='xent'),
                    name="mean-xent"
                    )
        with tf.variable_scope('optimizer'):
            opt_op = tf.train.AdamOptimizer(1e-2).minimize(loss)
        return opt_op


if __name__ == '__main__':
    # Set random seed for reproducibility
    # and create synthetic data
    np.random.seed(0)
    features = np.random.randn(64, 10, 30)
    labels = np.eye(5)[np.random.randint(0, 5, (64,))]

    graph1 = tf.Graph()
    with graph1.as_default():
        # Random seed for reproducibility
        tf.set_random_seed(0)
        # Placeholders
        batch_size_ph = tf.placeholder(tf.int64, name='batch_size_ph')
        features_data_ph = tf.placeholder(tf.float32, [None, None, 30], 'features_data_ph')
        labels_data_ph = tf.placeholder(tf.int32, [None, 5], 'labels_data_ph')
        # Dataset
        dataset = tf.data.Dataset.from_tensor_slices((features_data_ph, labels_data_ph))
        dataset = dataset.batch(batch_size_ph)
        iterator = tf.data.Iterator.from_structure(dataset.output_types, dataset.output_shapes)
        dataset_init_op = iterator.make_initializer(dataset, name='dataset_init')
        input_tensor, labels_tensor = iterator.get_next()

        # Model
        logits = model(graph1, input_tensor)
        # Optimization
        opt_op = get_opt_op(graph1, logits, labels_tensor)

        with tf.Session(graph=graph1) as sess:
            # Initialize variables
            tf.global_variables_initializer().run(session=sess)
            for epoch in range(3):
                batch = 0
                # Initialize dataset (could feed epochs in Dataset.repeat(epochs))
                sess.run(
                    dataset_init_op,
                    feed_dict={
                        features_data_ph: features,
                        labels_data_ph: labels,
                        batch_size_ph: 32
                    })
                values = []
                while True:
                    try:
                        if epoch < 2:
                            # Training
                            _, value = sess.run([opt_op, logits])
                            print('Epoch {}, batch {} | Sample value: {}'.format(epoch, batch, value[0]))
                            batch += 1
                        else:
                            # Final inference
                            values.append(sess.run(logits))
                            print('Epoch {}, batch {} | Final inference | Sample value: {}'.format(epoch, batch, values[-1][0]))
                            batch += 1
                    except tf.errors.OutOfRangeError:
                        break
            # Save model state
            print('\nSaving...')
            cwd = os.getcwd()
            path = os.path.join(cwd, 'simple')
            shutil.rmtree(path, ignore_errors=True)
            inputs_dict = {
                "batch_size_ph": batch_size_ph,
                "features_data_ph": features_data_ph,
                "labels_data_ph": labels_data_ph
            }
            outputs_dict = {
                "logits": logits
            }
            tf.saved_model.simple_save(
                sess, path, inputs_dict, outputs_dict
            )
            print('Ok')
    # Restoring
    graph2 = tf.Graph()
    with graph2.as_default():
        with tf.Session(graph=graph2) as sess:
            # Restore saved values
            print('\nRestoring...')
            tf.saved_model.loader.load(
                sess,
                [tag_constants.SERVING],
                path
            )
            print('Ok')
            # Get restored placeholders
            labels_data_ph = graph2.get_tensor_by_name('labels_data_ph:0')
            features_data_ph = graph2.get_tensor_by_name('features_data_ph:0')
            batch_size_ph = graph2.get_tensor_by_name('batch_size_ph:0')
            # Get restored model output
            restored_logits = graph2.get_tensor_by_name('dense/BiasAdd:0')
            # Get dataset initializing operation
            dataset_init_op = graph2.get_operation_by_name('dataset_init')

            # Initialize restored dataset
            sess.run(
                dataset_init_op,
                feed_dict={
                    features_data_ph: features,
                    labels_data_ph: labels,
                    batch_size_ph: 32
                }

            )
            # Compute inference for both batches in dataset
            restored_values = []
            for i in range(2):
                restored_values.append(sess.run(restored_logits))
                print('Restored values: ', restored_values[i][0])

    # Check if original inference and restored inference are equal
    valid = all((v == rv).all() for v, rv in zip(values, restored_values))
    print('\nInferences match: ', valid)

这将打印:

$ python3 save_and_restore.py

Epoch 0, batch 0 | Sample value: [-0.13851789 -0.3087595   0.12804556  0.20013677 -0.08229901]
Epoch 0, batch 1 | Sample value: [-0.00555491 -0.04339041 -0.05111827 -0.2480045  -0.00107776]
Epoch 1, batch 0 | Sample value: [-0.19321944 -0.2104792  -0.00602257  0.07465433  0.11674127]
Epoch 1, batch 1 | Sample value: [-0.05275984  0.05981954 -0.15913513 -0.3244143   0.10673307]
Epoch 2, batch 0 | Final inference | Sample value: [-0.26331693 -0.13013336 -0.12553    -0.04276478  0.2933622 ]
Epoch 2, batch 1 | Final inference | Sample value: [-0.07730117  0.11119192 -0.20817074 -0.35660955  0.16990358]

Saving...
INFO:tensorflow:Assets added to graph.
INFO:tensorflow:No assets to write.
INFO:tensorflow:SavedModel written to: b'/some/path/simple/saved_model.pb'
Ok

Restoring...
INFO:tensorflow:Restoring parameters from b'/some/path/simple/variables/variables'
Ok
Restored values:  [-0.26331693 -0.13013336 -0.12553    -0.04276478  0.2933622 ]
Restored values:  [-0.07730117  0.11119192 -0.20817074 -0.35660955  0.16990358]

Inferences match:  True

Docs

From the docs:

Save

# Create some variables.
v1 = tf.get_variable("v1", shape=[3], initializer = tf.zeros_initializer)
v2 = tf.get_variable("v2", shape=[5], initializer = tf.zeros_initializer)

inc_v1 = v1.assign(v1+1)
dec_v2 = v2.assign(v2-1)

# Add an op to initialize the variables.
init_op = tf.global_variables_initializer()

# Add ops to save and restore all the variables.
saver = tf.train.Saver()

# Later, launch the model, initialize the variables, do some work, and save the
# variables to disk.
with tf.Session() as sess:
  sess.run(init_op)
  # Do some work with the model.
  inc_v1.op.run()
  dec_v2.op.run()
  # Save the variables to disk.
  save_path = saver.save(sess, "/tmp/model.ckpt")
  print("Model saved in path: %s" % save_path)

Restore

tf.reset_default_graph()

# Create some variables.
v1 = tf.get_variable("v1", shape=[3])
v2 = tf.get_variable("v2", shape=[5])

# Add ops to save and restore all the variables.
saver = tf.train.Saver()

# Later, launch the model, use the saver to restore variables from disk, and
# do some work with the model.
with tf.Session() as sess:
  # Restore variables from disk.
  saver.restore(sess, "/tmp/model.ckpt")
  print("Model restored.")
  # Check the values of the variables
  print("v1 : %s" % v1.eval())
  print("v2 : %s" % v2.eval())

Tensorflow 2

This is still beta so I’d advise against for now. If you still want to go down that road here is the tf.saved_model usage guide

Tensorflow < 2

simple_save

Many good answer, for completeness I’ll add my 2 cents: simple_save. Also a standalone code example using the tf.data.Dataset API.

Python 3 ; Tensorflow 1.14

import tensorflow as tf
from tensorflow.saved_model import tag_constants

with tf.Graph().as_default():
    with tf.Session() as sess:
        ...

        # Saving
        inputs = {
            "batch_size_placeholder": batch_size_placeholder,
            "features_placeholder": features_placeholder,
            "labels_placeholder": labels_placeholder,
        }
        outputs = {"prediction": model_output}
        tf.saved_model.simple_save(
            sess, 'path/to/your/location/', inputs, outputs
        )

Restoring:

graph = tf.Graph()
with restored_graph.as_default():
    with tf.Session() as sess:
        tf.saved_model.loader.load(
            sess,
            [tag_constants.SERVING],
            'path/to/your/location/',
        )
        batch_size_placeholder = graph.get_tensor_by_name('batch_size_placeholder:0')
        features_placeholder = graph.get_tensor_by_name('features_placeholder:0')
        labels_placeholder = graph.get_tensor_by_name('labels_placeholder:0')
        prediction = restored_graph.get_tensor_by_name('dense/BiasAdd:0')

        sess.run(prediction, feed_dict={
            batch_size_placeholder: some_value,
            features_placeholder: some_other_value,
            labels_placeholder: another_value
        })

Standalone example

Original blog post

The following code generates random data for the sake of the demonstration.

  1. We start by creating the placeholders. They will hold the data at runtime. From them, we create the Dataset and then its Iterator. We get the iterator’s generated tensor, called input_tensor which will serve as input to our model.
  2. The model itself is built from input_tensor: a GRU-based bidirectional RNN followed by a dense classifier. Because why not.
  3. The loss is a softmax_cross_entropy_with_logits, optimized with Adam. After 2 epochs (of 2 batches each), we save the “trained” model with tf.saved_model.simple_save. If you run the code as is, then the model will be saved in a folder called simple/ in your current working directory.
  4. In a new graph, we then restore the saved model with tf.saved_model.loader.load. We grab the placeholders and logits with graph.get_tensor_by_name and the Iterator initializing operation with graph.get_operation_by_name.
  5. Lastly we run an inference for both batches in the dataset, and check that the saved and restored model both yield the same values. They do!

Code:

import os
import shutil
import numpy as np
import tensorflow as tf
from tensorflow.python.saved_model import tag_constants


def model(graph, input_tensor):
    """Create the model which consists of
    a bidirectional rnn (GRU(10)) followed by a dense classifier

    Args:
        graph (tf.Graph): Tensors' graph
        input_tensor (tf.Tensor): Tensor fed as input to the model

    Returns:
        tf.Tensor: the model's output layer Tensor
    """
    cell = tf.nn.rnn_cell.GRUCell(10)
    with graph.as_default():
        ((fw_outputs, bw_outputs), (fw_state, bw_state)) = tf.nn.bidirectional_dynamic_rnn(
            cell_fw=cell,
            cell_bw=cell,
            inputs=input_tensor,
            sequence_length=[10] * 32,
            dtype=tf.float32,
            swap_memory=True,
            scope=None)
        outputs = tf.concat((fw_outputs, bw_outputs), 2)
        mean = tf.reduce_mean(outputs, axis=1)
        dense = tf.layers.dense(mean, 5, activation=None)

        return dense


def get_opt_op(graph, logits, labels_tensor):
    """Create optimization operation from model's logits and labels

    Args:
        graph (tf.Graph): Tensors' graph
        logits (tf.Tensor): The model's output without activation
        labels_tensor (tf.Tensor): Target labels

    Returns:
        tf.Operation: the operation performing a stem of Adam optimizer
    """
    with graph.as_default():
        with tf.variable_scope('loss'):
            loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
                    logits=logits, labels=labels_tensor, name='xent'),
                    name="mean-xent"
                    )
        with tf.variable_scope('optimizer'):
            opt_op = tf.train.AdamOptimizer(1e-2).minimize(loss)
        return opt_op


if __name__ == '__main__':
    # Set random seed for reproducibility
    # and create synthetic data
    np.random.seed(0)
    features = np.random.randn(64, 10, 30)
    labels = np.eye(5)[np.random.randint(0, 5, (64,))]

    graph1 = tf.Graph()
    with graph1.as_default():
        # Random seed for reproducibility
        tf.set_random_seed(0)
        # Placeholders
        batch_size_ph = tf.placeholder(tf.int64, name='batch_size_ph')
        features_data_ph = tf.placeholder(tf.float32, [None, None, 30], 'features_data_ph')
        labels_data_ph = tf.placeholder(tf.int32, [None, 5], 'labels_data_ph')
        # Dataset
        dataset = tf.data.Dataset.from_tensor_slices((features_data_ph, labels_data_ph))
        dataset = dataset.batch(batch_size_ph)
        iterator = tf.data.Iterator.from_structure(dataset.output_types, dataset.output_shapes)
        dataset_init_op = iterator.make_initializer(dataset, name='dataset_init')
        input_tensor, labels_tensor = iterator.get_next()

        # Model
        logits = model(graph1, input_tensor)
        # Optimization
        opt_op = get_opt_op(graph1, logits, labels_tensor)

        with tf.Session(graph=graph1) as sess:
            # Initialize variables
            tf.global_variables_initializer().run(session=sess)
            for epoch in range(3):
                batch = 0
                # Initialize dataset (could feed epochs in Dataset.repeat(epochs))
                sess.run(
                    dataset_init_op,
                    feed_dict={
                        features_data_ph: features,
                        labels_data_ph: labels,
                        batch_size_ph: 32
                    })
                values = []
                while True:
                    try:
                        if epoch < 2:
                            # Training
                            _, value = sess.run([opt_op, logits])
                            print('Epoch {}, batch {} | Sample value: {}'.format(epoch, batch, value[0]))
                            batch += 1
                        else:
                            # Final inference
                            values.append(sess.run(logits))
                            print('Epoch {}, batch {} | Final inference | Sample value: {}'.format(epoch, batch, values[-1][0]))
                            batch += 1
                    except tf.errors.OutOfRangeError:
                        break
            # Save model state
            print('\nSaving...')
            cwd = os.getcwd()
            path = os.path.join(cwd, 'simple')
            shutil.rmtree(path, ignore_errors=True)
            inputs_dict = {
                "batch_size_ph": batch_size_ph,
                "features_data_ph": features_data_ph,
                "labels_data_ph": labels_data_ph
            }
            outputs_dict = {
                "logits": logits
            }
            tf.saved_model.simple_save(
                sess, path, inputs_dict, outputs_dict
            )
            print('Ok')
    # Restoring
    graph2 = tf.Graph()
    with graph2.as_default():
        with tf.Session(graph=graph2) as sess:
            # Restore saved values
            print('\nRestoring...')
            tf.saved_model.loader.load(
                sess,
                [tag_constants.SERVING],
                path
            )
            print('Ok')
            # Get restored placeholders
            labels_data_ph = graph2.get_tensor_by_name('labels_data_ph:0')
            features_data_ph = graph2.get_tensor_by_name('features_data_ph:0')
            batch_size_ph = graph2.get_tensor_by_name('batch_size_ph:0')
            # Get restored model output
            restored_logits = graph2.get_tensor_by_name('dense/BiasAdd:0')
            # Get dataset initializing operation
            dataset_init_op = graph2.get_operation_by_name('dataset_init')

            # Initialize restored dataset
            sess.run(
                dataset_init_op,
                feed_dict={
                    features_data_ph: features,
                    labels_data_ph: labels,
                    batch_size_ph: 32
                }

            )
            # Compute inference for both batches in dataset
            restored_values = []
            for i in range(2):
                restored_values.append(sess.run(restored_logits))
                print('Restored values: ', restored_values[i][0])

    # Check if original inference and restored inference are equal
    valid = all((v == rv).all() for v, rv in zip(values, restored_values))
    print('\nInferences match: ', valid)

This will print:

$ python3 save_and_restore.py

Epoch 0, batch 0 | Sample value: [-0.13851789 -0.3087595   0.12804556  0.20013677 -0.08229901]
Epoch 0, batch 1 | Sample value: [-0.00555491 -0.04339041 -0.05111827 -0.2480045  -0.00107776]
Epoch 1, batch 0 | Sample value: [-0.19321944 -0.2104792  -0.00602257  0.07465433  0.11674127]
Epoch 1, batch 1 | Sample value: [-0.05275984  0.05981954 -0.15913513 -0.3244143   0.10673307]
Epoch 2, batch 0 | Final inference | Sample value: [-0.26331693 -0.13013336 -0.12553    -0.04276478  0.2933622 ]
Epoch 2, batch 1 | Final inference | Sample value: [-0.07730117  0.11119192 -0.20817074 -0.35660955  0.16990358]

Saving...
INFO:tensorflow:Assets added to graph.
INFO:tensorflow:No assets to write.
INFO:tensorflow:SavedModel written to: b'/some/path/simple/saved_model.pb'
Ok

Restoring...
INFO:tensorflow:Restoring parameters from b'/some/path/simple/variables/variables'
Ok
Restored values:  [-0.26331693 -0.13013336 -0.12553    -0.04276478  0.2933622 ]
Restored values:  [-0.07730117  0.11119192 -0.20817074 -0.35660955  0.16990358]

Inferences match:  True

回答 1

我正在改善我的答案,以添加更多有关保存和还原模型的详细信息。

Tensorflow版本0.11中(及之后):

保存模型:

import tensorflow as tf

#Prepare to feed input, i.e. feed_dict and placeholders
w1 = tf.placeholder("float", name="w1")
w2 = tf.placeholder("float", name="w2")
b1= tf.Variable(2.0,name="bias")
feed_dict ={w1:4,w2:8}

#Define a test operation that we will restore
w3 = tf.add(w1,w2)
w4 = tf.multiply(w3,b1,name="op_to_restore")
sess = tf.Session()
sess.run(tf.global_variables_initializer())

#Create a saver object which will save all the variables
saver = tf.train.Saver()

#Run the operation by feeding input
print sess.run(w4,feed_dict)
#Prints 24 which is sum of (w1+w2)*b1 

#Now, save the graph
saver.save(sess, 'my_test_model',global_step=1000)

还原模型:

import tensorflow as tf

sess=tf.Session()    
#First let's load meta graph and restore weights
saver = tf.train.import_meta_graph('my_test_model-1000.meta')
saver.restore(sess,tf.train.latest_checkpoint('./'))


# Access saved Variables directly
print(sess.run('bias:0'))
# This will print 2, which is the value of bias that we saved


# Now, let's access and create placeholders variables and
# create feed-dict to feed new data

graph = tf.get_default_graph()
w1 = graph.get_tensor_by_name("w1:0")
w2 = graph.get_tensor_by_name("w2:0")
feed_dict ={w1:13.0,w2:17.0}

#Now, access the op that you want to run. 
op_to_restore = graph.get_tensor_by_name("op_to_restore:0")

print sess.run(op_to_restore,feed_dict)
#This will print 60 which is calculated 

这里和一些更高级的用例已经很好地解释了。

快速完整的教程,用于保存和恢复Tensorflow模型

I am improving my answer to add more details for saving and restoring models.

In(and after) Tensorflow version 0.11:

Save the model:

import tensorflow as tf

#Prepare to feed input, i.e. feed_dict and placeholders
w1 = tf.placeholder("float", name="w1")
w2 = tf.placeholder("float", name="w2")
b1= tf.Variable(2.0,name="bias")
feed_dict ={w1:4,w2:8}

#Define a test operation that we will restore
w3 = tf.add(w1,w2)
w4 = tf.multiply(w3,b1,name="op_to_restore")
sess = tf.Session()
sess.run(tf.global_variables_initializer())

#Create a saver object which will save all the variables
saver = tf.train.Saver()

#Run the operation by feeding input
print sess.run(w4,feed_dict)
#Prints 24 which is sum of (w1+w2)*b1 

#Now, save the graph
saver.save(sess, 'my_test_model',global_step=1000)

Restore the model:

import tensorflow as tf

sess=tf.Session()    
#First let's load meta graph and restore weights
saver = tf.train.import_meta_graph('my_test_model-1000.meta')
saver.restore(sess,tf.train.latest_checkpoint('./'))


# Access saved Variables directly
print(sess.run('bias:0'))
# This will print 2, which is the value of bias that we saved


# Now, let's access and create placeholders variables and
# create feed-dict to feed new data

graph = tf.get_default_graph()
w1 = graph.get_tensor_by_name("w1:0")
w2 = graph.get_tensor_by_name("w2:0")
feed_dict ={w1:13.0,w2:17.0}

#Now, access the op that you want to run. 
op_to_restore = graph.get_tensor_by_name("op_to_restore:0")

print sess.run(op_to_restore,feed_dict)
#This will print 60 which is calculated 

This and some more advanced use-cases have been explained very well here.

A quick complete tutorial to save and restore Tensorflow models


回答 2

在TensorFlow版本0.11.0RC1中(及之后),您可以直接调用tf.train.export_meta_graphtf.train.import_meta_graph根据https://www.tensorflow.org/programmers_guide/meta_graph来保存和恢复模型。

保存模型

w1 = tf.Variable(tf.truncated_normal(shape=[10]), name='w1')
w2 = tf.Variable(tf.truncated_normal(shape=[20]), name='w2')
tf.add_to_collection('vars', w1)
tf.add_to_collection('vars', w2)
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver.save(sess, 'my-model')
# `save` method will call `export_meta_graph` implicitly.
# you will get saved graph files:my-model.meta

恢复模型

sess = tf.Session()
new_saver = tf.train.import_meta_graph('my-model.meta')
new_saver.restore(sess, tf.train.latest_checkpoint('./'))
all_vars = tf.get_collection('vars')
for v in all_vars:
    v_ = sess.run(v)
    print(v_)

In (and after) TensorFlow version 0.11.0RC1, you can save and restore your model directly by calling tf.train.export_meta_graph and tf.train.import_meta_graph according to https://www.tensorflow.org/programmers_guide/meta_graph.

Save the model

w1 = tf.Variable(tf.truncated_normal(shape=[10]), name='w1')
w2 = tf.Variable(tf.truncated_normal(shape=[20]), name='w2')
tf.add_to_collection('vars', w1)
tf.add_to_collection('vars', w2)
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver.save(sess, 'my-model')
# `save` method will call `export_meta_graph` implicitly.
# you will get saved graph files:my-model.meta

Restore the model

sess = tf.Session()
new_saver = tf.train.import_meta_graph('my-model.meta')
new_saver.restore(sess, tf.train.latest_checkpoint('./'))
all_vars = tf.get_collection('vars')
for v in all_vars:
    v_ = sess.run(v)
    print(v_)

回答 3

对于TensorFlow版本<0.11.0RC1:

保存的检查点包含以下值: Variable模型中 s,而不是模型/图形本身,这意味着在还原检查点时,图形应相同。

这是线性回归的示例,其中存在一个训练循环,该循环保存变量检查点,而评估部分将恢复先前运行中保存的变量并计算预测。当然,您也可以根据需要恢复变量并继续训练。

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

w = tf.Variable(tf.zeros([1, 1], dtype=tf.float32))
b = tf.Variable(tf.ones([1, 1], dtype=tf.float32))
y_hat = tf.add(b, tf.matmul(x, w))

...more setup for optimization and what not...

saver = tf.train.Saver()  # defaults to saving all variables - in this case w and b

with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    if FLAGS.train:
        for i in xrange(FLAGS.training_steps):
            ...training loop...
            if (i + 1) % FLAGS.checkpoint_steps == 0:
                saver.save(sess, FLAGS.checkpoint_dir + 'model.ckpt',
                           global_step=i+1)
    else:
        # Here's where you're restoring the variables w and b.
        # Note that the graph is exactly as it was when the variables were
        # saved in a prior training run.
        ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)
        if ckpt and ckpt.model_checkpoint_path:
            saver.restore(sess, ckpt.model_checkpoint_path)
        else:
            ...no checkpoint found...

        # Now you can run the model to get predictions
        batch_x = ...load some data...
        predictions = sess.run(y_hat, feed_dict={x: batch_x})

下面是文档Variables,这包括保存和恢复。这里是文档Saver

For TensorFlow version < 0.11.0RC1:

The checkpoints that are saved contain values for the Variables in your model, not the model/graph itself, which means that the graph should be the same when you restore the checkpoint.

Here’s an example for a linear regression where there’s a training loop that saves variable checkpoints and an evaluation section that will restore variables saved in a prior run and compute predictions. Of course, you can also restore variables and continue training if you’d like.

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

w = tf.Variable(tf.zeros([1, 1], dtype=tf.float32))
b = tf.Variable(tf.ones([1, 1], dtype=tf.float32))
y_hat = tf.add(b, tf.matmul(x, w))

...more setup for optimization and what not...

saver = tf.train.Saver()  # defaults to saving all variables - in this case w and b

with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    if FLAGS.train:
        for i in xrange(FLAGS.training_steps):
            ...training loop...
            if (i + 1) % FLAGS.checkpoint_steps == 0:
                saver.save(sess, FLAGS.checkpoint_dir + 'model.ckpt',
                           global_step=i+1)
    else:
        # Here's where you're restoring the variables w and b.
        # Note that the graph is exactly as it was when the variables were
        # saved in a prior training run.
        ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)
        if ckpt and ckpt.model_checkpoint_path:
            saver.restore(sess, ckpt.model_checkpoint_path)
        else:
            ...no checkpoint found...

        # Now you can run the model to get predictions
        batch_x = ...load some data...
        predictions = sess.run(y_hat, feed_dict={x: batch_x})

Here are the docs for Variables, which cover saving and restoring. And here are the docs for the Saver.


回答 4

我的环境:Python 3.6,Tensorflow 1.3.0

尽管有许多解决方案,但是大多数解决方案都基于tf.train.Saver。当我们加载.ckpt保存的Saver,我们必须要么重新定义tensorflow网络,或者使用一些奇怪的和难以记住的名称,例如'placehold_0:0''dense/Adam/Weight:0'。我建议在这里使用tf.saved_model下面给出的一个最简单的示例,您可以从服务TensorFlow模型中了解更多信息:

保存模型:

import tensorflow as tf

# define the tensorflow network and do some trains
x = tf.placeholder("float", name="x")
w = tf.Variable(2.0, name="w")
b = tf.Variable(0.0, name="bias")

h = tf.multiply(x, w)
y = tf.add(h, b, name="y")
sess = tf.Session()
sess.run(tf.global_variables_initializer())

# save the model
export_path =  './savedmodel'
builder = tf.saved_model.builder.SavedModelBuilder(export_path)

tensor_info_x = tf.saved_model.utils.build_tensor_info(x)
tensor_info_y = tf.saved_model.utils.build_tensor_info(y)

prediction_signature = (
  tf.saved_model.signature_def_utils.build_signature_def(
      inputs={'x_input': tensor_info_x},
      outputs={'y_output': tensor_info_y},
      method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))

builder.add_meta_graph_and_variables(
  sess, [tf.saved_model.tag_constants.SERVING],
  signature_def_map={
      tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
          prediction_signature 
  },
  )
builder.save()

加载模型:

import tensorflow as tf
sess=tf.Session() 
signature_key = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
input_key = 'x_input'
output_key = 'y_output'

export_path =  './savedmodel'
meta_graph_def = tf.saved_model.loader.load(
           sess,
          [tf.saved_model.tag_constants.SERVING],
          export_path)
signature = meta_graph_def.signature_def

x_tensor_name = signature[signature_key].inputs[input_key].name
y_tensor_name = signature[signature_key].outputs[output_key].name

x = sess.graph.get_tensor_by_name(x_tensor_name)
y = sess.graph.get_tensor_by_name(y_tensor_name)

y_out = sess.run(y, {x: 3.0})

My environment: Python 3.6, Tensorflow 1.3.0

Though there have been many solutions, most of them is based on tf.train.Saver. When we load a .ckpt saved by Saver, we have to either redefine the tensorflow network or use some weird and hard-remembered name, e.g. 'placehold_0:0','dense/Adam/Weight:0'. Here I recommend to use tf.saved_model, one simplest example given below, your can learn more from Serving a TensorFlow Model:

Save the model:

import tensorflow as tf

# define the tensorflow network and do some trains
x = tf.placeholder("float", name="x")
w = tf.Variable(2.0, name="w")
b = tf.Variable(0.0, name="bias")

h = tf.multiply(x, w)
y = tf.add(h, b, name="y")
sess = tf.Session()
sess.run(tf.global_variables_initializer())

# save the model
export_path =  './savedmodel'
builder = tf.saved_model.builder.SavedModelBuilder(export_path)

tensor_info_x = tf.saved_model.utils.build_tensor_info(x)
tensor_info_y = tf.saved_model.utils.build_tensor_info(y)

prediction_signature = (
  tf.saved_model.signature_def_utils.build_signature_def(
      inputs={'x_input': tensor_info_x},
      outputs={'y_output': tensor_info_y},
      method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))

builder.add_meta_graph_and_variables(
  sess, [tf.saved_model.tag_constants.SERVING],
  signature_def_map={
      tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
          prediction_signature 
  },
  )
builder.save()

Load the model:

import tensorflow as tf
sess=tf.Session() 
signature_key = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
input_key = 'x_input'
output_key = 'y_output'

export_path =  './savedmodel'
meta_graph_def = tf.saved_model.loader.load(
           sess,
          [tf.saved_model.tag_constants.SERVING],
          export_path)
signature = meta_graph_def.signature_def

x_tensor_name = signature[signature_key].inputs[input_key].name
y_tensor_name = signature[signature_key].outputs[output_key].name

x = sess.graph.get_tensor_by_name(x_tensor_name)
y = sess.graph.get_tensor_by_name(y_tensor_name)

y_out = sess.run(y, {x: 3.0})

回答 5

有两个部分的模型,该模型定义,通过保存Supervisorgraph.pbtxt模型中的目录和张量的数值,保存到像检查点文件model.ckpt-1003418

可以使用还原模型定义tf.import_graph_def,并使用还原权重Saver

但是,Saver使用包含在模型Graph上的变量的特殊集合保存列表,并且此集合未使用import_graph_def进行初始化,因此您目前无法将两者一起使用(正在修复中)。现在,您必须使用Ryan Sepassi的方法-手动构造具有相同节点名称的图,然后Saver将权重加载到其中。

(或者,您可以通过使用import_graph_def,手动创建变量,并tf.add_to_collection(tf.GraphKeys.VARIABLES, variable)针对每个变量使用,然后使用来对其进行破解Saver

There are two parts to the model, the model definition, saved by Supervisor as graph.pbtxt in the model directory and the numerical values of tensors, saved into checkpoint files like model.ckpt-1003418.

The model definition can be restored using tf.import_graph_def, and the weights are restored using Saver.

However, Saver uses special collection holding list of variables that’s attached to the model Graph, and this collection is not initialized using import_graph_def, so you can’t use the two together at the moment (it’s on our roadmap to fix). For now, you have to use approach of Ryan Sepassi — manually construct a graph with identical node names, and use Saver to load the weights into it.

(Alternatively you could hack it by using by using import_graph_def, creating variables manually, and using tf.add_to_collection(tf.GraphKeys.VARIABLES, variable) for each variable, then using Saver)


回答 6

您也可以采用这种更简单的方法。

步骤1:初始化所有变量

W1 = tf.Variable(tf.truncated_normal([6, 6, 1, K], stddev=0.1), name="W1")
B1 = tf.Variable(tf.constant(0.1, tf.float32, [K]), name="B1")

Similarly, W2, B2, W3, .....

步骤2:Saver将会话保存在模型中并保存

model_saver = tf.train.Saver()

# Train the model and save it in the end
model_saver.save(session, "saved_models/CNN_New.ckpt")

步骤3:还原模型

with tf.Session(graph=graph_cnn) as session:
    model_saver.restore(session, "saved_models/CNN_New.ckpt")
    print("Model restored.") 
    print('Initialized')

第4步:检查您的变量

W1 = session.run(W1)
print(W1)

在其他python实例中运行时,请使用

with tf.Session() as sess:
    # Restore latest checkpoint
    saver.restore(sess, tf.train.latest_checkpoint('saved_model/.'))

    # Initalize the variables
    sess.run(tf.global_variables_initializer())

    # Get default graph (supply your custom graph if you have one)
    graph = tf.get_default_graph()

    # It will give tensor object
    W1 = graph.get_tensor_by_name('W1:0')

    # To get the value (numpy array)
    W1_value = session.run(W1)

You can also take this easier way.

Step 1: initialize all your variables

W1 = tf.Variable(tf.truncated_normal([6, 6, 1, K], stddev=0.1), name="W1")
B1 = tf.Variable(tf.constant(0.1, tf.float32, [K]), name="B1")

Similarly, W2, B2, W3, .....

Step 2: save the session inside model Saver and save it

model_saver = tf.train.Saver()

# Train the model and save it in the end
model_saver.save(session, "saved_models/CNN_New.ckpt")

Step 3: restore the model

with tf.Session(graph=graph_cnn) as session:
    model_saver.restore(session, "saved_models/CNN_New.ckpt")
    print("Model restored.") 
    print('Initialized')

Step 4: check your variable

W1 = session.run(W1)
print(W1)

While running in different python instance, use

with tf.Session() as sess:
    # Restore latest checkpoint
    saver.restore(sess, tf.train.latest_checkpoint('saved_model/.'))

    # Initalize the variables
    sess.run(tf.global_variables_initializer())

    # Get default graph (supply your custom graph if you have one)
    graph = tf.get_default_graph()

    # It will give tensor object
    W1 = graph.get_tensor_by_name('W1:0')

    # To get the value (numpy array)
    W1_value = session.run(W1)

回答 7

在大多数情况下,使用a从磁盘保存和还原tf.train.Saver是最佳选择:

... # build your model
saver = tf.train.Saver()

with tf.Session() as sess:
    ... # train the model
    saver.save(sess, "/tmp/my_great_model")

with tf.Session() as sess:
    saver.restore(sess, "/tmp/my_great_model")
    ... # use the model

您也可以保存/恢复图结构本身(有关详细信息,请参见MetaGraph文档)。默认情况下,Saver将图形结构保存到.meta文件中。您可以调用import_meta_graph()进行恢复。它还原图形结构并返回一个Saver可用于还原模型状态的:

saver = tf.train.import_meta_graph("/tmp/my_great_model.meta")

with tf.Session() as sess:
    saver.restore(sess, "/tmp/my_great_model")
    ... # use the model

但是,在某些情况下,您需要更快的速度。例如,如果实施提前停止,则希望在训练过程中每次模型改进时都保存检查点(以验证集为准),然后如果一段时间没有进展,则希望回滚到最佳模型。如果您在每次改进时都将模型保存到磁盘,则会极大地减慢训练速度。诀窍是将变量状态保存到内存中,然后稍后再恢复它们:

... # build your model

# get a handle on the graph nodes we need to save/restore the model
graph = tf.get_default_graph()
gvars = graph.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
assign_ops = [graph.get_operation_by_name(v.op.name + "/Assign") for v in gvars]
init_values = [assign_op.inputs[1] for assign_op in assign_ops]

with tf.Session() as sess:
    ... # train the model

    # when needed, save the model state to memory
    gvars_state = sess.run(gvars)

    # when needed, restore the model state
    feed_dict = {init_value: val
                 for init_value, val in zip(init_values, gvars_state)}
    sess.run(assign_ops, feed_dict=feed_dict)

快速说明:创建变量时X,TensorFlow自动创建一个赋值操作X/Assign以设置变量的初始值。与其创建占位符和额外的分配操作(这只会使图形混乱),我们仅使用这些现有的分配操作。每个赋值op的第一个输入是对应该初始化的变量的引用,第二个输入(assign_op.inputs[1])是初始值。因此,为了设置所需的任何值(而不是初始值),我们需要使用a feed_dict并替换初始值。是的,TensorFlow允许您为任何操作提供值,而不仅仅是占位符,因此可以正常工作。

In most cases, saving and restoring from disk using a tf.train.Saver is your best option:

... # build your model
saver = tf.train.Saver()

with tf.Session() as sess:
    ... # train the model
    saver.save(sess, "/tmp/my_great_model")

with tf.Session() as sess:
    saver.restore(sess, "/tmp/my_great_model")
    ... # use the model

You can also save/restore the graph structure itself (see the MetaGraph documentation for details). By default, the Saver saves the graph structure into a .meta file. You can call import_meta_graph() to restore it. It restores the graph structure and returns a Saver that you can use to restore the model’s state:

saver = tf.train.import_meta_graph("/tmp/my_great_model.meta")

with tf.Session() as sess:
    saver.restore(sess, "/tmp/my_great_model")
    ... # use the model

However, there are cases where you need something much faster. For example, if you implement early stopping, you want to save checkpoints every time the model improves during training (as measured on the validation set), then if there is no progress for some time, you want to roll back to the best model. If you save the model to disk every time it improves, it will tremendously slow down training. The trick is to save the variable states to memory, then just restore them later:

... # build your model

# get a handle on the graph nodes we need to save/restore the model
graph = tf.get_default_graph()
gvars = graph.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
assign_ops = [graph.get_operation_by_name(v.op.name + "/Assign") for v in gvars]
init_values = [assign_op.inputs[1] for assign_op in assign_ops]

with tf.Session() as sess:
    ... # train the model

    # when needed, save the model state to memory
    gvars_state = sess.run(gvars)

    # when needed, restore the model state
    feed_dict = {init_value: val
                 for init_value, val in zip(init_values, gvars_state)}
    sess.run(assign_ops, feed_dict=feed_dict)

A quick explanation: when you create a variable X, TensorFlow automatically creates an assignment operation X/Assign to set the variable’s initial value. Instead of creating placeholders and extra assignment ops (which would just make the graph messy), we just use these existing assignment ops. The first input of each assignment op is a reference to the variable it is supposed to initialize, and the second input (assign_op.inputs[1]) is the initial value. So in order to set any value we want (instead of the initial value), we need to use a feed_dict and replace the initial value. Yes, TensorFlow lets you feed a value for any op, not just for placeholders, so this works fine.


回答 8

正如Yaroslav所说,您可以通过导入图形,手动创建变量然后使用Saver来从graph_def和检查点恢复。

我将其实现为个人使用,因此尽管我在这里共享了代码。

链接: https //gist.github.com/nikitakit/6ef3b72be67b86cb7868

(当然,这是黑客,不能保证以此方式保存的模型在TensorFlow的未来版本中仍可读取。)

As Yaroslav said, you can hack restoring from a graph_def and checkpoint by importing the graph, manually creating variables, and then using a Saver.

I implemented this for my personal use, so I though I’d share the code here.

Link: https://gist.github.com/nikitakit/6ef3b72be67b86cb7868

(This is, of course, a hack, and there is no guarantee that models saved this way will remain readable in future versions of TensorFlow.)


回答 9

如果是内部保存的模型,则只需为所有变量指定一个还原器即可

restorer = tf.train.Saver(tf.all_variables())

并使用它来还原当前会话中的变量:

restorer.restore(self._sess, model_file)

对于外部模型,您需要指定从其变量名到变量名的映射。您可以使用以下命令查看模型变量名称

python /path/to/tensorflow/tensorflow/python/tools/inspect_checkpoint.py --file_name=/path/to/pretrained_model/model.ckpt

可以在Tensorflow源的’./tensorflow/python/tools’文件夹中找到inspect_checkpoint.py脚本。

要指定映射,您可以使用我的Tensorflow-Worklab,其中包含一组用于训练和重新训练不同模型的类和脚本。它包含一个重新训练ResNet模型的示例,位于此处

If it is an internally saved model, you just specify a restorer for all variables as

restorer = tf.train.Saver(tf.all_variables())

and use it to restore variables in a current session:

restorer.restore(self._sess, model_file)

For the external model you need to specify the mapping from the its variable names to your variable names. You can view the model variable names using the command

python /path/to/tensorflow/tensorflow/python/tools/inspect_checkpoint.py --file_name=/path/to/pretrained_model/model.ckpt

The inspect_checkpoint.py script can be found in ‘./tensorflow/python/tools’ folder of the Tensorflow source.

To specify the mapping, you can use my Tensorflow-Worklab, which contains a set of classes and scripts to train and retrain different models. It includes an example of retraining ResNet models, located here


回答 10

这是我针对两种基本情况的简单解决方案,不同之处在于您是要从文件中加载图形还是在运行时构建图形。

该答案适用于Tensorflow 0.12+(包括1.0)。

在代码中重建图形

保存

graph = ... # build the graph
saver = tf.train.Saver()  # create the saver after the graph
with ... as sess:  # your session object
    saver.save(sess, 'my-model')

载入中

graph = ... # build the graph
saver = tf.train.Saver()  # create the saver after the graph
with ... as sess:  # your session object
    saver.restore(sess, tf.train.latest_checkpoint('./'))
    # now you can use the graph, continue training or whatever

还从文件加载图形

使用此技术时,请确保所有图层/变量均已明确设置唯一名称。否则,Tensorflow将使名称本身具有唯一性,因此它们将与文件中存储的名称不同。在以前的技术中这不是问题,因为在加载和保存时都以相同的方式“混合”了名称。

保存

graph = ... # build the graph

for op in [ ... ]:  # operators you want to use after restoring the model
    tf.add_to_collection('ops_to_restore', op)

saver = tf.train.Saver()  # create the saver after the graph
with ... as sess:  # your session object
    saver.save(sess, 'my-model')

载入中

with ... as sess:  # your session object
    saver = tf.train.import_meta_graph('my-model.meta')
    saver.restore(sess, tf.train.latest_checkpoint('./'))
    ops = tf.get_collection('ops_to_restore')  # here are your operators in the same order in which you saved them to the collection

Here’s my simple solution for the two basic cases differing on whether you want to load the graph from file or build it during runtime.

This answer holds for Tensorflow 0.12+ (including 1.0).

Rebuilding the graph in code

Saving

graph = ... # build the graph
saver = tf.train.Saver()  # create the saver after the graph
with ... as sess:  # your session object
    saver.save(sess, 'my-model')

Loading

graph = ... # build the graph
saver = tf.train.Saver()  # create the saver after the graph
with ... as sess:  # your session object
    saver.restore(sess, tf.train.latest_checkpoint('./'))
    # now you can use the graph, continue training or whatever

Loading also the graph from a file

When using this technique, make sure all your layers/variables have explicitly set unique names. Otherwise Tensorflow will make the names unique itself and they’ll be thus different from the names stored in the file. It’s not a problem in the previous technique, because the names are “mangled” the same way in both loading and saving.

Saving

graph = ... # build the graph

for op in [ ... ]:  # operators you want to use after restoring the model
    tf.add_to_collection('ops_to_restore', op)

saver = tf.train.Saver()  # create the saver after the graph
with ... as sess:  # your session object
    saver.save(sess, 'my-model')

Loading

with ... as sess:  # your session object
    saver = tf.train.import_meta_graph('my-model.meta')
    saver.restore(sess, tf.train.latest_checkpoint('./'))
    ops = tf.get_collection('ops_to_restore')  # here are your operators in the same order in which you saved them to the collection

回答 11

您还可以在TensorFlow / skflow中查看示例,这些示例和方法可以帮助您轻松管理模型。它具有的参数还可以控制您备份模型的频率。saverestore

You can also check out examples in TensorFlow/skflow, which offers save and restore methods that can help you easily manage your models. It has parameters that you can also control how frequently you want to back up your model.


回答 12

如果您将tf.train.MonitoredTrainingSession用作默认会话,则无需添加额外的代码即可保存/还原内容。只需将检查点目录名传递给MonitoredTrainingSession的构造函数,它将使用会话挂钩来处理这些。

If you use tf.train.MonitoredTrainingSession as the default session, you don’t need to add extra code to do save/restore things. Just pass a checkpoint dir name to MonitoredTrainingSession’s constructor, it will use session hooks to handle these.


回答 13

这里的所有答案都很好,但我想补充两点。

首先,要详细说明@ user7505159的答案,将“ ./”添加到要还原的文件名的开头很重要。

例如,您可以保存一个图形,文件名中不包含“ ./”,如下所示:

# Some graph defined up here with specific names

saver = tf.train.Saver()
save_file = 'model.ckpt'

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver.save(sess, save_file)

但是为了还原图形,您可能需要在file_name前面加上“ ./”:

# Same graph defined up here

saver = tf.train.Saver()
save_file = './' + 'model.ckpt' # String addition used for emphasis

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver.restore(sess, save_file)

您不一定总是需要“ ./”,但是根据您的环境和TensorFlow的版本,它可能会引起问题。

它还要提到,sess.run(tf.global_variables_initializer())在恢复会话之前,这可能很重要。

如果在尝试还原已保存的会话时收到关于未初始化变量的错误,请确保在行sess.run(tf.global_variables_initializer())之前包括saver.restore(sess, save_file)。它可以节省您的头痛。

All the answers here are great, but I want to add two things.

First, to elaborate on @user7505159’s answer, the “./” can be important to add to the beginning of the file name that you are restoring.

For example, you can save a graph with no “./” in the file name like so:

# Some graph defined up here with specific names

saver = tf.train.Saver()
save_file = 'model.ckpt'

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver.save(sess, save_file)

But in order to restore the graph, you may need to prepend a “./” to the file_name:

# Same graph defined up here

saver = tf.train.Saver()
save_file = './' + 'model.ckpt' # String addition used for emphasis

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver.restore(sess, save_file)

You will not always need the “./”, but it can cause problems depending on your environment and version of TensorFlow.

It also want to mention that the sess.run(tf.global_variables_initializer()) can be important before restoring the session.

If you are receiving an error regarding uninitialized variables when trying to restore a saved session, make sure you include sess.run(tf.global_variables_initializer()) before the saver.restore(sess, save_file) line. It can save you a headache.


回答 14

如问题6255中所述

use '**./**model_name.ckpt'
saver.restore(sess,'./my_model_final.ckpt')

代替

saver.restore('my_model_final.ckpt')

As described in issue 6255:

use '**./**model_name.ckpt'
saver.restore(sess,'./my_model_final.ckpt')

instead of

saver.restore('my_model_final.ckpt')

回答 15

根据新的Tensorflow版本,tf.train.Checkpoint保存和还原模型的首选方法是:

Checkpoint.saveCheckpoint.restore写入和读取基于对象的检查点,而tf.train.Saver则写入和读取基于variable.name的检查点。基于对象的检查点保存带有命名边的Python对象(层,优化程序,变量等)之间的依存关系图,该图用于在恢复检查点时匹配变量。它对Python程序中的更改可能更健壮,并有助于在急切执行时支持变量的创建时恢复。身高tf.train.Checkpoint超过 tf.train.Saver对新代码

这是一个例子:

import tensorflow as tf
import os

tf.enable_eager_execution()

checkpoint_directory = "/tmp/training_checkpoints"
checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt")

checkpoint = tf.train.Checkpoint(optimizer=optimizer, model=model)
status = checkpoint.restore(tf.train.latest_checkpoint(checkpoint_directory))
for _ in range(num_training_steps):
  optimizer.minimize( ... )  # Variables will be restored on creation.
status.assert_consumed()  # Optional sanity checks.
checkpoint.save(file_prefix=checkpoint_prefix)

更多信息和示例在这里。

According to the new Tensorflow version, tf.train.Checkpoint is the preferable way of saving and restoring a model:

Checkpoint.save and Checkpoint.restore write and read object-based checkpoints, in contrast to tf.train.Saver which writes and reads variable.name based checkpoints. Object-based checkpointing saves a graph of dependencies between Python objects (Layers, Optimizers, Variables, etc.) with named edges, and this graph is used to match variables when restoring a checkpoint. It can be more robust to changes in the Python program, and helps to support restore-on-create for variables when executing eagerly. Prefer tf.train.Checkpoint over tf.train.Saver for new code.

Here is an example:

import tensorflow as tf
import os

tf.enable_eager_execution()

checkpoint_directory = "/tmp/training_checkpoints"
checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt")

checkpoint = tf.train.Checkpoint(optimizer=optimizer, model=model)
status = checkpoint.restore(tf.train.latest_checkpoint(checkpoint_directory))
for _ in range(num_training_steps):
  optimizer.minimize( ... )  # Variables will be restored on creation.
status.assert_consumed()  # Optional sanity checks.
checkpoint.save(file_prefix=checkpoint_prefix)

More information and example here.


回答 16

对于tensorflow 2.0,它很简单

# Save the model
model.save('path_to_my_model.h5')

恢复:

new_model = tensorflow.keras.models.load_model('path_to_my_model.h5')

For tensorflow 2.0, it is as simple as

# Save the model
model.save('path_to_my_model.h5')

To restore:

new_model = tensorflow.keras.models.load_model('path_to_my_model.h5')

回答 17

tf.keras模型保存 TF2.0

对于使用TF1.x保存模型,我看到了很好的答案。我想在保存中提供更多的指示tensorflow.keras模型时这有点复杂,因为有很多方法可以保存模型。

在这里,我提供了一个将tensorflow.keras模型保存到model_path当前目录下的文件夹的示例。这与最新的tensorflow(TF2.0)一起很好地工作。如果近期有任何更改,我将更新此描述。

保存和加载整个模型

import tensorflow as tf
from tensorflow import keras
mnist = tf.keras.datasets.mnist

#import data
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# create a model
def create_model():
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])
# compile the model
  model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
  return model

# Create a basic model instance
model=create_model()

model.fit(x_train, y_train, epochs=1)
loss, acc = model.evaluate(x_test, y_test,verbose=1)
print("Original model, accuracy: {:5.2f}%".format(100*acc))

# Save entire model to a HDF5 file
model.save('./model_path/my_model.h5')

# Recreate the exact same model, including weights and optimizer.
new_model = keras.models.load_model('./model_path/my_model.h5')
loss, acc = new_model.evaluate(x_test, y_test)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

仅保存和加载模型权重

如果只对保存模型权重感兴趣,然后对加载权重以恢复模型感兴趣,那么

model.fit(x_train, y_train, epochs=5)
loss, acc = model.evaluate(x_test, y_test,verbose=1)
print("Original model, accuracy: {:5.2f}%".format(100*acc))

# Save the weights
model.save_weights('./checkpoints/my_checkpoint')

# Restore the weights
model = create_model()
model.load_weights('./checkpoints/my_checkpoint')

loss,acc = model.evaluate(x_test, y_test)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

使用keras检查点回调进行保存和还原

# include the epoch in the file name. (uses `str.format`)
checkpoint_path = "training_2/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(
    checkpoint_path, verbose=1, save_weights_only=True,
    # Save weights, every 5-epochs.
    period=5)

model = create_model()
model.save_weights(checkpoint_path.format(epoch=0))
model.fit(train_images, train_labels,
          epochs = 50, callbacks = [cp_callback],
          validation_data = (test_images,test_labels),
          verbose=0)

latest = tf.train.latest_checkpoint(checkpoint_dir)

new_model = create_model()
new_model.load_weights(latest)
loss, acc = new_model.evaluate(test_images, test_labels)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

使用自定义指标保存模型

import tensorflow as tf
from tensorflow import keras
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# Custom Loss1 (for example) 
@tf.function() 
def customLoss1(yTrue,yPred):
  return tf.reduce_mean(yTrue-yPred) 

# Custom Loss2 (for example) 
@tf.function() 
def customLoss2(yTrue, yPred):
  return tf.reduce_mean(tf.square(tf.subtract(yTrue,yPred))) 

def create_model():
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),  
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])
  model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy', customLoss1, customLoss2])
  return model

# Create a basic model instance
model=create_model()

# Fit and evaluate model 
model.fit(x_train, y_train, epochs=1)
loss, acc,loss1, loss2 = model.evaluate(x_test, y_test,verbose=1)
print("Original model, accuracy: {:5.2f}%".format(100*acc))

model.save("./model.h5")

new_model=tf.keras.models.load_model("./model.h5",custom_objects={'customLoss1':customLoss1,'customLoss2':customLoss2})

使用自定义操作保存Keras模型

如以下情况(tf.tile)所示,当我们具有自定义操作时,我们需要创建一个函数并包装一个Lambda层。否则,无法保存模型。

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, Lambda
from tensorflow.keras import Model

def my_fun(a):
  out = tf.tile(a, (1, tf.shape(a)[0]))
  return out

a = Input(shape=(10,))
#out = tf.tile(a, (1, tf.shape(a)[0]))
out = Lambda(lambda x : my_fun(x))(a)
model = Model(a, out)

x = np.zeros((50,10), dtype=np.float32)
print(model(x).numpy())

model.save('my_model.h5')

#load the model
new_model=tf.keras.models.load_model("my_model.h5")

我想我已经介绍了许多保存tf.keras模型的方法。但是,还有许多其他方法。如果您发现上面没有涉及用例,请在下面发表评论。谢谢!

tf.keras Model saving with TF2.0

I see great answers for saving models using TF1.x. I want to provide couple of more pointers in saving tensorflow.keras models which is a little complicated as there are many ways to save a model.

Here I am providing an example of saving a tensorflow.keras model to model_path folder under current directory. This works well with most recent tensorflow (TF2.0). I will update this description if there is any change in near future.

Saving and loading entire model

import tensorflow as tf
from tensorflow import keras
mnist = tf.keras.datasets.mnist

#import data
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# create a model
def create_model():
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])
# compile the model
  model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
  return model

# Create a basic model instance
model=create_model()

model.fit(x_train, y_train, epochs=1)
loss, acc = model.evaluate(x_test, y_test,verbose=1)
print("Original model, accuracy: {:5.2f}%".format(100*acc))

# Save entire model to a HDF5 file
model.save('./model_path/my_model.h5')

# Recreate the exact same model, including weights and optimizer.
new_model = keras.models.load_model('./model_path/my_model.h5')
loss, acc = new_model.evaluate(x_test, y_test)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

Saving and loading model Weights only

If you are interested in saving model weights only and then load weights to restore the model, then

model.fit(x_train, y_train, epochs=5)
loss, acc = model.evaluate(x_test, y_test,verbose=1)
print("Original model, accuracy: {:5.2f}%".format(100*acc))

# Save the weights
model.save_weights('./checkpoints/my_checkpoint')

# Restore the weights
model = create_model()
model.load_weights('./checkpoints/my_checkpoint')

loss,acc = model.evaluate(x_test, y_test)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

Saving and restoring using keras checkpoint callback

# include the epoch in the file name. (uses `str.format`)
checkpoint_path = "training_2/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(
    checkpoint_path, verbose=1, save_weights_only=True,
    # Save weights, every 5-epochs.
    period=5)

model = create_model()
model.save_weights(checkpoint_path.format(epoch=0))
model.fit(train_images, train_labels,
          epochs = 50, callbacks = [cp_callback],
          validation_data = (test_images,test_labels),
          verbose=0)

latest = tf.train.latest_checkpoint(checkpoint_dir)

new_model = create_model()
new_model.load_weights(latest)
loss, acc = new_model.evaluate(test_images, test_labels)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

saving model with custom metrics

import tensorflow as tf
from tensorflow import keras
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# Custom Loss1 (for example) 
@tf.function() 
def customLoss1(yTrue,yPred):
  return tf.reduce_mean(yTrue-yPred) 

# Custom Loss2 (for example) 
@tf.function() 
def customLoss2(yTrue, yPred):
  return tf.reduce_mean(tf.square(tf.subtract(yTrue,yPred))) 

def create_model():
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),  
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])
  model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy', customLoss1, customLoss2])
  return model

# Create a basic model instance
model=create_model()

# Fit and evaluate model 
model.fit(x_train, y_train, epochs=1)
loss, acc,loss1, loss2 = model.evaluate(x_test, y_test,verbose=1)
print("Original model, accuracy: {:5.2f}%".format(100*acc))

model.save("./model.h5")

new_model=tf.keras.models.load_model("./model.h5",custom_objects={'customLoss1':customLoss1,'customLoss2':customLoss2})

Saving keras model with custom ops

When we have custom ops as in the following case (tf.tile), we need to create a function and wrap with a Lambda layer. Otherwise, model cannot be saved.

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, Lambda
from tensorflow.keras import Model

def my_fun(a):
  out = tf.tile(a, (1, tf.shape(a)[0]))
  return out

a = Input(shape=(10,))
#out = tf.tile(a, (1, tf.shape(a)[0]))
out = Lambda(lambda x : my_fun(x))(a)
model = Model(a, out)

x = np.zeros((50,10), dtype=np.float32)
print(model(x).numpy())

model.save('my_model.h5')

#load the model
new_model=tf.keras.models.load_model("my_model.h5")

I think I have covered a few of the many ways of saving tf.keras model. However, there are many other ways. Please comment below if you see your use case is not covered above. Thanks!


回答 18

使用tf.train.Saver保存模型,重命名,如果要减小模型大小,则需要指定var_list。val_list可以是tf.trainable_variables或tf.global_variables。

Use tf.train.Saver to save a model, remerber, you need to specify the var_list, if you want to reduce the model size. The val_list can be tf.trainable_variables or tf.global_variables.


回答 19

您可以使用以下方法将变量保存到网络

saver = tf.train.Saver() 
saver.save(sess, 'path of save/fileName.ckpt')

还原网络以供以后重复使用或在另一个脚本中使用,请使用:

saver = tf.train.Saver()
saver.restore(sess, tf.train.latest_checkpoint('path of save/')
sess.run(....) 

重要事项:

  1. sess 首次运行和后续运行之间必须相同(一致的结构)。
  2. saver.restore 需要已保存文件的文件夹路径,而不是单个文件路径。

You can save the variables in the network using

saver = tf.train.Saver() 
saver.save(sess, 'path of save/fileName.ckpt')

To restore the network for reuse later or in another script, use:

saver = tf.train.Saver()
saver.restore(sess, tf.train.latest_checkpoint('path of save/')
sess.run(....) 

Important points:

  1. sess must be same between first and later runs (coherent structure).
  2. saver.restore needs the path of the folder of the saved files, not an individual file path.

回答 20

无论您要将模型保存到哪里,

self.saver = tf.train.Saver()
with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            ...
            self.saver.save(sess, filename)

确保您所有的人tf.Variable都有名字,因为您以后可能要使用他们的名字来还原它们。在您想要预测的地方

saver = tf.train.import_meta_graph(filename)
name = 'name given when you saved the file' 
with tf.Session() as sess:
      saver.restore(sess, name)
      print(sess.run('W1:0')) #example to retrieve by variable name

确保保护程序在相应的会话中运行。请记住,如果使用tf.train.latest_checkpoint('./'),则将仅使用最新的检查点。

Wherever you want to save the model,

self.saver = tf.train.Saver()
with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            ...
            self.saver.save(sess, filename)

Make sure, all your tf.Variable have names, because you may want to restore them later using their names. And where you want to predict,

saver = tf.train.import_meta_graph(filename)
name = 'name given when you saved the file' 
with tf.Session() as sess:
      saver.restore(sess, name)
      print(sess.run('W1:0')) #example to retrieve by variable name

Make sure that saver runs inside the corresponding session. Remember that, if you use the tf.train.latest_checkpoint('./'), then only the latest check point will be used.


回答 21

我正在使用版本:

tensorflow (1.13.1)
tensorflow-gpu (1.13.1)

简单的方法是

救:

model.save("model.h5")

恢复:

model = tf.keras.models.load_model("model.h5")

I’m on Version:

tensorflow (1.13.1)
tensorflow-gpu (1.13.1)

Simple way is

Save:

model.save("model.h5")

Restore:

model = tf.keras.models.load_model("model.h5")

回答 22

对于tensorflow-2.0

这很简单。

import tensorflow as tf

model.save("model_name")

恢复

model = tf.keras.models.load_model('model_name')

For tensorflow-2.0

it’s very simple.

import tensorflow as tf

SAVE

model.save("model_name")

RESTORE

model = tf.keras.models.load_model('model_name')

回答 23

遵循@Vishnuvardhan Janapati的回答,这是在TensorFlow 2.0.0下使用自定义图层/度量/损耗来保存和重新加载模型的另一种方法

import tensorflow as tf
from tensorflow.keras.layers import Layer
from tensorflow.keras.utils.generic_utils import get_custom_objects

# custom loss (for example)  
def custom_loss(y_true,y_pred):
  return tf.reduce_mean(y_true - y_pred)
get_custom_objects().update({'custom_loss': custom_loss}) 

# custom loss (for example) 
class CustomLayer(Layer):
  def __init__(self, ...):
      ...
  # define custom layer and all necessary custom operations inside custom layer

get_custom_objects().update({'CustomLayer': CustomLayer})  

这样,一旦执行了此类代码,并使用tf.keras.models.save_modelmodel.saveModelCheckpoint回调保存了模型,就可以重新加载模型,而无需精确的自定义对象,就像

new_model = tf.keras.models.load_model("./model.h5"})

Following @Vishnuvardhan Janapati ‘s answer, here is another way to save and reload model with custom layer/metric/loss under TensorFlow 2.0.0

import tensorflow as tf
from tensorflow.keras.layers import Layer
from tensorflow.keras.utils.generic_utils import get_custom_objects

# custom loss (for example)  
def custom_loss(y_true,y_pred):
  return tf.reduce_mean(y_true - y_pred)
get_custom_objects().update({'custom_loss': custom_loss}) 

# custom loss (for example) 
class CustomLayer(Layer):
  def __init__(self, ...):
      ...
  # define custom layer and all necessary custom operations inside custom layer

get_custom_objects().update({'CustomLayer': CustomLayer})  

In this way, once you have executed such codes, and saved your model with tf.keras.models.save_model or model.save or ModelCheckpoint callback, you can re-load your model without the need of precise custom objects, as simple as

new_model = tf.keras.models.load_model("./model.h5"})

回答 24

在新版本的tensorflow 2.0中,保存/加载模型的过程要容易得多。由于实施了Keras API,因此是TensorFlow的高级API。

保存模型:检查文档以供参考:https : //www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/models/save_model

tf.keras.models.save_model(model_name, filepath, save_format)

加载模型:

https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/models/load_model

model = tf.keras.models.load_model(filepath)

In the new version of tensorflow 2.0, the process of saving/loading a model is a lot easier. Because of the Implementation of the Keras API, a high-level API for TensorFlow.

To save a model: Check the documentation for reference: https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/models/save_model

tf.keras.models.save_model(model_name, filepath, save_format)

To load a model:

https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/models/load_model

model = tf.keras.models.load_model(filepath)

如何在Python中使用Urlencode查询字符串?

问题:如何在Python中使用Urlencode查询字符串?

我尝试在提交之前对该字符串进行urlencode。

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 

I am trying to urlencode this string before I submit.

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 

回答 0

您需要将参数传递urlencode()为映射(dict)或2元组序列,例如:

>>> import urllib
>>> f = { 'eventName' : 'myEvent', 'eventDescription' : 'cool event'}
>>> urllib.urlencode(f)
'eventName=myEvent&eventDescription=cool+event'

Python 3或以上

采用:

>>> urllib.parse.urlencode(f)
eventName=myEvent&eventDescription=cool+event

请注意,这在通常意义上不会进行url编码(请看输出)。为此使用urllib.parse.quote_plus

You need to pass your parameters into urlencode() as either a mapping (dict), or a sequence of 2-tuples, like:

>>> import urllib
>>> f = { 'eventName' : 'myEvent', 'eventDescription' : 'cool event'}
>>> urllib.urlencode(f)
'eventName=myEvent&eventDescription=cool+event'

Python 3 or above

Use:

>>> urllib.parse.urlencode(f)
eventName=myEvent&eventDescription=cool+event

Note that this does not do url encoding in the commonly used sense (look at the output). For that use urllib.parse.quote_plus.


回答 1

Python 2

您正在寻找的是urllib.quote_plus

>>> urllib.quote_plus('string_of_characters_like_these:$#@=?%^Q^$')
'string_of_characters_like_these%3A%24%23%40%3D%3F%25%5EQ%5E%24'

Python 3

在Python 3中,该urllib软件包已分解为较小的组件。您将使用urllib.parse.quote_plus(注意parse子模块)

import urllib.parse
urllib.parse.quote_plus(...)

Python 2

What you’re looking for is urllib.quote_plus:

>>> urllib.quote_plus('string_of_characters_like_these:$#@=?%^Q^$')
'string_of_characters_like_these%3A%24%23%40%3D%3F%25%5EQ%5E%24'

Python 3

In Python 3, the urllib package has been broken into smaller components. You’ll use urllib.parse.quote_plus (note the parse child module)

import urllib.parse
urllib.parse.quote_plus(...)

回答 2

尝试使用请求而不是urllib,您无需费心urlencode!

import requests
requests.get('http://youraddress.com', params=evt.fields)

编辑:

如果您需要有序的名称/值对或一个名称的多个值,请按如下所示设置参数:

params=[('name1','value11'), ('name1','value12'), ('name2','value21'), ...]

而不是使用字典。

Try requests instead of urllib and you don’t need to bother with urlencode!

import requests
requests.get('http://youraddress.com', params=evt.fields)

EDIT:

If you need ordered name-value pairs or multiple values for a name then set params like so:

params=[('name1','value11'), ('name1','value12'), ('name2','value21'), ...]

instead of using a dictionary.


回答 3

语境

  • Python(版本2.7.2)

问题

  • 您要生成一个urlencoded查询字符串。
  • 您有一个包含名称-值对的字典或对象。
  • 您希望能够控制名称-值对的输出顺序。

  • urllib.urlencode
  • urllib.quote_plus

陷阱

以下是一个完整的解决方案,包括如何处理一些陷阱。

### ********************
## init python (version 2.7.2 )
import urllib

### ********************
## first setup a dictionary of name-value pairs
dict_name_value_pairs = {
  "bravo"   : "True != False",
  "alpha"   : "http://www.example.com",
  "charlie" : "hello world",
  "delta"   : "1234567 !@#$%^&*",
  "echo"    : "user@example.com",
  }

### ********************
## setup an exact ordering for the name-value pairs
ary_ordered_names = []
ary_ordered_names.append('alpha')
ary_ordered_names.append('bravo')
ary_ordered_names.append('charlie')
ary_ordered_names.append('delta')
ary_ordered_names.append('echo')

### ********************
## show the output results
if('NO we DO NOT care about the ordering of name-value pairs'):
  queryString  = urllib.urlencode(dict_name_value_pairs)
  print queryString 
  """
  echo=user%40example.com&bravo=True+%21%3D+False&delta=1234567+%21%40%23%24%25%5E%26%2A&charlie=hello+world&alpha=http%3A%2F%2Fwww.example.com
  """

if('YES we DO care about the ordering of name-value pairs'):
  queryString  = "&".join( [ item+'='+urllib.quote_plus(dict_name_value_pairs[item]) for item in ary_ordered_names ] )
  print queryString
  """
  alpha=http%3A%2F%2Fwww.example.com&bravo=True+%21%3D+False&charlie=hello+world&delta=1234567+%21%40%23%24%25%5E%26%2A&echo=user%40example.com
  """ 

Context

  • Python (version 2.7.2 )

Problem

  • You want to generate a urlencoded query string.
  • You have a dictionary or object containing the name-value pairs.
  • You want to be able to control the output ordering of the name-value pairs.

Solution

  • urllib.urlencode
  • urllib.quote_plus

Pitfalls

Example

The following is a complete solution, including how to deal with some pitfalls.

### ********************
## init python (version 2.7.2 )
import urllib

### ********************
## first setup a dictionary of name-value pairs
dict_name_value_pairs = {
  "bravo"   : "True != False",
  "alpha"   : "http://www.example.com",
  "charlie" : "hello world",
  "delta"   : "1234567 !@#$%^&*",
  "echo"    : "user@example.com",
  }

### ********************
## setup an exact ordering for the name-value pairs
ary_ordered_names = []
ary_ordered_names.append('alpha')
ary_ordered_names.append('bravo')
ary_ordered_names.append('charlie')
ary_ordered_names.append('delta')
ary_ordered_names.append('echo')

### ********************
## show the output results
if('NO we DO NOT care about the ordering of name-value pairs'):
  queryString  = urllib.urlencode(dict_name_value_pairs)
  print queryString 
  """
  echo=user%40example.com&bravo=True+%21%3D+False&delta=1234567+%21%40%23%24%25%5E%26%2A&charlie=hello+world&alpha=http%3A%2F%2Fwww.example.com
  """

if('YES we DO care about the ordering of name-value pairs'):
  queryString  = "&".join( [ item+'='+urllib.quote_plus(dict_name_value_pairs[item]) for item in ary_ordered_names ] )
  print queryString
  """
  alpha=http%3A%2F%2Fwww.example.com&bravo=True+%21%3D+False&charlie=hello+world&delta=1234567+%21%40%23%24%25%5E%26%2A&echo=user%40example.com
  """ 

回答 4


回答 5

尝试这个:

urllib.pathname2url(stringToURLEncode)

urlencode将不起作用,因为它仅适用于词典。quote_plus没有产生正确的输出。

Try this:

urllib.pathname2url(stringToURLEncode)

urlencode won’t work because it only works on dictionaries. quote_plus didn’t produce the correct output.


回答 6

请注意,urllib.urlencode并非总能解决问题。问题在于某些服务关心参数的顺序,当您创建字典时,这些顺序会丢失。对于这种情况,如Ricky所建议的那样,urllib.quote_plus更好。

Note that the urllib.urlencode does not always do the trick. The problem is that some services care about the order of arguments, which gets lost when you create the dictionary. For such cases, urllib.quote_plus is better, as Ricky suggested.


回答 7

在Python 3中,这与我合作

import urllib

urllib.parse.quote(query)

In Python 3, this worked with me

import urllib

urllib.parse.quote(query)

回答 8

供将来参考(例如:适用于python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'

for future references (ex: for python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'

回答 9

为了在需要同时支持python 2和python 3的脚本/程序中使用,这六个模块提供了quote和urlencode函数:

>>> from six.moves.urllib.parse import urlencode, quote
>>> data = {'some': 'query', 'for': 'encoding'}
>>> urlencode(data)
'some=query&for=encoding'
>>> url = '/some/url/with spaces and %;!<>&'
>>> quote(url)
'/some/url/with%20spaces%20and%20%25%3B%21%3C%3E%26'

For use in scripts/programs which need to support both python 2 and 3, the six module provides quote and urlencode functions:

>>> from six.moves.urllib.parse import urlencode, quote
>>> data = {'some': 'query', 'for': 'encoding'}
>>> urlencode(data)
'some=query&for=encoding'
>>> url = '/some/url/with spaces and %;!<>&'
>>> quote(url)
'/some/url/with%20spaces%20and%20%25%3B%21%3C%3E%26'

回答 10

如果urllib.parse.urlencode()给您错误,请尝试urllib3模块。

语法如下:

import urllib3
urllib3.request.urlencode({"user" : "john" }) 

If the urllib.parse.urlencode( ) is giving you errors , then Try the urllib3 module .

The syntax is as follows :

import urllib3
urllib3.request.urlencode({"user" : "john" }) 

回答 11

可能尚未提到的另一件事是,urllib.urlencode()它将字典中的空值编码为字符串,None而不是缺少该参数。我不知道通常是否需要这样做,但是不适合我的用例,因此我必须使用quote_plus

Another thing that might not have been mentioned already is that urllib.urlencode() will encode empty values in the dictionary as the string None instead of having that parameter as absent. I don’t know if this is typically desired or not, but does not fit my use case, hence I have to use quote_plus.


回答 12

为使Python 3 urllib3正常工作,您可以根据其官方文档使用以下命令:

import urllib3

http = urllib3.PoolManager()
response = http.request(
     'GET',
     'https://api.prylabs.net/eth/v1alpha1/beacon/attestations',
     fields={  # here fields are the query params
          'epoch': 1234,
          'pageSize': pageSize 
      } 
 )
response = attestations.data.decode('UTF-8')

For Python 3 urllib3 works properly, you can use as follow as per its official docs :

import urllib3

http = urllib3.PoolManager()
response = http.request(
     'GET',
     'https://api.prylabs.net/eth/v1alpha1/beacon/attestations',
     fields={  # here fields are the query params
          'epoch': 1234,
          'pageSize': pageSize 
      } 
 )
response = attestations.data.decode('UTF-8')

什么是Monkey修补?

问题:什么是Monkey修补?

我想了解什么是Monkey补丁或Monkey补丁?

是方法/运算符重载还是委派?

这些东西有什么共同点吗?

I am trying to understand, what is monkey patching or a monkey patch?

Is that something like methods/operators overloading or delegating?

Does it have anything common with these things?


回答 0

不,这与这些东西都不一样。它只是在运行时动态替换属性。

例如,考虑一个具有method的类get_data。该方法进行外部查找(例如,在数据库或Web API上),并且类中的各种其他方法都调用它。但是,在单元测试中,您不希望依赖于外部数据源-因此您可以用get_data返回一些固定数据的存根动态替换该方法。

因为Python类是可变的,并且方法只是类的属性,所以您可以随意执行此操作-实际上,您甚至可以以完全相同的方式替换模块中的类和函数。

但是,正如评论员指出的那样,在进行Monkey修补时要格外小心:

  1. 如果除了测试逻辑调用之外还有其他要求get_data,它还会调用Monkey修补的替代品,而不是原始替代品-可能是好是坏。提防。

  2. 如果存在某个变量或属性get_data,在您替换它时也指向该函数,则该别名将不会更改其含义,并且将继续指向原始get_data。(为什么?Python只是get_data将类中的名称重新绑定到其他函数对象;其他名称绑定完全不受影响。)

No, it’s not like any of those things. It’s simply the dynamic replacement of attributes at runtime.

For instance, consider a class that has a method get_data. This method does an external lookup (on a database or web API, for example), and various other methods in the class call it. However, in a unit test, you don’t want to depend on the external data source – so you dynamically replace the get_data method with a stub that returns some fixed data.

Because Python classes are mutable, and methods are just attributes of the class, you can do this as much as you like – and, in fact, you can even replace classes and functions in a module in exactly the same way.

But, as a commenter pointed out, use caution when monkeypatching:

  1. If anything else besides your test logic calls get_data as well, it will also call your monkey-patched replacement rather than the original — which can be good or bad. Just beware.

  2. If some variable or attribute exists that also points to the get_data function by the time you replace it, this alias will not change its meaning and will continue to point to the original get_data. (Why? Python just rebinds the name get_data in your class to some other function object; other name bindings are not impacted at all.)


回答 1

MonkeyPatch是一段Python代码,可在运行时(通常在启动时)扩展或修改其他代码。

一个简单的示例如下所示:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

资料来源: Zope Wiki上的MonkeyPatch页面。

A MonkeyPatch is a piece of Python code which extends or modifies other code at runtime (typically at startup).

A simple example looks like this:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

Source: MonkeyPatch page on Zope wiki.


回答 2

什么是Monkey补丁?

简而言之,Monkey修补程序是在程序运行时对模块或类进行更改。

使用示例

在Pandas文档中有一个Monkey修补的示例:

import pandas as pd
def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

为了解决这个问题,首先我们导入模块:

import pandas as pd

接下来,我们创建一个方法定义,该定义在任何类定义的范围之外都是未绑定的和自由的(由于函数和未绑定方法之间的区别是毫无意义的,Python 3取消了未绑定方法):

def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

接下来,我们简单地将该方法附加到要在其上使用的类:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

然后,我们可以在类的实例上使用方法,并在完成后删除该方法:

df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

注意改名

如果您正在使用名称处理(带有双下划线的前缀属性,这会更改名称,并且我不建议这样做),则必须手动命名。由于我不建议使用名称修饰,因此在此不再进行演示。

测试例

我们如何在测试中使用这些知识?

假设我们需要模拟对外部数据源的数据检索调用,该调用会导致错误,因为我们要确保在这种情况下的正确行为。我们可以Monkey修补数据结构以确保这种行为。(因此,使用与Daniel Roseman建议的类似的方法名称:)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

当我们测试它的行为是否依赖于此方法引发错误时,如果正确实施,我们将在测试结果中获得该行为。

只需执行上述操作,就Structure可以在整个过程中更改对象,因此,您需要在单元测试中使用设置和拆卸来避免这样做,例如:

def setUp(self):
    # retain a pointer to the actual real method:
    self.real_get_data = datasource.Structure.get_data
    # monkey patch it:
    datasource.Structure.get_data = get_data

def tearDown(self):
    # give the real method back to the Structure object:
    datasource.Structure.get_data = self.real_get_data

(虽然上面是好的,它很可能是一个更好的主意,使用mock图书馆修补代码mockpatch装饰会少些误差比上面做容易,这需要更多的代码,从而有更多机会引入错误我尚未审查其中的代码,mock但我想它以类似的方式使用了Monkey修补程序。)

What is a monkey patch?

Simply put, monkey patching is making changes to a module or class while the program is running.

Example in usage

There’s an example of monkey-patching in the Pandas documentation:

import pandas as pd
def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

To break this down, first we import our module:

import pandas as pd

Next we create a method definition, which exists unbound and free outside the scope of any class definitions (since the distinction is fairly meaningless between a function and an unbound method, Python 3 does away with the unbound method):

def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

Next we simply attach that method to the class we want to use it on:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

And then we can use the method on an instance of the class, and delete the method when we’re done:

df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

Caveat for name-mangling

If you’re using name-mangling (prefixing attributes with a double-underscore, which alters the name, and which I don’t recommend) you’ll have to name-mangle manually if you do this. Since I don’t recommend name-mangling, I will not demonstrate it here.

Testing Example

How can we use this knowledge, for example, in testing?

Say we need to simulate a data retrieval call to an outside data source that results in an error, because we want to ensure correct behavior in such a case. We can monkey patch the data structure to ensure this behavior. (So using a similar method name as suggested by Daniel Roseman:)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

And when we test it for behavior that relies on this method raising an error, if correctly implemented, we’ll get that behavior in the test results.

Just doing the above will alter the Structure object for the life of the process, so you’ll want to use setups and teardowns in your unittests to avoid doing that, e.g.:

def setUp(self):
    # retain a pointer to the actual real method:
    self.real_get_data = datasource.Structure.get_data
    # monkey patch it:
    datasource.Structure.get_data = get_data

def tearDown(self):
    # give the real method back to the Structure object:
    datasource.Structure.get_data = self.real_get_data

(While the above is fine, it would probably be a better idea to use the mock library to patch the code. mock‘s patch decorator would be less error prone than doing the above, which would require more lines of code and thus more opportunities to introduce errors. I have yet to review the code in mock but I imagine it uses monkey-patching in a similar way.)


回答 3

根据维基百科

在Python中,“Monkey补丁”一词仅指在运行时对类或模块的动态修改,其目的是为了修补现有的第三方代码,以作为无法按需使用的错误或功能的解决方法。

According to Wikipedia:

In Python, the term monkey patch only refers to dynamic modifications of a class or module at runtime, motivated by the intent to patch existing third-party code as a workaround to a bug or feature which does not act as you desire.


回答 4

首先:Monkey修补是一个邪恶的hack(我认为)。

它通常用于用自定义实现替换模块或类级别的方法。

最常见的用例是在无法替换原始代码时为模块或类中的错误添加解决方法。在这种情况下,您可以通过Monkey补丁替换“错误的”代码,并将其替换为您自己的模块/包中的实现。

First: monkey patching is an evil hack (in my opinion).

It is often used to replace a method on the module or class level with a custom implementation.

The most common usecase is adding a workaround for a bug in a module or class when you can’t replace the original code. In this case you replace the “wrong” code through monkey patching with an implementation inside your own module/package.


回答 5

Monkey补丁只能用动态语言完成,其中python是一个很好的例子。在运行时更改方法而不是更新对象定义是一个示例;类似地,在运行时添加属性(无论方法还是变量)也被视为Monkey补丁。这些操作通常在使用您没有来源的模块时完成,这样就无法轻易更改对象定义。

这被认为是不好的,因为这意味着对象的定义不能完全或准确地描述其实际行为。

Monkey patching can only be done in dynamic languages, of which python is a good example. Changing a method at runtime instead of updating the object definition is one example;similarly, adding attributes (whether methods or variables) at runtime is considered monkey patching. These are often done when working with modules you don’t have the source for, such that the object definitions can’t be easily changed.

This is considered bad because it means that an object’s definition does not completely or accurately describe how it actually behaves.


回答 6

Monkey修补程序是在运行时重新打开类中的现有类或方法并更改其行为,应谨慎使用它们,或者仅在确实需要时使用它。

由于Python是一种动态编程语言,因此类是可变的,因此您可以重新打开它们并进行修改甚至替换。

Monkey patching is reopening the existing classes or methods in class at runtime and changing the behavior, which should be used cautiously, or you should use it only when you really need to.

As Python is a dynamic programming language, Classes are mutable so you can reopen them and modify or even replace them.


回答 7

什么是Monkey修补?Monkey修补程序是一种用于在运行时动态更新一段代码的行为的技术。

为什么要使用Monkey补丁?它允许我们在运行时修改或扩展库,模块,类或方法的行为,而无需实际修改源代码

结论Monkey修补是一种很酷的技术,现在我们已经学习了如何在Python中进行修补。但是,正如我们所讨论的,它有其自身的缺点,应谨慎使用。

有关更多信息,请参考[1]:https : //medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505

What is monkey patching? Monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time.

Why use monkey patching? It allows us to modify or extend the behavior of libraries, modules, classes or methods at runtime without actually modifying the source code

Conclusion Monkey patching is a cool technique and now we have learned how to do that in Python. However, as we discussed, it has its own drawbacks and should be used carefully.

For more info Please refer [1]: https://medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505


如何检查Django版本

问题:如何检查Django版本

我必须为我们的应用程序使用PythonDjango。所以我有两个版本的Python,分别是2.6和2.7。现在,我已经安装了Django。我可以运行示例应用程序以测试Django成功。但是,如何确定Django使用2.6还是2.7版本以及Django使用什么版本的模块?

I have to use Python and Django for our application. So I have two versions of Python, 2.6 and 2.7. Now I have installed Django. I could run the sample application for testing Django succesfuly. But how do I make sure whether Django uses the 2.6 or 2.7 version and what version of modules Django uses?


回答 0

Django 1.5支持Python 2.6.5和更高版本。

如果您使用的是Linux,并且要检查使用的Python版本,请从命令行运行python -V

如果要检查Django版本,请打开Python控制台并输入

>>> import django
>>> django.VERSION
(2, 0, 0, 'final', 0)

Django 1.5 supports Python 2.6.5 and later.

If you’re under Linux and want to check the Python version you’re using, run python -V from the command line.

If you want to check the Django version, open a Python console and type

>>> import django
>>> django.VERSION
(2, 0, 0, 'final', 0)

回答 1

基本上与bcoughlan的答案相同,但是在这里,它作为可执行命令:

$ python -c "import django; print(django.get_version())"
2.0

Basically the same as bcoughlan’s answer, but here it is as an executable command:

$ python -c "import django; print(django.get_version())"
2.0

回答 2

如果您已安装该应用程序:

$ django-admin.py version
2.0

If you have installed the application:

$ django-admin.py version
2.0

回答 3

转到Django项目主目录并执行以下操作:

./manage.py --version

Go to your Django project home directory and do:

./manage.py --version

回答 4

>>> import django
>>> print(django.get_version())
1.6.1

我正在使用IDLE(Python GUI)。

>>> import django
>>> print(django.get_version())
1.6.1

I am using the IDLE (Python GUI).


回答 5

如果您有点子,也可以

点冻结
它将显示您的所有组件版本,包括Django。

您可以通过grep传递它,以仅获取Django版本。那是,

josh@villaroyale:~/code/djangosite$ pip freeze | grep Django
Django==1.4.3

If you have pip, you can also do a

pip freeze
and it will show your all component version including Django .

You can pipe it through grep to get just the Django version. That is,

josh@villaroyale:~/code/djangosite$ pip freeze | grep Django
Django==1.4.3

回答 6

对于Python

import sys
sys.version

对于Django(如其他人在此处所述):

import django
django.get_version()

仅检查版本的潜在问题是版本会升级,因此代码可能会过时。您要确保’1.7′<‘1.7.1′<‘1.7.5′<‘1.7.10’。普通的字符串比较将在最后一次比较中失败:

>>> '1.7.5' < '1.7.10'
False

解决方案是使用distutils中的StrictVersion

>>> from distutils.version import StrictVersion
>>> StrictVersion('1.7.5') < StrictVersion('1.7.10')
True

For Python:

import sys
sys.version

For Django (as mentioned by others here):

import django
django.get_version()

The potential problem with simply checking the version, is that versions get upgraded and so the code can go out of date. You want to make sure that ‘1.7’ < ‘1.7.1’ < ‘1.7.5’ < ‘1.7.10’. A normal string comparison would fail in the last comparison:

>>> '1.7.5' < '1.7.10'
False

The solution is to use StrictVersion from distutils.

>>> from distutils.version import StrictVersion
>>> StrictVersion('1.7.5') < StrictVersion('1.7.10')
True

回答 7

正如您所说的,您有两个版本的python,我假设它们位于不同的虚拟环境(例如venv)或conda 环境中

当您安装django时,可能仅在一种环境中。可能有两个不同版本的django,每个版本的python都有一个。

在Unix / Mac终端中,您可以如下检查python版本:

$ python --version

如果您想知道来源:

$ which python

并检查django的版本:

$ python -m django --version

As you say you have two versions of python, I assume they are in different virtual environments (e.g. venv) or perhaps conda environments.

When you installed django, it was likely in only one environment. It is possible that you have two different versions of django, one for each version of python.

In from a Unix/Mac terminal, you can check your python version as follows:

$ python --version

If you want to know the source:

$ which python

And to check the version of django:

$ python -m django --version

回答 8

有多种获取Django版本的方法。您可以根据需要使用以下给出的任何一种。

注意: 如果您在虚拟环境中工作,请加载python环境


终端命令

  1. python -m django --version
  2. django-admin --version 要么 django-admin.py version
  3. ./manage.py --version 要么 python manage.py --version
  4. pip freeze | grep Django
  5. python -c "import django; print(django.get_version())"
  6. python manage.py runserver --version

Django Shell命令

  1. import django django.get_version() 要么 django.VERSION
  2. from django.utils import version version.get_version() 要么 version.get_complete_version()
  3. import pkg_resources pkg_resources.get_distribution('django').version

(如果您有某种更正或想添加更多相关信息,请随意修改此答案。)

There are various ways to get the Django version. You can use any one of the following given below according to your requirements.

Note: If you are working in a virtual environment then please load your python environment


Terminal Commands

  1. python -m django --version
  2. django-admin --version or django-admin.py version
  3. ./manage.py --version or python manage.py --version
  4. pip freeze | grep Django
  5. python -c "import django; print(django.get_version())"
  6. python manage.py runserver --version

Django Shell Commands

  1. import django django.get_version() OR django.VERSION
  2. from django.utils import version version.get_version() OR version.get_complete_version()
  3. import pkg_resources pkg_resources.get_distribution('django').version

(Feel free to modify this answer, if you have some kind of correction or you want to add more related information.)


回答 9

要使用Python Shell进行检查,请执行以下操作。

>>>from django import get_version
>>> get_version()

如果您希望在Unix / Linux shell中使用一行来完成此操作,请执行

python -c 'import django; print(django.get_version())'

开发应用程序后,即可使用以下方法直接检查版本。

python manage.py runserver --version

For checking using a Python shell, do the following.

>>>from django import get_version
>>> get_version()

If you wish to do it in Unix/Linux shell with a single line, then do

python -c 'import django; print(django.get_version())'

Once you have developed an application, then you can check version directly using the following.

python manage.py runserver --version

回答 10

django-admin --version
python manage.py --version
pip freeze | grep django
django-admin --version
python manage.py --version
pip freeze | grep django

回答 11

Django将使用PYTHONPATH环境变量指定的Python版本。您可以echo $PYTHONPATH在外壳中使用以确定要使用的版本。

Django使用的模块版本将是PYTHONPATH指定的Python版本下安装的模块版本。

Django will use the version of Python specified by the PYTHONPATH environment variable. You can use echo $PYTHONPATH in a shell to determine which version will be used.

The module versions used by Django will be the module versions installed under the version of Python specified by PYTHONPATH.


回答 12

pip list在LINUX TERMINAL上运行,并在列表中找到Django及其版本

pip freeze在Windows上的cmd上 运行

run pip list on LINUX TERMINAL and find Django and its version on list

run pip freeze on cmd on Windows


回答 13

您也可以不用Python就可以做到。只需在Django目录中输入以下内容即可:

cat __init__.py | grep VERSION

你会得到类似的东西:

VERSION = (1, 5, 5, 'final', 0)

You can do it without Python too. Just type this in your Django directory:

cat __init__.py | grep VERSION

And you will get something like:

VERSION = (1, 5, 5, 'final', 0)

回答 14

Django中有一个未记录的utils版本模块

https://github.com/django/django/blob/master/django/utils/version.py

有了它,您可以将正常版本作为字符串或详细版本元组获取:

>>> from django.utils import version
>>> version.get_version()
... 1.9
>>> version.get_complete_version()
... (1, 9, 0, 'final', 0)

There is an undocumented utils versions module in django

https://github.com/django/django/blob/master/django/utils/version.py

With that you can get the normal version as string or a detailed version tuple:

>>> from django.utils import version
>>> version.get_version()
... 1.9
>>> version.get_complete_version()
... (1, 9, 0, 'final', 0)

回答 15

Django版本或任何其他软件包版本

打开终端或命令提示符

类型

pip show django

要么

pip3 show django

您可以找到任何软件包版本…
示例

pip show tensorflow

pip show numpy 

等等….

Django version or any other package version

open the terminal or command prompt

type

pip show django

or

pip3 show django

you can find any package version…
example

pip show tensorflow

pip show numpy 

etc….


回答 16

输入您的CMD或终端:

python -m django --version

Type in your CMD or terminal:

python -m django --version

回答 17

我认为最Python化的方式是:

>>> import pkg_resources; 
>>> pkg_resources.get_distribution('django').version
'1.8.4'

这直接与setup.py相关联: https //github.com/django/django/blob/master/setup.py#L37

这绝对是获得ANY软件包版本号的最佳方法!

也有 distutils

>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion("2.3.1") < LooseVersion("10.1.2")
True
>>> StrictVersion("2.3.1") < StrictVersion("10.1.2")
True
>>> StrictVersion("2.3.1") > StrictVersion("10.1.2")
False

至于python版本,我同意@jamesdradbury

>>> import sys
>>> sys.version
'3.4.3 (default, Jul 13 2015, 12:18:23) \n[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)]'

捆绑在一起:

>>> StrictVersion((sys.version.split(' ')[0])) > StrictVersion('2.6')
True

I thought the most pythonic way was:

>>> import pkg_resources; 
>>> pkg_resources.get_distribution('django').version
'1.8.4'

This ties directly into setup.py: https://github.com/django/django/blob/master/setup.py#L37

Its definitely the best way to get the version number of ANY package!

Also there is distutils

>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion("2.3.1") < LooseVersion("10.1.2")
True
>>> StrictVersion("2.3.1") < StrictVersion("10.1.2")
True
>>> StrictVersion("2.3.1") > StrictVersion("10.1.2")
False

As for the python version, i agree with @jamesdradbury

>>> import sys
>>> sys.version
'3.4.3 (default, Jul 13 2015, 12:18:23) \n[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)]'

Tying it all together:

>>> StrictVersion((sys.version.split(' ')[0])) > StrictVersion('2.6')
True

回答 18

如果要进行Django版本比较,可以使用django-nine(pip install django-nine)。例如,如果您的环境中安装的Django版本是1.7.4,则以下内容将适用。

from nine import versions

versions.DJANGO_1_7 # True
versions.DJANGO_LTE_1_7 # True
versions.DJANGO_GTE_1_7 # True
versions.DJANGO_GTE_1_8 # False
versions.DJANGO_GTE_1_4 # True
versions.DJANGO_LTE_1_6 # False

If you want to make Django version comparison, you could use django-nine (pip install django-nine). For example, if Django version installed in your environment is 1.7.4, then the following would be true.

from nine import versions

versions.DJANGO_1_7 # True
versions.DJANGO_LTE_1_7 # True
versions.DJANGO_GTE_1_7 # True
versions.DJANGO_GTE_1_8 # False
versions.DJANGO_GTE_1_4 # True
versions.DJANGO_LTE_1_6 # False

回答 19

在Python Shell中输入以下命令

import django
django.get_version()

Type the following command in Python shell

import django
django.get_version()

回答 20

Django 1.0之后,您可以执行此操作

$ django-admin --version
1.11.10

After django 1.0 you can just do this

$ django-admin --version
1.11.10

回答 21

您可以通过在shell提示符中运行以下命令来获取Django版本

python -m django –version

如果安装了Django,则应该看到该版本,否则将收到错误消息,提示“没有名为django的模块”。

You can get django version by running the following command in a shell prompt

python -m django –version

If Django is installed, you should see the version otherwise you’ll get an error telling “No module named django”.


回答 22

您可以导入django,然后按如下所示键入print语句,以了解django的版本,即安装在系统上的版本:

>>> import django
>>> print(django.get_version())
2.1

you can import django and then type print statement as given below to know the version of django i.e. installed on your system:

>>> import django
>>> print(django.get_version())
2.1

回答 23

Django版本支持的Python版本

Django version     Python versions
1.0                2.3, 2.4, 2.5, 2.6
1.1                2.3, 2.4, 2.5, 2.6
1.2                2.4, 2.5, 2.6, 2.7
1.3                2.4, 2.5, 2.6, 2.7
1.4                2.5, 2.6, 2.7
1.5                2.6.5, 2.7 and 3.2.3, 3.3 (experimental)
1.6                2.6.5, 2.7 and 3.2.3, 3.3
1.11               2.7, 3.4, 3.5, 3.6, 3.7 (added in 1.11.17)
2.0                3.4, 3.5, 3.6, 3.7
2.1, 2.2           3.5, 3.6, 3.7

要验证Python是否可以看到Django,请在您的shell中键入python。然后在Python提示符下,尝试导入Django:

>>> import django
>>> print(django.get_version())
2.1
>>> django.VERSION
(2, 1, 4, 'final', 0)

Python version supported by Django version

Django version     Python versions
1.0                2.3, 2.4, 2.5, 2.6
1.1                2.3, 2.4, 2.5, 2.6
1.2                2.4, 2.5, 2.6, 2.7
1.3                2.4, 2.5, 2.6, 2.7
1.4                2.5, 2.6, 2.7
1.5                2.6.5, 2.7 and 3.2.3, 3.3 (experimental)
1.6                2.6.5, 2.7 and 3.2.3, 3.3
1.11               2.7, 3.4, 3.5, 3.6, 3.7 (added in 1.11.17)
2.0                3.4, 3.5, 3.6, 3.7
2.1, 2.2           3.5, 3.6, 3.7

To verify that Django can be seen by Python, type python from your shell. Then at the Python prompt, try to import Django:

>>> import django
>>> print(django.get_version())
2.1
>>> django.VERSION
(2, 1, 4, 'final', 0)

回答 24

只需键入python -m django --version 或键入pip freeze即可查看已安装模块的所有版本,包括Django。

Simply type python -m django --version or type pip freeze to see all the versions of installed modules including Django.


使用Python的stdlib查找本地IP地址

问题:使用Python的stdlib查找本地IP地址

如何仅使用标准库在Python平台中独立查找本地IP地址(即192.168.xx或10.0.xx)?

How can I find local IP addresses (i.e. 192.168.x.x or 10.0.x.x) in Python platform independently and using only the standard library?


回答 0

import socket
socket.gethostbyname(socket.gethostname())

这将永远无法正常工作(返回127.0.0.1主机/etc/hosts名为as的机器127.0.0.1),将是gimel显示的一种称呼,socket.getfqdn()而是使用。当然,您的计算机需要一个可解析的主机名。

import socket
socket.gethostbyname(socket.gethostname())

This won’t work always (returns 127.0.0.1 on machines having the hostname in /etc/hosts as 127.0.0.1), a paliative would be what gimel shows, use socket.getfqdn() instead. Of course your machine needs a resolvable hostname.


回答 1

我刚刚发现了它,但是似乎有点破烂,但是他们说在* nix上尝试过,而我在Windows上做了,它起作用了。

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()

这假设您可以访问互联网,并且没有本地代理。

I just found this but it seems a bit hackish, however they say tried it on *nix and I did on windows and it worked.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()

This assumes you have an internet access, and that there is no local proxy.


回答 2

此方法在本地设备(具有默认路由的设备)上返回“主要” IP

  • 完全不需要可路由的网络访问或任何连接。
  • 即使所有接口都从网络上拔下,它也可以工作。
  • 不需要甚至尝试到达其他任何地方
  • 与NAT,公共IP,专用IP,外部IP和内部IP一起使用
  • 没有外部依赖项的纯Python 2(或3)。
  • 适用于Linux,Windows和OSX。

Python 3或2:

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

这将返回一个作为主IP的IP(具有默认路由的IP)。如果您需要将所有IP附加到所有接口(包括localhost等),请参阅此答案

如果您像家庭中的wifi盒一样位于NAT防火墙的后面,则不会显示您的公共NAT IP,而是显示您本地IP上的私有IP,该IP具有到您本地WIFI路由器的默认路由;获取您的wifi路由器的外部IP要么需要在THAT盒子上运行它,要么连接到可能反映IP的外部服务,例如whatismyip.com/whatismyipaddress.com …,但这与原始问题完全不同。:)

This method returns the “primary” IP on the local box (the one with a default route).

  • Does NOT need routable net access or any connection at all.
  • Works even if all interfaces are unplugged from the network.
  • Does NOT need or even try to get anywhere else.
  • Works with NAT, public, private, external, and internal IP’s
  • Pure Python 2 (or 3) with no external dependencies.
  • Works on Linux, Windows, and OSX.

Python 3 or 2:

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

This returns a single IP which is the primary (the one with a default route). If you need instead all IP’s attached to all interfaces (including localhost, etc), see this answer.

If you are behind a NAT firewall like your wifi box at home, then this will not show your public NAT IP, but instead your private IP on the local network which has a default route to your local WIFI router; getting your wifi router’s external IP would either require running this on THAT box, or connecting to an external service such as whatismyip.com/whatismyipaddress.com that could reflect back the IP… but that is completely different from the original question. :)


回答 3

作为别名myip,应该在任何地方都有效:

alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
  • 可与Python 2.x,Python 3.x,现代和旧版Linux发行版,OSX / macOS和Windows一起正常使用,以查找当前的IPv4地址。
  • 对于具有多个IP地址,IPv6,没有配置的IP地址或没有Internet访问的计算机,不会返回正确的结果。

与上述相同,但只有Python代码:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
  • 如果未配置IP地址,这将引发异常。

在没有Internet连接的情况下也可以在LAN上运行的版本:

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(感谢@ccpizza


背景

使用socket.gethostbyname(socket.gethostname())在这里不起作用,因为我所在的其中一台计算机上有/etc/hosts重复的条目并对其自身进行了引用。socket.gethostbyname()仅返回中的最后一项/etc/hosts

这是我最初的尝试,清除了所有以以下地址开头的地址"127."

import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])

这适用于Linux 2和Windows上的Python 2和3,但不适用于多个网络设备或IPv6。但是,它停止了在最近的Linux发行版上的工作,因此我尝试了这种替代技术。它尝试通过8.8.8.8以下端口连接到Google DNS服务器53

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

然后,我将上述两种技术组合成一种在任何地方都可以使用的单行myip代码,并在此答案的顶部创建了别名和Python代码段。

随着IPv6的日益普及以及对于具有多个网络接口的服务器,使用第三方Python模块查找IP地址可能比此处列出的任何方法都更可靠和可靠。

As an alias called myip, that should work everywhere:

alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
  • Works correctly with Python 2.x, Python 3.x, modern and old Linux distros, OSX/macOS and Windows for finding the current IPv4 address.
  • Will not return the correct result for machines with multiple IP addresses, IPv6, no configured IP address or no internet access.

Same as above, but only the Python code:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
  • This will throw an exception if no IP address is configured.

Version that will also work on LANs without an internet connection:

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(thanks @ccpizza)


Background:

Using socket.gethostbyname(socket.gethostname()) did not work here, because one of the computers I was on had an /etc/hosts with duplicate entries and references to itself. socket.gethostbyname() only returns the last entry in /etc/hosts.

This was my initial attempt, which weeds out all addresses starting with "127.":

import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])

This works with Python 2 and 3, on Linux and Windows, but does not deal with several network devices or IPv6. However, it stopped working on recent Linux distros, so I tried this alternative technique instead. It tries to connect to the Google DNS server at 8.8.8.8 at port 53:

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

Then I combined the two above techniques into a one-liner that should work everywhere, and created the myip alias and Python snippet at the top of this answer.

With the increasing popularity of IPv6, and for servers with multiple network interfaces, using a third-party Python module for finding the IP address is probably both more robust and reliable than any of the methods listed here.


回答 4

您可以使用netifaces模块。只需输入:

pip install netifaces

在命令外壳中,它将在默认的Python安装中自行安装。

然后,您可以像这样使用它:

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
    print '%s: %s' % (ifaceName, ', '.join(addresses))

在我的计算机上打印:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}:192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583} :: 10.5.9.207

该模块的作者声称它应该可以在Windows,UNIX和Mac OS X上运行。

You can use the netifaces module. Just type:

pip install netifaces

in your command shell and it will install itself on default Python installation.

Then you can use it like this:

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
    print '%s: %s' % (ifaceName, ', '.join(addresses))

On my computer it printed:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207

Author of this module claims it should work on Windows, UNIX and Mac OS X.


回答 5

套接字API方法

参见https://stackoverflow.com/a/28950776/711085

缺点:

  • 不是跨平台的。
  • 需要更多后备代码,与互联网上特定地址的存在相关
  • 如果您在使用NAT,这也将不起作用
  • 可能会创建UDP连接,而不依赖于(通常是ISP的)DNS可用性(请参阅其他答案,以获取使用8.8.8.8的想法:Google的(偶然也是DNS)服务器)
  • 确保将目标地址设置为UNREACHABLE,例如指定不使用的数字IP地址。请勿使用诸如fakesubdomain.google.com或somefakewebsite.com之类的域;您仍然会向该方发送垃圾邮件(无论现在还是将来),并在此过程中向您自己的网络邮箱发送垃圾邮件。

反射法

(请注意,这不能回答OP的本地IP地址问题,例如192.168 …;它为您提供了公共IP地址,根据使用情况,可能更需要此IP地址。)

您可以查询某些网站,例如whatismyip.com(但使用API​​),例如:

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

或者如果使用python2:

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

优点:

  • 这种方法的一个好处是它是跨平台的
  • 它可以从丑陋的NAT(例如您的家庭路由器)后面运行。

缺点(和解决方法):

  • 要求此网站正常运行,格式不得更改(几乎肯定不会更改),并且您的DNS服务器正常工作。如果发生故障,还可以通过查询其他第三方IP地址反射器来缓解此问题。
  • 如果您不查询多个反射器(以防止受损的反射器告诉您您的地址不是它的东西),或者如果您不使用HTTPS(以防止中间人的攻击),则可能是攻击向量成为服务器)

编辑:尽管起初我以为这些方法确实很糟糕(除非您使用了许多后备功能,否则从现在起很多年后代码都将是无关紧要的),但确实提出了“什么是互联网?”的问题。一台计算机可能具有指向许多不同网络的许多接口。有关主题的更详尽说明,请使用googlegateways and routes。计算机可能能够通过内部网关访问内部网络,或者通过例如路由器上的网关访问万维网(通常是这种情况)。OP询问的本地IP地址仅在单个链路层上定义明确,因此您必须指定(“我们正在谈论的是网卡还是以太网电缆?”) 。提出的这个问题可能有多个非唯一答案。但是,万维网上的全局IP地址可能是定义明确的(在没有大量网络碎片的情况下):可能是通过可以访问TLD的网关返回的路径。

Socket API method

see https://stackoverflow.com/a/28950776/711085

Downsides:

  • Not cross-platform.
  • Requires more fallback code, tied to existence of particular addresses on the internet
  • This will also not work if you’re behind a NAT
  • Probably creates a UDP connection, not independent of (usually ISP’s) DNS availability (see other answers for ideas like using 8.8.8.8: Google’s (coincidentally also DNS) server)
  • Make sure you make the destination address UNREACHABLE, like a numeric IP address that is spec-guaranteed to be unused. Do NOT use some domain like fakesubdomain.google.com or somefakewebsite.com; you’ll still be spamming that party (now or in the future), and spamming your own network boxes as well in the process.

Reflector method

(Do note that this does not answer the OP’s question of the local IP address, e.g. 192.168…; it gives you your public IP address, which might be more desirable depending on use case.)

You can query some site like whatismyip.com (but with an API), such as:

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

or if using python2:

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

Advantages:

  • One upside of this method is it’s cross-platform
  • It works from behind ugly NATs (e.g. your home router).

Disadvantages (and workarounds):

  • Requires this website to be up, the format to not change (almost certainly won’t), and your DNS servers to be working. One can mitigate this issue by also querying other third-party IP address reflectors in case of failure.
  • Possible attack vector if you don’t query multiple reflectors (to prevent a compromised reflector from telling you that your address is something it’s not), or if you don’t use HTTPS (to prevent a man-in-the-middle attack pretending to be the server)

edit: Though initially I thought these methods were really bad (unless you use many fallbacks, the code may be irrelevant many years from now), it does pose the question “what is the internet?”. A computer may have many interfaces pointing to many different networks. For a more thorough description of the topic, google for gateways and routes. A computer may be able to access an internal network via an internal gateway, or access the world-wide web via a gateway on for example a router (usually the case). The local IP address that the OP asks about is only well-defined with respect to a single link layer, so you have to specify that (“is it the network card, or the ethernet cable, which we’re talking about?”). There may be multiple non-unique answers to this question as posed. However the global IP address on the world-wide web is probably well-defined (in the absence of massive network fragmentation): probably the return path via the gateway which can access the TLDs.


回答 6

如果计算机具有通往Internet的路由,即使/ etc / hosts设置不正确,它始终可以获取首选的本地ip地址。

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
local_ip_address = s.getsockname()[0]

If the computer has a route to the Internet, this will always work to get the preferred local ip address, even if /etc/hosts is not set correctly.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
local_ip_address = s.getsockname()[0]

回答 7

在Linux上:

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 

On Linux:

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 

回答 8

即时通讯使用以下模块:

#!/usr/bin/python
# module for getting the lan ip address of the computer

import os
import socket

if os.name != "nt":
    import fcntl
    import struct
    def get_interface_ip(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
                s.fileno(),
                0x8915,  # SIOCGIFADDR
                struct.pack('256s', bytes(ifname[:15], 'utf-8'))
                # Python 2.7: remove the second argument for the bytes call
            )[20:24])

def get_lan_ip():
    ip = socket.gethostbyname(socket.gethostname())
    if ip.startswith("127.") and os.name != "nt":
        interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
        for ifname in interfaces:
            try:
                ip = get_interface_ip(ifname)
                break;
            except IOError:
                pass
    return ip

经过Windows和Linux(并不需要其他模块)测试,旨在用于基于单个IPv4的LAN中的系统。

接口名称的固定列表不适用于最新的Linux版本,这些版本采用了Alexander指出的有关可预测接口名称的systemd v197更改。在这种情况下,您需要使用系统上的接口名称手动替换列表,或使用其他解决方案(如netifaces)

im using following module:

#!/usr/bin/python
# module for getting the lan ip address of the computer

import os
import socket

if os.name != "nt":
    import fcntl
    import struct
    def get_interface_ip(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
                s.fileno(),
                0x8915,  # SIOCGIFADDR
                struct.pack('256s', bytes(ifname[:15], 'utf-8'))
                # Python 2.7: remove the second argument for the bytes call
            )[20:24])

def get_lan_ip():
    ip = socket.gethostbyname(socket.gethostname())
    if ip.startswith("127.") and os.name != "nt":
        interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
        for ifname in interfaces:
            try:
                ip = get_interface_ip(ifname)
                break;
            except IOError:
                pass
    return ip

Tested with windows and linux (and doesnt require additional modules for those) intended for use on systems which are in a single IPv4 based LAN.

The fixed list of interface names does not work for recent linux versions, which have adopted the systemd v197 change regarding predictable interface names as pointed out by Alexander. In such cases, you need to manually replace the list with the interface names on your system, or use another solution like netifaces.


回答 9

我在我的ubuntu机器上使用它:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

这行不通。

I use this on my ubuntu machines:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

This doesn’t work.


回答 10

如果您不想使用外部软件包,也不想依赖外部Internet服务器,则可能会有所帮助。这是我在Google代码搜索中找到并修改为返回所需信息的代码示例:

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break

用法:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

由于它依赖windll,因此仅在Windows上有效。

If you don’t want to use external packages and don’t want to rely on outside Internet servers, this might help. It’s a code sample that I found on Google Code Search and modified to return required information:

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break

Usage:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

As it relies on windll, this will work only on Windows.


回答 11

在Debian(经过测试)上,我怀疑大多数Linux都可以。

import commands

RetMyIP = commands.getoutput("hostname -I")

在MS Windows上(已测试)

import socket

socket.gethostbyname(socket.gethostname())

On Debian (tested) and I suspect most Linux’s..

import commands

RetMyIP = commands.getoutput("hostname -I")

On MS Windows (tested)

import socket

socket.gethostbyname(socket.gethostname())

回答 12

我不认为该版本已经发布。我在Ubuntu 12.04上使用python 2.7进行了测试。

在以下位置找到了此解决方案:http : //code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

结果示例:

>>> get_ip_address('eth0')
'38.113.228.130'

A version I do not believe that has been posted yet. I tested with python 2.7 on Ubuntu 12.04.

Found this solution at : http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

Example Result:

>>> get_ip_address('eth0')
'38.113.228.130'

回答 13

Ninjagecko的答案有所不同。这应该在允许UDP广播并且不需要访问LAN或Internet上的地址的任何LAN上都有效。

import socket
def getNetworkIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

print (getNetworkIp())

Variation on ninjagecko’s answer. This should work on any LAN that allows UDP broadcast and doesn’t require access to an address on the LAN or internet.

import socket
def getNetworkIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

print (getNetworkIp())

回答 14

恐怕除了连接到另一台计算机并将其发送给您的IP地址之外,没有其他任何独立于平台的良好方法。例如: findmyipaddress。请注意,除非您需要的IP地址位于NAT后面,否则这将无法工作,除非要连接的计算机也位于NAT后面。

这是在Linux中工作的一种解决方案: 获取与网络接口关联的IP地址

I’m afraid there aren’t any good platform independent ways to do this other than connecting to another computer and having it send you your IP address. For example: findmyipaddress. Note that this won’t work if you need an IP address that’s behind NAT unless the computer you’re connecting to is behind NAT as well.

Here’s one solution that works in Linux: get the IP address associated with a network interface.


回答 15

通过命令行实用程序产生“干净”输出的一种简单方法:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips

它将显示系统上的所有IPv4地址。

One simple way to produce “clean” output via command line utils:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips

It will show all IPv4 addresses on the system.


回答 16

仅供参考,我可以验证该方法:

import socket
addr = socket.gethostbyname(socket.gethostname())

在OS X(10.6,10.5),Windows XP和管理良好的RHEL部门服务器上均可使用。它不能在非常小的CentOS VM上工作,而我只是对其进行一些内核黑客攻击。因此,对于该实例,您只需检查127.0.0.1地址,然后执行以下操作:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

然后从输出中解析IP地址。应当注意,默认情况下ifconfig不在普通用户的PATH中,这就是为什么我在命令中提供完整路径的原因。我希望这有帮助。

FYI I can verify that the method:

import socket
addr = socket.gethostbyname(socket.gethostname())

Works in OS X (10.6,10.5), Windows XP, and on a well administered RHEL department server. It did not work on a very minimal CentOS VM that I just do some kernel hacking on. So for that instance you can just check for a 127.0.0.1 address and in that case do the following:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

And then parse the ip address from the output. It should be noted that ifconfig is not in a normal user’s PATH by default and that is why I give the full path in the command. I hope this helps.


回答 17

这是UnkwnTech回答的一种变体,它提供了一个get_local_addr()函数,该函数返回主机的主要LAN ip地址。我发布它是因为这增加了许多东西:ipv6支持,错误处理,忽略localhost / linklocal地址,并使用TESTNET地址(rfc5737)连接。

# imports
import errno
import socket
import logging

# localhost prefixes
_local_networks = ("127.", "0:0:0:0:0:0:0:1")

# ignore these prefixes -- localhost, unspecified, and link-local
_ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:")

def detect_family(addr):
    if "." in addr:
        assert ":" not in addr
        return socket.AF_INET
    elif ":" in addr:
        return socket.AF_INET6
    else:
        raise ValueError("invalid ipv4/6 address: %r" % addr)

def expand_addr(addr):
    """convert address into canonical expanded form --
    no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups.
    """
    family = detect_family(addr)
    addr = socket.inet_ntop(family, socket.inet_pton(family, addr))
    if "::" in addr:
        count = 8-addr.count(":")
        addr = addr.replace("::", (":0" * count) + ":")
        if addr.startswith(":"):
            addr = "0" + addr
    return addr

def _get_local_addr(family, remote):
    try:
        s = socket.socket(family, socket.SOCK_DGRAM)
        try:
            s.connect((remote, 9))
            return s.getsockname()[0]
        finally:
            s.close()
    except socket.error:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        return None

def get_local_addr(remote=None, ipv6=True):
    """get LAN address of host

    :param remote:
        return  LAN address that host would use to access that specific remote address.
        by default, returns address it would use to access the public internet.

    :param ipv6:
        by default, attempts to find an ipv6 address first.
        if set to False, only checks ipv4.

    :returns:
        primary LAN address for host, or ``None`` if couldn't be determined.
    """
    if remote:
        family = detect_family(remote)
        local = _get_local_addr(family, remote)
        if not local:
            return None
        if family == socket.AF_INET6:
            # expand zero groups so the startswith() test works.
            local = expand_addr(local)
        if local.startswith(_local_networks):
            # border case where remote addr belongs to host
            return local
    else:
        # NOTE: the two addresses used here are TESTNET addresses,
        #       which should never exist in the real world.
        if ipv6:
            local = _get_local_addr(socket.AF_INET6, "2001:db8::1234")
            # expand zero groups so the startswith() test works.
            if local:
                local = expand_addr(local)
        else:
            local = None
        if not local:
            local = _get_local_addr(socket.AF_INET, "192.0.2.123")
            if not local:
                return None
    if local.startswith(_ignored_networks):
        return None
    return local

This is a variant of UnkwnTech’s answer — it provides a get_local_addr() function, which returns the primary LAN ip address of the host. I’m posting it because this adds a number of things: ipv6 support, error handling, ignoring localhost/linklocal addrs, and uses a TESTNET addr (rfc5737) to connect to.

# imports
import errno
import socket
import logging

# localhost prefixes
_local_networks = ("127.", "0:0:0:0:0:0:0:1")

# ignore these prefixes -- localhost, unspecified, and link-local
_ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:")

def detect_family(addr):
    if "." in addr:
        assert ":" not in addr
        return socket.AF_INET
    elif ":" in addr:
        return socket.AF_INET6
    else:
        raise ValueError("invalid ipv4/6 address: %r" % addr)

def expand_addr(addr):
    """convert address into canonical expanded form --
    no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups.
    """
    family = detect_family(addr)
    addr = socket.inet_ntop(family, socket.inet_pton(family, addr))
    if "::" in addr:
        count = 8-addr.count(":")
        addr = addr.replace("::", (":0" * count) + ":")
        if addr.startswith(":"):
            addr = "0" + addr
    return addr

def _get_local_addr(family, remote):
    try:
        s = socket.socket(family, socket.SOCK_DGRAM)
        try:
            s.connect((remote, 9))
            return s.getsockname()[0]
        finally:
            s.close()
    except socket.error:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        return None

def get_local_addr(remote=None, ipv6=True):
    """get LAN address of host

    :param remote:
        return  LAN address that host would use to access that specific remote address.
        by default, returns address it would use to access the public internet.

    :param ipv6:
        by default, attempts to find an ipv6 address first.
        if set to False, only checks ipv4.

    :returns:
        primary LAN address for host, or ``None`` if couldn't be determined.
    """
    if remote:
        family = detect_family(remote)
        local = _get_local_addr(family, remote)
        if not local:
            return None
        if family == socket.AF_INET6:
            # expand zero groups so the startswith() test works.
            local = expand_addr(local)
        if local.startswith(_local_networks):
            # border case where remote addr belongs to host
            return local
    else:
        # NOTE: the two addresses used here are TESTNET addresses,
        #       which should never exist in the real world.
        if ipv6:
            local = _get_local_addr(socket.AF_INET6, "2001:db8::1234")
            # expand zero groups so the startswith() test works.
            if local:
                local = expand_addr(local)
        else:
            local = None
        if not local:
            local = _get_local_addr(socket.AF_INET, "192.0.2.123")
            if not local:
                return None
    if local.startswith(_ignored_networks):
        return None
    return local

回答 18

import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

回答 19

这将适用于大多数linux系统:

import socket, subprocess, re
def get_ipv4_address():
    """
    Returns IP address(es) of current machine.
    :return:
    """
    p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
    ifc_resp = p.communicate()
    patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    resp = patt.findall(ifc_resp[0])
    print resp

get_ipv4_address()

This will work on most linux boxes:

import socket, subprocess, re
def get_ipv4_address():
    """
    Returns IP address(es) of current machine.
    :return:
    """
    p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
    ifc_resp = p.communicate()
    patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    resp = patt.findall(ifc_resp[0])
    print resp

get_ipv4_address()

回答 20

这个答案是我个人为解决获得LAN IP问题而进行的个人尝试,因为它socket.gethostbyname(socket.gethostname())也返回了127.0.0.1。此方法不需要Internet,仅需要LAN连接即可。代码适用于Python 3.x,但可以轻松转换为2.x。使用UDP广播:

import select
import socket
import threading
from queue import Queue, Empty

def get_local_ip():
        def udp_listening_server():
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.bind(('<broadcast>', 8888))
            s.setblocking(0)
            while True:
                result = select.select([s],[],[])
                msg, address = result[0][0].recvfrom(1024)
                msg = str(msg, 'UTF-8')
                if msg == 'What is my LAN IP address?':
                    break
            queue.put(address)

        queue = Queue()
        thread = threading.Thread(target=udp_listening_server)
        thread.queue = queue
        thread.start()
        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        waiting = True
        while waiting:
            s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888))
            try:
                address = queue.get(False)
            except Empty:
                pass
            else:
                waiting = False
        return address[0]

if __name__ == '__main__':
    print(get_local_ip())

This answer is my personal attempt to solve the problem of getting the LAN IP, since socket.gethostbyname(socket.gethostname()) also returned 127.0.0.1. This method does not require Internet just a LAN connection. Code is for Python 3.x but could easily be converted for 2.x. Using UDP Broadcast:

import select
import socket
import threading
from queue import Queue, Empty

def get_local_ip():
        def udp_listening_server():
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.bind(('<broadcast>', 8888))
            s.setblocking(0)
            while True:
                result = select.select([s],[],[])
                msg, address = result[0][0].recvfrom(1024)
                msg = str(msg, 'UTF-8')
                if msg == 'What is my LAN IP address?':
                    break
            queue.put(address)

        queue = Queue()
        thread = threading.Thread(target=udp_listening_server)
        thread.queue = queue
        thread.start()
        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        waiting = True
        while waiting:
            s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888))
            try:
                address = queue.get(False)
            except Empty:
                pass
            else:
                waiting = False
        return address[0]

if __name__ == '__main__':
    print(get_local_ip())

回答 21

127.0.1.1 您的真实IP地址。一般来说,计算机可以具有任意数量的IP地址。您可以为专用网络过滤它们-127.0.0.0/8、10.0.0.0/8、172.16.0.0/12和192.168.0.0/16。

但是,没有跨平台的方法来获取所有IP地址。在Linux上,您可以使用SIOCGIFCONFioctl。

127.0.1.1 is your real IP address. More generally speaking, a computer can have any number of IP addresses. You can filter them for private networks – 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.

However, there is no cross-platform way to get all IP addresses. On Linux, you can use the SIOCGIFCONF ioctl.


回答 22

使用IP命令并返回IPv4和IPv6地址的命令版本略有改进:

import commands,re,socket

#A generator that returns stripped lines of output from "ip address show"
iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n'))

#Turn that into a list of IPv4 and IPv6 address/mask strings
addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines))
#addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64']

#Get a list of IPv4 addresses as (IPstring,subnetsize) tuples
ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)]
#ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)]

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]

A slight refinement of the commands version that uses the IP command, and returns IPv4 and IPv6 addresses:

import commands,re,socket

#A generator that returns stripped lines of output from "ip address show"
iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n'))

#Turn that into a list of IPv4 and IPv6 address/mask strings
addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines))
#addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64']

#Get a list of IPv4 addresses as (IPstring,subnetsize) tuples
ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)]
#ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)]

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]

回答 23

好了,您可以在GNU / Linux上使用命令“ ip route”来知道您当前的IP地址。

这显示了路由器/调制解调器上运行的DHCP服务器为接口提供的IP。通常,“ 192.168.1.1/24”是本地网络的IP,其中“ 24”表示DHCP服务器在掩码范围内指定的可能IP地址范围。

这是一个示例:请注意,PyNotify只是为了使我的观点更清楚而已,根本不需要

#! /usr/bin/env python

import sys , pynotify

if sys.version_info[1] != 7:
   raise RuntimeError('Python 2.7 And Above Only')       

from subprocess import check_output # Available on Python 2.7+ | N/A 

IP = check_output(['ip', 'route'])
Split_Result = IP.split()

# print Split_Result[2] # Remove "#" to enable

pynotify.init("image")
notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
notify.show()    

这样做的好处是您无需指定网络接口。这在运行套接字服务器时非常有用

您可以使用easy_install甚至Pip安装PyNotify:

easy_install py-notify

要么

pip install py-notify

或在python脚本/解释器中

from pip import main

main(['install', 'py-notify'])

Well you can use the command “ip route” on GNU/Linux to know your current IP address.

This shows the IP given to the interface by the DHCP server running on the router/modem. Usually “192.168.1.1/24” is the IP for local network where “24” means the range of posible IP addresses given by the DHCP server within the mask range.

Here’s an example: Note that PyNotify is just an addition to get my point straight and is not required at all

#! /usr/bin/env python

import sys , pynotify

if sys.version_info[1] != 7:
   raise RuntimeError('Python 2.7 And Above Only')       

from subprocess import check_output # Available on Python 2.7+ | N/A 

IP = check_output(['ip', 'route'])
Split_Result = IP.split()

# print Split_Result[2] # Remove "#" to enable

pynotify.init("image")
notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
notify.show()    

The advantage of this is that you don’t need to specify the network interface. That’s pretty useful when running a socket server

You can install PyNotify using easy_install or even Pip:

easy_install py-notify

or

pip install py-notify

or within python script/interpreter

from pip import main

main(['install', 'py-notify'])

回答 24

如果您正在寻找与本地IP地址不同的IPV4地址127.0.0.1,这是一个整洁的python代码:

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]

也可以单行编写:

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]

即使您输入localhost/etc/hostname,代码仍会提供您的本地IP地址。

If you’re looking for an IPV4 address different from your localhost IP address 127.0.0.1, here is a neat piece of python codes:

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]

Which can also be written in a single line:

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]

Even if you put localhost in /etc/hostname, the code will still give your local IP address.


回答 25

对于Linux,可以只使用check_output了的hostname -I,像这样的系统命令:

from subprocess import check_output
check_output(['hostname', '-I'])

For linux, you can just use check_output of the hostname -I system command like so:

from subprocess import check_output
check_output(['hostname', '-I'])

回答 26

注意:这不是使用标准库,而是非常简单。

$ pip安装pif

from pif import get_public_ip
get_public_ip()

Note: This is not using the standard library, but quite simple.

$ pip install pif

from pif import get_public_ip
get_public_ip()

回答 27

netifaces可通过pip和easy_install获得。(我知道,它不在基础中,但是值得安装。)

netifaces的跨平台确实有些奇怪:

  • 不一定总是包含localhost / loop-back接口(Cygwin)。
  • 每个协议列出了地址(例如IPv4,IPv6),每个接口列出了协议。在某些系统(Linux)上,每个协议接口对都有自己的关联接口(使用interface_name:n表示法),而在其他系统(Windows)上,单个接口将具有每个协议的地址列表。在这两种情况下,都有一个协议列表,但是它可能只包含一个元素。

以下是一些netifaces代码可用于:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()

# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]

# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]

iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.

上面的代码不会将地址映射回其接口名称(用于动态生成ebtables / iptables规则)。因此,这是一个将上述信息和接口名称保存在元组中的版本:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
ifaces = netifaces.interfaces()

# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]

# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]

iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]

而且,不,我不喜欢列表理解。这些天就是我的大脑运作的方式。

以下代码片段将全部打印出来:

from __future__ import print_function  # For 2.x folks
from pprint import pprint as pp

print('\nifaces = ', end='')
pp(ifaces)

print('\nif_addrs = ', end='')
pp(if_addrs)

print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)

print('\niface_addrs = ', end='')
pp(iface_addrs)

请享用!

netifaces is available via pip and easy_install. (I know, it’s not in base, but it could be worth the install.)

netifaces does have some oddities across platforms:

  • The localhost/loop-back interface may not always be included (Cygwin).
  • Addresses are listed per-protocol (e.g., IPv4, IPv6) and protocols are listed per-interface. On some systems (Linux) each protocol-interface pair has its own associated interface (using the interface_name:n notation) while on other systems (Windows) a single interface will have a list of addresses for each protocol. In both cases there is a protocol list, but it may contain only a single element.

Here’s some netifaces code to play with:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()

# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]

# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]

iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.

The above code doesn’t map an address back to its interface name (useful for generating ebtables/iptables rules on the fly). So here’s a version that keeps the above information with the interface name in a tuple:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
ifaces = netifaces.interfaces()

# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]

# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]

iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]

And, no, I’m not in love with list comprehensions. It’s just the way my brain works these days.

The following snippet will print it all out:

from __future__ import print_function  # For 2.x folks
from pprint import pprint as pp

print('\nifaces = ', end='')
pp(ifaces)

print('\nif_addrs = ', end='')
pp(if_addrs)

print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)

print('\niface_addrs = ', end='')
pp(iface_addrs)

Enjoy!


回答 28

使用新引入的asyncio软件包的Python 3.4版本。

async get_local_ip():
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        asyncio.DatagramProtocol,
        remote_addr=('8.8.8.8', 80))
    result = transport.get_extra_info('sockname')[0])
    transport.close()
    return result

这是基于UnkwnTech的出色回答

A Python 3.4 version utilizing the newly introduced asyncio package.

async get_local_ip():
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        asyncio.DatagramProtocol,
        remote_addr=('8.8.8.8', 80))
    result = transport.get_extra_info('sockname')[0])
    transport.close()
    return result

This is based on UnkwnTech’s excellent answer.


回答 29

要获取IP地址,您可以直接在python中使用shell命令

import socket, subprocess

def getIpAndHostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = getIpAndHostname()

To get the ip address you can use a shell command directly in python:

import socket, subprocess

def getIpAndHostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = getIpAndHostname()