分类目录归档:知识问答

Python中的目录树列表

问题:Python中的目录树列表

如何获取Python给定目录中所有文件(和目录)的列表?

How do I get a list of all files (and directories) in a given directory in Python?


回答 0

这是遍历目录树中每个文件和目录的一种方式:

import os

for dirname, dirnames, filenames in os.walk('.'):
    # print path to all subdirectories first.
    for subdirname in dirnames:
        print(os.path.join(dirname, subdirname))

    # print path to all filenames.
    for filename in filenames:
        print(os.path.join(dirname, filename))

    # Advanced usage:
    # editing the 'dirnames' list will stop os.walk() from recursing into there.
    if '.git' in dirnames:
        # don't go into any .git directories.
        dirnames.remove('.git')

This is a way to traverse every file and directory in a directory tree:

import os

for dirname, dirnames, filenames in os.walk('.'):
    # print path to all subdirectories first.
    for subdirname in dirnames:
        print(os.path.join(dirname, subdirname))

    # print path to all filenames.
    for filename in filenames:
        print(os.path.join(dirname, filename))

    # Advanced usage:
    # editing the 'dirnames' list will stop os.walk() from recursing into there.
    if '.git' in dirnames:
        # don't go into any .git directories.
        dirnames.remove('.git')

回答 1

您可以使用

os.listdir(path)

作为参考和更多的os函数,请看这里:

You can use

os.listdir(path)

For reference and more os functions look here:


回答 2

这是我经常使用的辅助函数:

import os

def listdir_fullpath(d):
    return [os.path.join(d, f) for f in os.listdir(d)]

Here’s a helper function I use quite often:

import os

def listdir_fullpath(d):
    return [os.path.join(d, f) for f in os.listdir(d)]

回答 3

import os

for filename in os.listdir("C:\\temp"):
    print  filename
import os

for filename in os.listdir("C:\\temp"):
    print  filename

回答 4

如果您需要遍历功能,那么还可以使用一个模块。例如:

import glob
glob.glob('./[0-9].*')

将返回类似:

['./1.gif', './2.txt']

请参阅此处的文档。

If you need globbing abilities, there’s a module for that as well. For example:

import glob
glob.glob('./[0-9].*')

will return something like:

['./1.gif', './2.txt']

See the documentation here.


回答 5

尝试这个:

import os
for top, dirs, files in os.walk('./'):
    for nm in files:       
        print os.path.join(top, nm)

Try this:

import os
for top, dirs, files in os.walk('./'):
    for nm in files:       
        print os.path.join(top, nm)

回答 6

对于当前工作目录中的文件,但未指定路径

Python 2.7:

import os
os.listdir(os.getcwd())

Python 3.x:

import os
os.listdir()

感谢Stam Kaly对python 3.x的评论

For files in current working directory without specifying a path

Python 2.7:

import os
os.listdir(os.getcwd())

Python 3.x:

import os
os.listdir()

Thanks to Stam Kaly for comment on python 3.x


回答 7

递归实现

import os

def scan_dir(dir):
    for name in os.listdir(dir):
        path = os.path.join(dir, name)
        if os.path.isfile(path):
            print path
        else:
            scan_dir(path)

A recursive implementation

import os

def scan_dir(dir):
    for name in os.listdir(dir):
        path = os.path.join(dir, name)
        if os.path.isfile(path):
            print path
        else:
            scan_dir(path)

回答 8

我写了一个很长的版本,其中包含了我可能需要的所有选项:http : //sam.nipl.net/code/python/find.py

我想它也适合这里:

#!/usr/bin/env python

import os
import sys

def ls(dir, hidden=False, relative=True):
    nodes = []
    for nm in os.listdir(dir):
        if not hidden and nm.startswith('.'):
            continue
        if not relative:
            nm = os.path.join(dir, nm)
        nodes.append(nm)
    nodes.sort()
    return nodes

def find(root, files=True, dirs=False, hidden=False, relative=True, topdown=True):
    root = os.path.join(root, '')  # add slash if not there
    for parent, ldirs, lfiles in os.walk(root, topdown=topdown):
        if relative:
            parent = parent[len(root):]
        if dirs and parent:
            yield os.path.join(parent, '')
        if not hidden:
            lfiles   = [nm for nm in lfiles if not nm.startswith('.')]
            ldirs[:] = [nm for nm in ldirs  if not nm.startswith('.')]  # in place
        if files:
            lfiles.sort()
            for nm in lfiles:
                nm = os.path.join(parent, nm)
                yield nm

def test(root):
    print "* directory listing, with hidden files:"
    print ls(root, hidden=True)
    print
    print "* recursive listing, with dirs, but no hidden files:"
    for f in find(root, dirs=True):
        print f
    print

if __name__ == "__main__":
    test(*sys.argv[1:])

I wrote a long version, with all the options I might need: http://sam.nipl.net/code/python/find.py

I guess it will fit here too:

#!/usr/bin/env python

import os
import sys

def ls(dir, hidden=False, relative=True):
    nodes = []
    for nm in os.listdir(dir):
        if not hidden and nm.startswith('.'):
            continue
        if not relative:
            nm = os.path.join(dir, nm)
        nodes.append(nm)
    nodes.sort()
    return nodes

def find(root, files=True, dirs=False, hidden=False, relative=True, topdown=True):
    root = os.path.join(root, '')  # add slash if not there
    for parent, ldirs, lfiles in os.walk(root, topdown=topdown):
        if relative:
            parent = parent[len(root):]
        if dirs and parent:
            yield os.path.join(parent, '')
        if not hidden:
            lfiles   = [nm for nm in lfiles if not nm.startswith('.')]
            ldirs[:] = [nm for nm in ldirs  if not nm.startswith('.')]  # in place
        if files:
            lfiles.sort()
            for nm in lfiles:
                nm = os.path.join(parent, nm)
                yield nm

def test(root):
    print "* directory listing, with hidden files:"
    print ls(root, hidden=True)
    print
    print "* recursive listing, with dirs, but no hidden files:"
    for f in find(root, dirs=True):
        print f
    print

if __name__ == "__main__":
    test(*sys.argv[1:])

回答 9

这是另一种选择。

os.scandir(path='.')

它返回os.DirEntry对象的迭代器,该对象与path所给目录中的条目(以及文件属性信息)相对应。

例:

with os.scandir(path) as it:
    for entry in it:
        if not entry.name.startswith('.'):
            print(entry.name)

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

Python文档

Here is another option.

os.scandir(path='.')

It returns an iterator of os.DirEntry objects corresponding to the entries (along with file attribute information) in the directory given by path.

Example:

with os.scandir(path) as it:
    for entry in it:
        if not entry.name.startswith('.'):
            print(entry.name)

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.

Python Docs


回答 10

虽然os.listdir()可以很好地生成文件名和目录名列表,但是一旦拥有了这些文件名,就经常想做更多的事情-在Python3中,pathlib使其他琐事变得简单。让我们看一下,看看您是否像我一样喜欢它。

要列出目录内容,请构造一个Path对象并获取迭代器:

In [16]: Path('/etc').iterdir()
Out[16]: <generator object Path.iterdir at 0x110853fc0>

如果我们只想要事物名称列表:

In [17]: [x.name for x in Path('/etc').iterdir()]
Out[17]:
['emond.d',
 'ntp-restrict.conf',
 'periodic',

如果您只想要Dirs:

In [18]: [x.name for x in Path('/etc').iterdir() if x.is_dir()]
Out[18]:
['emond.d',
 'periodic',
 'mach_init.d',

如果您想要该树中所有conf文件的名称:

In [20]: [x.name for x in Path('/etc').glob('**/*.conf')]
Out[20]:
['ntp-restrict.conf',
 'dnsextd.conf',
 'syslog.conf',

如果要在树中的conf文件列表> = 1K中:

In [23]: [x.name for x in Path('/etc').glob('**/*.conf') if x.stat().st_size > 1024]
Out[23]:
['dnsextd.conf',
 'pf.conf',
 'autofs.conf',

解决相对路径变得容易:

In [32]: Path('../Operational Metrics.md').resolve()
Out[32]: PosixPath('/Users/starver/code/xxxx/Operational Metrics.md')

使用路径导航非常清晰(尽管出乎意料):

In [10]: p = Path('.')

In [11]: core = p / 'web' / 'core'

In [13]: [x for x in core.iterdir() if x.is_file()]
Out[13]:
[PosixPath('web/core/metrics.py'),
 PosixPath('web/core/services.py'),
 PosixPath('web/core/querysets.py'),

While os.listdir() is fine for generating a list of file and dir names, frequently you want to do more once you have those names – and in Python3, pathlib makes those other chores simple. Let’s take a look and see if you like it as much as I do.

To list dir contents, construct a Path object and grab the iterator:

In [16]: Path('/etc').iterdir()
Out[16]: <generator object Path.iterdir at 0x110853fc0>

If we want just a list of names of things:

In [17]: [x.name for x in Path('/etc').iterdir()]
Out[17]:
['emond.d',
 'ntp-restrict.conf',
 'periodic',

If you want just the dirs:

In [18]: [x.name for x in Path('/etc').iterdir() if x.is_dir()]
Out[18]:
['emond.d',
 'periodic',
 'mach_init.d',

If you want the names of all conf files in that tree:

In [20]: [x.name for x in Path('/etc').glob('**/*.conf')]
Out[20]:
['ntp-restrict.conf',
 'dnsextd.conf',
 'syslog.conf',

If you want a list of conf files in the tree >= 1K:

In [23]: [x.name for x in Path('/etc').glob('**/*.conf') if x.stat().st_size > 1024]
Out[23]:
['dnsextd.conf',
 'pf.conf',
 'autofs.conf',

Resolving relative paths become easy:

In [32]: Path('../Operational Metrics.md').resolve()
Out[32]: PosixPath('/Users/starver/code/xxxx/Operational Metrics.md')

Navigating with a Path is pretty clear (although unexpected):

In [10]: p = Path('.')

In [11]: core = p / 'web' / 'core'

In [13]: [x for x in core.iterdir() if x.is_file()]
Out[13]:
[PosixPath('web/core/metrics.py'),
 PosixPath('web/core/services.py'),
 PosixPath('web/core/querysets.py'),

回答 11

一个很好的衬垫,可以递归地仅列出文件。我在setup.py package_data指令中使用了此命令:

import os

[os.path.join(x[0],y) for x in os.walk('<some_directory>') for y in x[2]]

我知道这不是问题的答案,但可能会派上用场

A nice one liner to list only the files recursively. I used this in my setup.py package_data directive:

import os

[os.path.join(x[0],y) for x in os.walk('<some_directory>') for y in x[2]]

I know it’s not the answer to the question, but may come in handy


回答 12

对于Python 2

#!/bin/python2

import os

def scan_dir(path):
    print map(os.path.abspath, os.listdir(pwd))

对于Python 3

对于过滤器和地图,您需要使用list()包装它们

#!/bin/python3

import os

def scan_dir(path):
    print(list(map(os.path.abspath, os.listdir(pwd))))

现在的建议是,用生成器表达式或列表推导替换map和filter的用法:

#!/bin/python

import os

def scan_dir(path):
    print([os.path.abspath(f) for f in os.listdir(path)])

For Python 2

#!/bin/python2

import os

def scan_dir(path):
    print map(os.path.abspath, os.listdir(pwd))

For Python 3

For filter and map, you need wrap them with list()

#!/bin/python3

import os

def scan_dir(path):
    print(list(map(os.path.abspath, os.listdir(pwd))))

The recommendation now is that you replace your usage of map and filter with generators expressions or list comprehensions:

#!/bin/python

import os

def scan_dir(path):
    print([os.path.abspath(f) for f in os.listdir(path)])

回答 13

这是一行Pythonic版本:

import os
dir = 'given_directory_name'
filenames = [os.path.join(os.path.dirname(os.path.abspath(__file__)),dir,i) for i in os.listdir(dir)]

此代码列出了给定目录名称中所有文件和目录的完整路径。

Here is a one line Pythonic version:

import os
dir = 'given_directory_name'
filenames = [os.path.join(os.path.dirname(os.path.abspath(__file__)),dir,i) for i in os.listdir(dir)]

This code lists the full path of all files and directories in the given directory name.


回答 14

我知道这是一个老问题。如果您使用的是liunx机器,这是我遇到的一种巧妙方法。

import subprocess
print(subprocess.check_output(["ls", "/"]).decode("utf8"))

I know this is an old question. This is a neat way I came across if you are on a liunx machine.

import subprocess
print(subprocess.check_output(["ls", "/"]).decode("utf8"))

回答 15

#import modules
import os

_CURRENT_DIR = '.'


def rec_tree_traverse(curr_dir, indent):
    "recurcive function to traverse the directory"
    #print "[traverse_tree]"

    try :
        dfList = [os.path.join(curr_dir, f_or_d) for f_or_d in os.listdir(curr_dir)]
    except:
        print "wrong path name/directory name"
        return

    for file_or_dir in dfList:

        if os.path.isdir(file_or_dir):
            #print "dir  : ",
            print indent, file_or_dir,"\\"
            rec_tree_traverse(file_or_dir, indent*2)

        if os.path.isfile(file_or_dir):
            #print "file : ",
            print indent, file_or_dir

    #end if for loop
#end of traverse_tree()

def main():

    base_dir = _CURRENT_DIR

    rec_tree_traverse(base_dir," ")

    raw_input("enter any key to exit....")
#end of main()


if __name__ == '__main__':
    main()
#import modules
import os

_CURRENT_DIR = '.'


def rec_tree_traverse(curr_dir, indent):
    "recurcive function to traverse the directory"
    #print "[traverse_tree]"

    try :
        dfList = [os.path.join(curr_dir, f_or_d) for f_or_d in os.listdir(curr_dir)]
    except:
        print "wrong path name/directory name"
        return

    for file_or_dir in dfList:

        if os.path.isdir(file_or_dir):
            #print "dir  : ",
            print indent, file_or_dir,"\\"
            rec_tree_traverse(file_or_dir, indent*2)

        if os.path.isfile(file_or_dir):
            #print "file : ",
            print indent, file_or_dir

    #end if for loop
#end of traverse_tree()

def main():

    base_dir = _CURRENT_DIR

    rec_tree_traverse(base_dir," ")

    raw_input("enter any key to exit....")
#end of main()


if __name__ == '__main__':
    main()

回答 16

仅供参考,添加扩展名或扩展名文件过滤器os

path = '.'
for dirname, dirnames, filenames in os.walk(path):
    # print path to all filenames with extension py.
    for filename in filenames:
        fname_path = os.path.join(dirname, filename)
        fext = os.path.splitext(fname_path)[1]
        if fext == '.py':
            print fname_path
        else:
            continue

FYI Add a filter of extension or ext file import os

path = '.'
for dirname, dirnames, filenames in os.walk(path):
    # print path to all filenames with extension py.
    for filename in filenames:
        fname_path = os.path.join(dirname, filename)
        fext = os.path.splitext(fname_path)[1]
        if fext == '.py':
            print fname_path
        else:
            continue

回答 17

如果知道的话,我会把它扔进去。通配符搜索的简单而肮脏的方法。

import re
import os

[a for a in os.listdir(".") if re.search("^.*\.py$",a)]

If figured I’d throw this in. Simple and dirty way to do wildcard searches.

import re
import os

[a for a in os.listdir(".") if re.search("^.*\.py$",a)]

回答 18

下面的代码将列出目录和目录中的文件

def print_directory_contents(sPath):
        import os                                       
        for sChild in os.listdir(sPath):                
            sChildPath = os.path.join(sPath,sChild)
            if os.path.isdir(sChildPath):
                print_directory_contents(sChildPath)
            else:
                print(sChildPath)

Below code will list directories and the files within the dir

def print_directory_contents(sPath):
        import os                                       
        for sChild in os.listdir(sPath):                
            sChildPath = os.path.join(sPath,sChild)
            if os.path.isdir(sChildPath):
                print_directory_contents(sChildPath)
            else:
                print(sChildPath)

回答 19

和我一起工作的人是上述萨利赫回答的一种修改版本。

代码如下:

“ dir =’given_directory_name’文件名= [os.listdir(dir)中用于i的os.path.abspath(os.path.join(dir,i))]”

The one worked with me is kind of a modified version from Saleh answer above.

The code is as follows:

“dir = ‘given_directory_name’ filenames = [os.path.abspath(os.path.join(dir,i)) for i in os.listdir(dir)]”


如何让python等待按下的键?

问题:如何让python等待按下的键?

我希望我的脚本等待用户按下任何键。

我怎么做?

I want my script to wait until the user presses any key.

How do I do that?


回答 0

Python 3中使用input()

input("Press Enter to continue...")

Python 2中使用raw_input()

raw_input("Press Enter to continue...")

不过,这仅等待用户按下Enter键。

可能要使用msvcrt((仅Windows / DOS)使用msvcrt模块可以访问Microsoft Visual C / C ++运行时库(MSVCRT)中的许多功能):

import msvcrt as m
def wait():
    m.getch()

这应该等待按键。

附加信息:

Python 3 raw_input()中不存在

在Python 2 input(prompt)中等效于eval(raw_input(prompt))

In Python 3 use input():

input("Press Enter to continue...")

In Python 2 use raw_input():

raw_input("Press Enter to continue...")

This only waits for the user to press enter though.

One might want to use msvcrt ((Windows/DOS only) The msvcrt module gives you access to a number of functions in the Microsoft Visual C/C++ Runtime Library (MSVCRT)):

import msvcrt as m
def wait():
    m.getch()

This should wait for a key press.

Additional info:

in Python 3 raw_input() does not exist

In Python 2 input(prompt) is equivalent to eval(raw_input(prompt))


回答 1

在Python 2中执行此操作的一种方法是使用raw_input()

raw_input("Press Enter to continue...")

在python3中 input()

One way to do this in Python 2, is to use raw_input():

raw_input("Press Enter to continue...")

In python3 it’s just input()


回答 2

在我的Linux机器上,我使用以下代码。这类似于我在其他地方看到的代码(例如,在旧的python FAQ中),但是该代码在一个紧密的循环中旋转,其中该代码不起作用,并且在很多奇怪的情况下,代码无法解决这个问题代码呢。

def read_single_keypress():
    """Waits for a single keypress on stdin.

    This is a silly function to call if you need to do it a lot because it has
    to store stdin's current setup, setup stdin for reading single keystrokes
    then read the single keystroke then revert stdin back after reading the
    keystroke.

    Returns a tuple of characters of the key that was pressed - on Linux, 
    pressing keys like up arrow results in a sequence of characters. Returns 
    ('\x03',) on KeyboardInterrupt which can happen when a signal gets
    handled.

    """
    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    ret = []
    try:
        ret.append(sys.stdin.read(1)) # returns a single character
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save | os.O_NONBLOCK)
        c = sys.stdin.read(1) # returns a single character
        while len(c) > 0:
            ret.append(c)
            c = sys.stdin.read(1)
    except KeyboardInterrupt:
        ret.append('\x03')
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return tuple(ret)

On my linux box, I use the following code. This is similar to code I’ve seen elsewhere (in the old python FAQs for instance) but that code spins in a tight loop where this code doesn’t and there are lots of odd corner cases that code doesn’t account for that this code does.

def read_single_keypress():
    """Waits for a single keypress on stdin.

    This is a silly function to call if you need to do it a lot because it has
    to store stdin's current setup, setup stdin for reading single keystrokes
    then read the single keystroke then revert stdin back after reading the
    keystroke.

    Returns a tuple of characters of the key that was pressed - on Linux, 
    pressing keys like up arrow results in a sequence of characters. Returns 
    ('\x03',) on KeyboardInterrupt which can happen when a signal gets
    handled.

    """
    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    ret = []
    try:
        ret.append(sys.stdin.read(1)) # returns a single character
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save | os.O_NONBLOCK)
        c = sys.stdin.read(1) # returns a single character
        while len(c) > 0:
            ret.append(c)
            c = sys.stdin.read(1)
    except KeyboardInterrupt:
        ret.append('\x03')
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return tuple(ret)

回答 3

如果可以,请根据系统命令使用以下命令:

Linux:

import os
os.system('read -sn 1 -p "Press any key to continue..."')
print

视窗:

import os
os.system("pause")

If you are ok with depending on system commands you can use the following:

Linux:

import os
os.system('read -sn 1 -p "Press any key to continue..."')
print

Windows:

import os
os.system("pause")

回答 4

只需使用

input("Press Enter to continue...")

解析时将导致SyntaxError:预期的EOF。

简单修复方法:

try:
    input("Press enter to continue")
except SyntaxError:
    pass

Simply using

input("Press Enter to continue...")

will cause a SyntaxError: expected EOF while parsing.

Simple fix use:

try:
    input("Press enter to continue")
except SyntaxError:
    pass

回答 5

python 手册提供以下内容:

import termios, fcntl, sys, os
fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:
    while 1:
        try:
            c = sys.stdin.read(1)
            print "Got character", repr(c)
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

可以合并到您的用例中。

The python manual provides the following:

import termios, fcntl, sys, os
fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:
    while 1:
        try:
            c = sys.stdin.read(1)
            print "Got character", repr(c)
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

which can be rolled into your use case.


回答 6

跨平台,Python 2/3代码:

# import sys, os

def wait_key():
    ''' Wait for a key press on the console and return it. '''
    result = None
    if os.name == 'nt':
        import msvcrt
        result = msvcrt.getch()
    else:
        import termios
        fd = sys.stdin.fileno()

        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)

        try:
            result = sys.stdin.read(1)
        except IOError:
            pass
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

    return result

我删除了fctl / non-blocking东西,因为它给了IOErrors,我不需要它。我之所以使用此代码,是因为我想阻止它。;)

附录:

我在PyPI上的一个包中实现了此功能,并使用了许多其他名为console的好东西:

>>> from console.utils import wait_key

>>> wait_key()
'h'

Cross Platform, Python 2/3 code:

# import sys, os

def wait_key():
    ''' Wait for a key press on the console and return it. '''
    result = None
    if os.name == 'nt':
        import msvcrt
        result = msvcrt.getch()
    else:
        import termios
        fd = sys.stdin.fileno()

        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)

        try:
            result = sys.stdin.read(1)
        except IOError:
            pass
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

    return result

I removed the fctl/non-blocking stuff because it was giving IOErrors and I didn’t need it. I’m using this code specifically because I want it to block. ;)

Addendum:

I implemented this in a package on PyPI with a lot of other goodies called console:

>>> from console.utils import wait_key

>>> wait_key()
'h'

回答 7

我不知道这样做是与平台无关的,但是在Windows下,如果使用msvcrt模块,则可以使用其getch函数:

import msvcrt
c = msvcrt.getch()
print 'you entered', c

mscvcrt还包括非阻塞kbhit()函数,以查看是否在不等待键的情况下按下了键(不确定是否有相应的curses函数)。在UNIX下,有curses程序包,但是不确定是否可以不将其用于所有屏幕输出而使用它。该代码在UNIX下工作:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

请注意,curses.getch()返回所按下键的序数,以便使其具有与强制转换相同的输出。

I don’t know of a platform independent way of doing it, but under Windows, if you use the msvcrt module, you can use its getch function:

import msvcrt
c = msvcrt.getch()
print 'you entered', c

mscvcrt also includes the non-blocking kbhit() function to see if a key was pressed without waiting (not sure if there’s a corresponding curses function). Under UNIX, there is the curses package, but not sure if you can use it without using it for all of the screen output. This code works under UNIX:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

Note that curses.getch() returns the ordinal of the key pressed so to make it have the same output I had to cast it.


回答 8

如果要等待输入(因此用户敲击键盘不会引起意外的事情),请使用

sys.stdin.readline()

If you want to wait for enter (so the user knocking the keyboard does not cause something un-intended to happen) use

sys.stdin.readline()

回答 9

我是python的新手,我已经认为自己太愚蠢了,无法重现这里提出的最简单的建议。事实证明,有一个陷阱应该知道:

当从IDLE执行python脚本时,某些IO命令的行为似乎完全不同(因为实际上没有终端窗口)。

例如。msvcrt.getch是非阻塞的,并且始终返回$ ff。这已经很久以前就被报道过了(参见例如https://bugs.python.org/issue9290它被标记为已修复,在当前版本的python / IDLE中问题似乎仍然存在。

因此,如果上面发布的任何代码都不适合您,请尝试手动运行脚本,而不要从IDLE运行

I am new to python and I was already thinking I am too stupid to reproduce the simplest suggestions made here. It turns out, there’s a pitfall one should know:

When a python-script is executed from IDLE, some IO-commands seem to behave completely different (as there is actually no terminal window).

Eg. msvcrt.getch is non-blocking and always returns $ff. This has already been reported long ago (see e.g. https://bugs.python.org/issue9290 ) – and it’s marked as fixed, somehow the problem seems to persist in current versions of python/IDLE.

So if any of the code posted above doesn’t work for you, try running the script manually, and NOT from IDLE.


回答 10

如果要查看他们是否按下了确切的键(例如说“ b”),请执行以下操作:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break

If you want to see if they pressed a exact key (like say ‘b’) Do this:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break

回答 11

os.system似乎总是调用sh,后者无法识别s和n选项以进行读取。但是,可以将read命令传递给bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")

os.system seems to always invoke sh, which does not recognize the s and n options for read. However the read command can be passed to bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")

构建一个基本的Python迭代器

问题:构建一个基本的Python迭代器

如何在python中创建一个迭代函数(或迭代器对象)?

How would one create an iterative function (or iterator object) in python?


回答 0

python中的迭代器对象符合迭代器协议,这基本上意味着它们提供了两种方法:__iter__()__next__()

  • __iter__返回迭代器对象,并在循环开始时隐式调用。

  • __next__()方法返回下一个值,并在每次循环增量时隐式调用。当没有更多值要返回时,此方法将引发StopIteration异常,该异常由循环构造以停止迭代的方式隐式捕获。

这是一个简单的计数器示例:

class Counter:
    def __init__(self, low, high):
        self.current = low - 1
        self.high = high

    def __iter__(self):
        return self

    def __next__(self): # Python 2: def next(self)
        self.current += 1
        if self.current < self.high:
            return self.current
        raise StopIteration


for c in Counter(3, 9):
    print(c)

这将打印:

3
4
5
6
7
8

如上一个答案所述,使用生成器编写起来更容易:

def counter(low, high):
    current = low
    while current < high:
        yield current
        current += 1

for c in counter(3, 9):
    print(c)

打印的输出将相同。在内部,生成器对象支持迭代器协议,并且执行与类Counter大致相似的操作。

David Mertz的文章Iterators和Simple Generators是很好的介绍。

Iterator objects in python conform to the iterator protocol, which basically means they provide two methods: __iter__() and __next__().

  • The __iter__ returns the iterator object and is implicitly called at the start of loops.

  • The __next__() method returns the next value and is implicitly called at each loop increment. This method raises a StopIteration exception when there are no more value to return, which is implicitly captured by looping constructs to stop iterating.

Here’s a simple example of a counter:

class Counter:
    def __init__(self, low, high):
        self.current = low - 1
        self.high = high

    def __iter__(self):
        return self

    def __next__(self): # Python 2: def next(self)
        self.current += 1
        if self.current < self.high:
            return self.current
        raise StopIteration


for c in Counter(3, 9):
    print(c)

This will print:

3
4
5
6
7
8

This is easier to write using a generator, as covered in a previous answer:

def counter(low, high):
    current = low
    while current < high:
        yield current
        current += 1

for c in counter(3, 9):
    print(c)

The printed output will be the same. Under the hood, the generator object supports the iterator protocol and does something roughly similar to the class Counter.

David Mertz’s article, Iterators and Simple Generators, is a pretty good introduction.


回答 1

有四种方法可以构建迭代函数:

例子:

# generator
def uc_gen(text):
    for char in text.upper():
        yield char

# generator expression
def uc_genexp(text):
    return (char for char in text.upper())

# iterator protocol
class uc_iter():
    def __init__(self, text):
        self.text = text.upper()
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        try:
            result = self.text[self.index]
        except IndexError:
            raise StopIteration
        self.index += 1
        return result

# getitem method
class uc_getitem():
    def __init__(self, text):
        self.text = text.upper()
    def __getitem__(self, index):
        return self.text[index]

要查看所有四种方法:

for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
    for ch in iterator('abcde'):
        print(ch, end=' ')
    print()

结果是:

A B C D E
A B C D E
A B C D E
A B C D E

注意事项

两种生成器类型(uc_genuc_genexp)不能为reversed(); 普通的iterator(uc_iter)将需要__reversed__magic方法(根据docs,它必须返回一个新的iterator,但返回self工作结果(至少在CPython中));并且getitem iteratable(uc_getitem)必须具有__len__魔术方法:

    # for uc_iter we add __reversed__ and update __next__
    def __reversed__(self):
        self.index = -1
        return self
    def __next__(self):
        try:
            result = self.text[self.index]
        except IndexError:
            raise StopIteration
        self.index += -1 if self.index < 0 else +1
        return result

    # for uc_getitem
    def __len__(self)
        return len(self.text)

为了回答上校Panic关于无限懒惰求值的迭代器的第二个问题,以下是使用上述四种方法中的每一个的示例:

# generator
def even_gen():
    result = 0
    while True:
        yield result
        result += 2


# generator expression
def even_genexp():
    return (num for num in even_gen())  # or even_iter or even_getitem
                                        # not much value under these circumstances

# iterator protocol
class even_iter():
    def __init__(self):
        self.value = 0
    def __iter__(self):
        return self
    def __next__(self):
        next_value = self.value
        self.value += 2
        return next_value

# getitem method
class even_getitem():
    def __getitem__(self, index):
        return index * 2

import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
    limit = random.randint(15, 30)
    count = 0
    for even in iterator():
        print even,
        count += 1
        if count >= limit:
            break
    print

结果(至少在我的示例运行中):

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32

如何选择使用哪一个?这主要是一个品味问题。我最常看到的两种方法是生成器和迭代器协议,以及混合方法(__iter__返回生成器)。

生成器表达式可用于替换列表推导(它们很懒,因此可以节省资源)。

如果需要与早期的Python 2.x版本兼容,请使用__getitem__

There are four ways to build an iterative function:

Examples:

# generator
def uc_gen(text):
    for char in text.upper():
        yield char

# generator expression
def uc_genexp(text):
    return (char for char in text.upper())

# iterator protocol
class uc_iter():
    def __init__(self, text):
        self.text = text.upper()
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        try:
            result = self.text[self.index]
        except IndexError:
            raise StopIteration
        self.index += 1
        return result

# getitem method
class uc_getitem():
    def __init__(self, text):
        self.text = text.upper()
    def __getitem__(self, index):
        return self.text[index]

To see all four methods in action:

for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
    for ch in iterator('abcde'):
        print(ch, end=' ')
    print()

Which results in:

A B C D E
A B C D E
A B C D E
A B C D E

Note:

The two generator types (uc_gen and uc_genexp) cannot be reversed(); the plain iterator (uc_iter) would need the __reversed__ magic method (which, according to the docs, must return a new iterator, but returning self works (at least in CPython)); and the getitem iteratable (uc_getitem) must have the __len__ magic method:

    # for uc_iter we add __reversed__ and update __next__
    def __reversed__(self):
        self.index = -1
        return self
    def __next__(self):
        try:
            result = self.text[self.index]
        except IndexError:
            raise StopIteration
        self.index += -1 if self.index < 0 else +1
        return result

    # for uc_getitem
    def __len__(self)
        return len(self.text)

To answer Colonel Panic’s secondary question about an infinite lazily evaluated iterator, here are those examples, using each of the four methods above:

# generator
def even_gen():
    result = 0
    while True:
        yield result
        result += 2


# generator expression
def even_genexp():
    return (num for num in even_gen())  # or even_iter or even_getitem
                                        # not much value under these circumstances

# iterator protocol
class even_iter():
    def __init__(self):
        self.value = 0
    def __iter__(self):
        return self
    def __next__(self):
        next_value = self.value
        self.value += 2
        return next_value

# getitem method
class even_getitem():
    def __getitem__(self, index):
        return index * 2

import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
    limit = random.randint(15, 30)
    count = 0
    for even in iterator():
        print even,
        count += 1
        if count >= limit:
            break
    print

Which results in (at least for my sample run):

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32

How to choose which one to use? This is mostly a matter of taste. The two methods I see most often are generators and the iterator protocol, as well as a hybrid (__iter__ returning a generator).

Generator expressions are useful for replacing list comprehensions (they are lazy and so can save on resources).

If one needs compatibility with earlier Python 2.x versions use __getitem__.


回答 2

首先,itertools模块在各种情况下都非常有用,在这种情况下,迭代器将是有用的,但是这里是在python中创建迭代器所需的全部:

那不是很酷吗?Yield可以用来代替函数中的正常收益。它返回的对象是相同的,但是它不会破坏状态并退出,而是为您要执行下一次迭代保存状态。这是直接从itertools函数列表中提取的示例:

def count(n=0):
    while True:
        yield n
        n += 1

如功能说明中所述(它是itertools模块中的count()函数…),它生成一个迭代器,该迭代器返回以n开头的连续整数。

生成器表达式是蠕虫(真棒蠕虫!)的另一种形式。可以使用它们代替列表推导来节省内存(列表推导会在内存中创建一个列表,如果未分配给变量,该列表在使用后会被销毁,但是生成器表达式可以创建一个Generator对象…说迭​​代器)。这是生成器表达式定义的示例:

gen = (n for n in xrange(0,11))

这与上面的迭代器定义非常相似,不同之处在于整个范围的预定范围是0到10。

我刚刚找到了xrange()(应该是我之前从未见过……)并将其添加到上述示例中。 xrange()range()的可迭代版本,其优点是不预先构建列表。如果您要遍历庞大的数据集并且只有那么多的内存可以进行访问,这将非常有用。

First of all the itertools module is incredibly useful for all sorts of cases in which an iterator would be useful, but here is all you need to create an iterator in python:

yield

Isn’t that cool? Yield can be used to replace a normal return in a function. It returns the object just the same, but instead of destroying state and exiting, it saves state for when you want to execute the next iteration. Here is an example of it in action pulled directly from the itertools function list:

def count(n=0):
    while True:
        yield n
        n += 1

As stated in the functions description (it’s the count() function from the itertools module…) , it produces an iterator that returns consecutive integers starting with n.

Generator expressions are a whole other can of worms (awesome worms!). They may be used in place of a List Comprehension to save memory (list comprehensions create a list in memory that is destroyed after use if not assigned to a variable, but generator expressions can create a Generator Object… which is a fancy way of saying Iterator). Here is an example of a generator expression definition:

gen = (n for n in xrange(0,11))

This is very similar to our iterator definition above except the full range is predetermined to be between 0 and 10.

I just found xrange() (suprised I hadn’t seen it before…) and added it to the above example. xrange() is an iterable version of range() which has the advantage of not prebuilding the list. It would be very useful if you had a giant corpus of data to iterate over and only had so much memory to do it in.


回答 3

我看到你们return self中有些人在做__iter__。我只想指出,__iter__它本身可以成为生成器(因此消除了对异常的需求__next__并引发了StopIteration异常)

class range:
  def __init__(self,a,b):
    self.a = a
    self.b = b
  def __iter__(self):
    i = self.a
    while i < self.b:
      yield i
      i+=1

当然,这里也可以直接生成一个生成器,但是对于更复杂的类,它可能很有用。

I see some of you doing return self in __iter__. I just wanted to note that __iter__ itself can be a generator (thus removing the need for __next__ and raising StopIteration exceptions)

class range:
  def __init__(self,a,b):
    self.a = a
    self.b = b
  def __iter__(self):
    i = self.a
    while i < self.b:
      yield i
      i+=1

Of course here one might as well directly make a generator, but for more complex classes it can be useful.


回答 4

这个问题是关于可迭代的对象,而不是关于迭代器。在Python中,序列也是可迭代的,因此制作可迭代类的一种方法是使其表现得像序列,即给它__getitem____len__方法。我已经在Python 2和3上对此进行了测试。

class CustomRange:

    def __init__(self, low, high):
        self.low = low
        self.high = high

    def __getitem__(self, item):
        if item >= len(self):
            raise IndexError("CustomRange index out of range")
        return self.low + item

    def __len__(self):
        return self.high - self.low


cr = CustomRange(0, 10)
for i in cr:
    print(i)

This question is about iterable objects, not about iterators. In Python, sequences are iterable too so one way to make an iterable class is to make it behave like a sequence, i.e. give it __getitem__ and __len__ methods. I have tested this on Python 2 and 3.

class CustomRange:

    def __init__(self, low, high):
        self.low = low
        self.high = high

    def __getitem__(self, item):
        if item >= len(self):
            raise IndexError("CustomRange index out of range")
        return self.low + item

    def __len__(self):
        return self.high - self.low


cr = CustomRange(0, 10)
for i in cr:
    print(i)

回答 5

对于复杂的对象,此页面上的所有答案都非常有用。但对于含有内置的迭代类型,属性那些像strlistsetdict,或任何实现collections.Iterable,你可以在你的类省略某些事情。

class Test(object):
    def __init__(self, string):
        self.string = string

    def __iter__(self):
        # since your string is already iterable
        return (ch for ch in self.string)
        # or simply
        return self.string.__iter__()
        # also
        return iter(self.string)

可以像这样使用:

for x in Test("abcde"):
    print(x)

# prints
# a
# b
# c
# d
# e

All answers on this page are really great for a complex object. But for those containing builtin iterable types as attributes, like str, list, set or dict, or any implementation of collections.Iterable, you can omit certain things in your class.

class Test(object):
    def __init__(self, string):
        self.string = string

    def __iter__(self):
        # since your string is already iterable
        return (ch for ch in self.string)
        # or simply
        return self.string.__iter__()
        # also
        return iter(self.string)

It can be used like:

for x in Test("abcde"):
    print(x)

# prints
# a
# b
# c
# d
# e

回答 6

如果没有,这是一个迭代函数yield。它利用iter函数和闭包将其状态保存在listpython 2的封闭范围内的可变()中。

def count(low, high):
    counter = [0]
    def tmp():
        val = low + counter[0]
        if val < high:
            counter[0] += 1
            return val
        return None
    return iter(tmp, None)

对于Python 3,封闭状态在封闭范围内保持不变,并nonlocal在局部范围内用于更新状态变量。

def count(low, high):
    counter = 0
    def tmp():
        nonlocal counter
        val = low + counter
        if val < high:
            counter += 1
            return val
        return None
    return iter(tmp, None)  

测试;

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9

This is an iterable function without yield. It make use of the iter function and a closure which keeps it’s state in a mutable (list) in the enclosing scope for python 2.

def count(low, high):
    counter = [0]
    def tmp():
        val = low + counter[0]
        if val < high:
            counter[0] += 1
            return val
        return None
    return iter(tmp, None)

For Python 3, closure state is kept in an immutable in the enclosing scope and nonlocal is used in local scope to update the state variable.

def count(low, high):
    counter = 0
    def tmp():
        nonlocal counter
        val = low + counter
        if val < high:
            counter += 1
            return val
        return None
    return iter(tmp, None)  

Test;

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9

回答 7

如果您想找简单明了的东西,也许对您来说已经足够了:

class A(object):
    def __init__(self, l):
        self.data = l

    def __iter__(self):
        return iter(self.data)

使用示例:

In [3]: a = A([2,3,4])

In [4]: [i for i in a]
Out[4]: [2, 3, 4]

If you looking for something short and simple, maybe it will be enough for you:

class A(object):
    def __init__(self, l):
        self.data = l

    def __iter__(self):
        return iter(self.data)

example of usage:

In [3]: a = A([2,3,4])

In [4]: [i for i in a]
Out[4]: [2, 3, 4]

回答 8

受Matt Gregory的回答启发,这里有一个更复杂的迭代器,它将返回a,b,…,z,aa,ab,…,zz,aaa,aab,…,zzy,zzz

    class AlphaCounter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def __next__(self): # Python 3: def __next__(self)
        alpha = ' abcdefghijklmnopqrstuvwxyz'
        n_current = sum([(alpha.find(self.current[x])* 26**(len(self.current)-x-1)) for x in range(len(self.current))])
        n_high = sum([(alpha.find(self.high[x])* 26**(len(self.high)-x-1)) for x in range(len(self.high))])
        if n_current > n_high:
            raise StopIteration
        else:
            increment = True
            ret = ''
            for x in self.current[::-1]:
                if 'z' == x:
                    if increment:
                        ret += 'a'
                    else:
                        ret += 'z'
                else:
                    if increment:
                        ret += alpha[alpha.find(x)+1]
                        increment = False
                    else:
                        ret += x
            if increment:
                ret += 'a'
            tmp = self.current
            self.current = ret[::-1]
            return tmp

for c in AlphaCounter('a', 'zzz'):
    print(c)

Inspired by Matt Gregory’s answer here is a bit more complicated iterator that will return a,b,…,z,aa,ab,…,zz,aaa,aab,…,zzy,zzz

    class AlphaCounter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def __next__(self): # Python 3: def __next__(self)
        alpha = ' abcdefghijklmnopqrstuvwxyz'
        n_current = sum([(alpha.find(self.current[x])* 26**(len(self.current)-x-1)) for x in range(len(self.current))])
        n_high = sum([(alpha.find(self.high[x])* 26**(len(self.high)-x-1)) for x in range(len(self.high))])
        if n_current > n_high:
            raise StopIteration
        else:
            increment = True
            ret = ''
            for x in self.current[::-1]:
                if 'z' == x:
                    if increment:
                        ret += 'a'
                    else:
                        ret += 'z'
                else:
                    if increment:
                        ret += alpha[alpha.find(x)+1]
                        increment = False
                    else:
                        ret += x
            if increment:
                ret += 'a'
            tmp = self.current
            self.current = ret[::-1]
            return tmp

for c in AlphaCounter('a', 'zzz'):
    print(c)

为什么总是在__new __()之后调用__init __()?

问题:为什么总是在__new __()之后调用__init __()?

我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。

但是,对于为什么__init__总是被称为after ,我有点困惑__new__。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放到__new__hacky中之外)。

这是一个例子:

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()

输出:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

为什么?

I’m just trying to streamline one of my classes and have introduced some functionality in the same style as the flyweight design pattern.

However, I’m a bit confused as to why __init__ is always called after __new__. I wasn’t expecting this. Can anyone tell me why this is happening and how I can implement this functionality otherwise? (Apart from putting the implementation into the __new__ which feels quite hacky.)

Here’s an example:

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()

Outputs:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

Why?


回答 0

使用__new__时,你需要控制一个新实例的创建。

使用 __init__时,你需要一个新的实例的控件初始化。

__new__是实例创建的第一步。它首先被调用,并负责返回您的类的新实例。

相反, __init__什么也不返回;创建实例后,它仅负责初始化实例。

通常,__new__除非您要继承不可变类型(例如str,int,unicode或tuple),否则无需重写。

从2008年4月发布:何时使用__new__vs __init__在mail.python.org上。

您应该考虑要尝试做的事通常是通过Factory完成的,这是最好的方法。使用__new__不是一个好的清洁解决方案,因此请考虑使用工厂。在这里,您有一个很好的工厂示例

Use __new__ when you need to control the creation of a new instance.

Use __init__ when you need to control initialization of a new instance.

__new__ is the first step of instance creation. It’s called first, and is responsible for returning a new instance of your class.

In contrast, __init__ doesn’t return anything; it’s only responsible for initializing the instance after it’s been created.

In general, you shouldn’t need to override __new__ unless you’re subclassing an immutable type like str, int, unicode or tuple.

From April 2008 post: When to use __new__ vs. __init__? on mail.python.org.

You should consider that what you are trying to do is usually done with a Factory and that’s the best way to do it. Using __new__ is not a good clean solution so please consider the usage of a factory. Here you have a good factory example.


回答 1

__new__是静态类方法,__init__而是实例方法。 __new__必须先创建实例,因此__init__可以对其进行初始化。注意,__init__将其self作为参数。在创建实例之前,没有任何实例self

现在,我知道您正在尝试在Python中实现单例模式。有几种方法可以做到这一点。

另外,从Python 2.6开始,您可以使用类装饰器

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...

__new__ is static class method, while __init__ is instance method. __new__ has to create the instance first, so __init__ can initialize it. Note that __init__ takes self as parameter. Until you create instance there is no self.

Now, I gather, that you’re trying to implement singleton pattern in Python. There are a few ways to do that.

Also, as of Python 2.6, you can use class decorators.

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...

回答 2

在大多数众所周知的OO语言中,类似的表达式SomeClass(arg1, arg2)将分配一个新实例,初始化该实例的属性,然后返回它。

在大多数著名的OO语言中,可以通过定义构造函数为每个类自定义“初始化实例的属性”部分,该构造函数基本上只是在新实例上运行的代码块(使用提供给构造函数表达式的参数) )来设置所需的任何初始条件。在Python中,这对应于class的__init__方法。

Python的__new__功能无非就是“分配新实例”部分的类似的按类自定义。当然,这允许您执行不同寻常的操作,例如返回现有实例而不是分配新实例。因此,在Python中,我们不应该真的认为这部分必然涉及分配。我们所需要的只是__new__从某个地方提出一个合适的实例。

但这仍然只是工作的一半,Python系统无法知道有时您希望__init__稍后再执行另一部分工作(),而有时又不想。如果您想要这种行为,则必须明确地说出。

通常,您可以重构,因此只需要__new__,或者不需要__new__,或者这样__init__就可以在已初始化的对象上表现不同。但是,如果你真的想,Python不竟让你重新定义“工作”,所以SomeClass(arg1, arg2)不一定需要__new__后面__init__。为此,您需要创建一个元类,并定义其__call__方法。

元类只是类的类。而类的__call__方法控制了当您调用类的实例时会发生什么。因此,metaclass__call__方法控制了您调用类时发生的事情。即,它允许您从头到尾重新定义实例创建机制。在此级别上,您可以最优雅地实现完全非标准的实例创建过程,例如单例模式。事实上,用了不到10行代码就可以实现一个Singleton元类是那么甚至不要求你与futz __new__ 可言,并且可以将任何通过简单地增加,否则正常的,定义为单__metaclass__ = Singleton

class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance

但是,这可能比这种情况下真正应具有的魔力还要深!

In most well-known OO languages, an expression like SomeClass(arg1, arg2) will allocate a new instance, initialise the instance’s attributes, and then return it.

In most well-known OO languages, the “initialise the instance’s attributes” part can be customised for each class by defining a constructor, which is basically just a block of code that operates on the new instance (using the arguments provided to the constructor expression) to set up whatever initial conditions are desired. In Python, this corresponds to the class’ __init__ method.

Python’s __new__ is nothing more and nothing less than similar per-class customisation of the “allocate a new instance” part. This of course allows you to do unusual things such as returning an existing instance rather than allocating a new one. So in Python, we shouldn’t really think of this part as necessarily involving allocation; all that we require is that __new__ comes up with a suitable instance from somewhere.

But it’s still only half of the job, and there’s no way for the Python system to know that sometimes you want to run the other half of the job (__init__) afterwards and sometimes you don’t. If you want that behavior, you have to say so explicitly.

Often, you can refactor so you only need __new__, or so you don’t need __new__, or so that __init__ behaves differently on an already-initialised object. But if you really want to, Python does actually allow you to redefine “the job”, so that SomeClass(arg1, arg2) doesn’t necessarily call __new__ followed by __init__. To do this, you need to create a metaclass, and define its __call__ method.

A metaclass is just the class of a class. And a class’ __call__ method controls what happens when you call instances of the class. So a metaclass__call__ method controls what happens when you call a class; i.e. it allows you to redefine the instance-creation mechanism from start to finish. This is the level at which you can most elegantly implement a completely non-standard instance creation process such as the singleton pattern. In fact, with less than 10 lines of code you can implement a Singleton metaclass that then doesn’t even require you to futz with __new__ at all, and can turn any otherwise-normal class into a singleton by simply adding __metaclass__ = Singleton!

class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance

However this is probably deeper magic than is really warranted for this situation!


回答 3

引用文档

典型的实现通过使用带有适当参数的“ super(currentclass,cls).__ new __(cls [,…])”调用超类的__new __()方法,然后根据需要修改新创建的实例来创建该类的新实例。在返回之前。

如果__new __()不返回cls的实例,则将不会调用新实例的__init __()方法。

__new __()主要用于允许不可变类型的子类(例如int,str或tuple)自定义实例创建。

To quote the documentation:

Typical implementations create a new instance of the class by invoking the superclass’s __new__() method using “super(currentclass, cls).__new__(cls[, …])”with appropriate arguments and then modifying the newly-created instance as necessary before returning it.

If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation.


回答 4

我意识到这个问题已经很久了,但是我也遇到了类似的问题。以下是我想要的:

class Agent(object):
    _agents = dict()

    def __new__(cls, *p):
        number = p[0]
        if not number in cls._agents:
            cls._agents[number] = object.__new__(cls)
        return cls._agents[number]

    def __init__(self, number):
        self.number = number

    def __eq__(self, rhs):
        return self.number == rhs.number

Agent("a") is Agent("a") == True

我将此页面用作资源http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html

I realize that this question is quite old but I had a similar issue. The following did what I wanted:

class Agent(object):
    _agents = dict()

    def __new__(cls, *p):
        number = p[0]
        if not number in cls._agents:
            cls._agents[number] = object.__new__(cls)
        return cls._agents[number]

    def __init__(self, number):
        self.number = number

    def __eq__(self, rhs):
        return self.number == rhs.number

Agent("a") is Agent("a") == True

I used this page as a resource http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html


回答 5

我认为这个问题的简单答案是,如果__new__返回的值与类的类型相同,则__init__函数将执行,否则将不会执行。在这种情况下,您的代码将返回A._dict('key')与相同的类cls,因此__init__将被执行。

I think the simple answer to this question is that, if __new__ returns a value that is the same type as the class, the __init__ function executes, otherwise it won’t. In this case your code returns A._dict('key') which is the same class as cls, so __init__ will be executed.


回答 6

__new__返回相同类的实例时,__init__随后在返回的对象上运行。即您不能使用它__new__来阻止__init__运行。即使您从中返回先前创建的对象__new__,也将__init__一次又一次地将其初始化为double(三重,等等)。

这是Singleton模式的通用方法,它在上面扩展了vartec答案并对其进行了修复:

def SingletonClass(cls):
    class Single(cls):
        __doc__ = cls.__doc__
        _initialized = False
        _instance = None

        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
            return cls._instance

        def __init__(self, *args, **kwargs):
            if self._initialized:
                return
            super(Single, self).__init__(*args, **kwargs)
            self.__class__._initialized = True  # Its crucial to set this variable on the class!
    return Single

全文在这里

实际上涉及的另一种方法__new__是使用类方法:

class Singleton(object):
    __initialized = False

    def __new__(cls, *args, **kwargs):
        if not cls.__initialized:
            cls.__init__(*args, **kwargs)
            cls.__initialized = True
        return cls


class MyClass(Singleton):
    @classmethod
    def __init__(cls, x, y):
        print "init is here"

    @classmethod
    def do(cls):
        print "doing stuff"

请注意,通过这种方法,您需要用修饰所有方法@classmethod,因为您将永远不会使用的任何实际实例MyClass

When __new__ returns instance of the same class, __init__ is run afterwards on returned object. I.e. you can NOT use __new__ to prevent __init__ from being run. Even if you return previously created object from __new__, it will be double (triple, etc…) initialized by __init__ again and again.

Here is the generic approach to Singleton pattern which extends vartec answer above and fixes it:

def SingletonClass(cls):
    class Single(cls):
        __doc__ = cls.__doc__
        _initialized = False
        _instance = None

        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
            return cls._instance

        def __init__(self, *args, **kwargs):
            if self._initialized:
                return
            super(Single, self).__init__(*args, **kwargs)
            self.__class__._initialized = True  # Its crucial to set this variable on the class!
    return Single

Full story is here.

Another approach, which in fact involves __new__ is to use classmethods:

class Singleton(object):
    __initialized = False

    def __new__(cls, *args, **kwargs):
        if not cls.__initialized:
            cls.__init__(*args, **kwargs)
            cls.__initialized = True
        return cls


class MyClass(Singleton):
    @classmethod
    def __init__(cls, x, y):
        print "init is here"

    @classmethod
    def do(cls):
        print "doing stuff"

Please pay attention, that with this approach you need to decorate ALL of your methods with @classmethod, because you’ll never use any real instance of MyClass.


回答 7

参考此文档

当对不可变的内置类型(例如数字和字符串)进行子类化时,有时在其他情况下,可以使用new静态方法。new是实例构造的第一步,在init之前调用。

方法被称为与类作为第一个参数; 它的责任是返回该类的新实例。

将此与init进行比较:init是使用实例作为其第一个参数调用的,它不返回任何内容;它的责任是初始化实例。

在某些情况下,无需调用init即可创建新实例(例如,从泡菜中加载实例时)。如果不调用new,就无法创建新实例(尽管在某些情况下,可以通过调用基类的new来摆脱困境)。

关于您希望实现的目标,在有关Singleton模式的相同文档信息中也有

class Singleton(object):
        def __new__(cls, *args, **kwds):
            it = cls.__dict__.get("__it__")
            if it is not None:
                return it
            cls.__it__ = it = object.__new__(cls)
            it.init(*args, **kwds)
            return it
        def init(self, *args, **kwds):
            pass

您也可以使用装饰器使用PEP 318中的此实现

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
...

Referring to this doc:

When subclassing immutable built-in types like numbers and strings, and occasionally in other situations, the static method new comes in handy. new is the first step in instance construction, invoked before init.

The new method is called with the class as its first argument; its responsibility is to return a new instance of that class.

Compare this to init: init is called with an instance as its first argument, and it doesn’t return anything; its responsibility is to initialize the instance.

There are situations where a new instance is created without calling init (for example when the instance is loaded from a pickle). There is no way to create a new instance without calling new (although in some cases you can get away with calling a base class’s new).

Regarding what you wish to achieve, there also in same doc info about Singleton pattern

class Singleton(object):
        def __new__(cls, *args, **kwds):
            it = cls.__dict__.get("__it__")
            if it is not None:
                return it
            cls.__it__ = it = object.__new__(cls)
            it.init(*args, **kwds)
            return it
        def init(self, *args, **kwds):
            pass

you may also use this implementation from PEP 318, using a decorator

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
...

回答 8

class M(type):
    _dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print 'EXISTS'
            return cls._dict[key]
        else:
            print 'NEW'
            instance = super(M, cls).__call__(key)
            cls._dict[key] = instance
            return instance

class A(object):
    __metaclass__ = M

    def __init__(self, key):
        print 'INIT'
        self.key = key
        print

a1 = A('aaa')
a2 = A('bbb')
a3 = A('aaa')

输出:

NEW
INIT

NEW
INIT

EXISTS

NB作为一个副作用M._dict属性会自动变成可触及AA._dict所以要小心不要顺带覆盖它。

class M(type):
    _dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print 'EXISTS'
            return cls._dict[key]
        else:
            print 'NEW'
            instance = super(M, cls).__call__(key)
            cls._dict[key] = instance
            return instance

class A(object):
    __metaclass__ = M

    def __init__(self, key):
        print 'INIT'
        self.key = key
        print

a1 = A('aaa')
a2 = A('bbb')
a3 = A('aaa')

outputs:

NEW
INIT

NEW
INIT

EXISTS

NB As a side effect M._dict property automatically becomes accessible from A as A._dict so take care not to overwrite it incidentally.


回答 9

__new__应该返回一个类的新的空白实例。然后调用__init__初始化该实例。您不是在__new__的“ NEW”情况下调用__init__,因此正在为您调用它。所调用的代码__new__无法跟踪是否已在特定实例上调用__init__,也不会跟踪它,因为您在这里做的事情很不寻常。

您可以在__init__函数中向该对象添加一个属性,以指示它已被初始化。首先检查该属性是否存在,如果已存在,请不要继续进行。

__new__ should return a new, blank instance of a class. __init__ is then called to initialise that instance. You’re not calling __init__ in the “NEW” case of __new__, so it’s being called for you. The code that is calling __new__ doesn’t keep track of whether __init__ has been called on a particular instance or not nor should it, because you’re doing something very unusual here.

You could add an attribute to the object in the __init__ function to indicate that it’s been initialised. Check for the existence of that attribute as the first thing in __init__ and don’t proceed any further if it has been.


回答 10

对@AntonyHatchkins答案的更新,您可能希望为元类型的每个类提供单独的实例字典,这意味着您应__init__在元类中使用一个方法使用该字典初始化您的类对象,而不是使它在所有类中都为全局对象。

class MetaQuasiSingleton(type):
    def __init__(cls, name, bases, attibutes):
        cls._dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print('EXISTS')
            instance = cls._dict[key]
        else:
            print('NEW')
            instance = super().__call__(key)
            cls._dict[key] = instance
        return instance

class A(metaclass=MetaQuasiSingleton):
    def __init__(self, key):
        print 'INIT'
        self.key = key
        print()

我继续使用一种__init__方法更新了原始代码,并将语法更改为Python 3表示法(super类参数中的no-arg调用和metaclass而不是作为属性)。

无论哪种方式,最重要的一点是,你的类初始化函数(__call__方法)将不会执行任何__new__或者__init__如果键被找到。这比使用干净得多__new__,如果要跳过默认__init__步骤,使用标记您需要标记该对象。

An update to @AntonyHatchkins answer, you probably want a separate dictionary of instances for each class of the metatype, meaning that you should have an __init__ method in the metaclass to initialize your class object with that dictionary instead of making it global across all the classes.

class MetaQuasiSingleton(type):
    def __init__(cls, name, bases, attibutes):
        cls._dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print('EXISTS')
            instance = cls._dict[key]
        else:
            print('NEW')
            instance = super().__call__(key)
            cls._dict[key] = instance
        return instance

class A(metaclass=MetaQuasiSingleton):
    def __init__(self, key):
        print 'INIT'
        self.key = key
        print()

I have gone ahead and updated the original code with an __init__ method and changed the syntax to Python 3 notation (no-arg call to super and metaclass in the class arguments instead of as an attribute).

Either way, the important point here is that your class initializer (__call__ method) will not execute either __new__ or __init__ if the key is found. This is much cleaner than using __new__, which requires you to mark the object if you want to skip the default __init__ step.


回答 11

深入了解这一点!

CPython中泛型类的类型为type,其基类为Object(除非您明确定义另一个基类,如元类)。低级呼叫的顺序可以在这里找到。所谓的第一种方法是type_call,然后调用tp_new,然后tp_init

这里有趣的部分是tp_new将调用Object的(基类)new方法object_new,该方法执行tp_allocPyType_GenericAlloc)为对象分配内存的方法:)

那时在内存中创建对象,然后__init__调用该方法。如果__init__未在您的类中实现,则将object_init调用gets并且不执行任何操作:)

然后type_call只返回绑定到变量的对象。

Digging little deeper into that!

The type of a generic class in CPython is type and its base class is Object (Unless you explicitly define another base class like a metaclass). The sequence of low level calls can be found here. The first method called is the type_call which then calls tp_new and then tp_init.

The interesting part here is that tp_new will call the Object‘s (base class) new method object_new which does a tp_alloc (PyType_GenericAlloc) which allocates the memory for the object :)

At that point the object is created in memory and then the __init__ method gets called. If __init__ is not implemented in your class then the object_init gets called and it does nothing :)

Then type_call just returns the object which binds to your variable.


回答 12

应该将其__init__视为传统OO语言中的一种简单构造函数。例如,如果您熟悉Java或C ++,则向构造函数隐式传递一个指向其自身实例的指针。对于Java,它是this变量。如果要检查为Java生成的字节码,则有人会注意到有两个调用。第一个调用是对“ new”方法的调用,然后下一个调用是对init方法的调用(这是对用户定义的构造函数的实际调用)。通过两步过程,可以在调用类的构造方法(该实例的另一个方法)之前创建实际实例。

现在,对于Python,__new__是用户可以访问的附加功能。Java由于其类型性质而没有提供这种灵活性。如果一种语言提供了该功能,那么的实现者__new__可以在返回实例之前用该方法做很多事情,包括在某些情况下创建不相关对象的全新实例。而且,这种方法对于Python尤其适用于不可变类型也很有效。

One should look at __init__ as a simple constructor in traditional OO languages. For example, if you are familiar with Java or C++, the constructor is passed a pointer to its own instance implicitly. In the case of Java, it is the this variable. If one were to inspect the byte code generated for Java, one would notice two calls. The first call is to an “new” method, and then next call is to the init method (which is the actual call to the user defined constructor). This two step process enables creation of the actual instance before calling the constructor method of the class which is just another method of that instance.

Now, in the case of Python, __new__ is a added facility that is accessible to the user. Java does not provide that flexibility, due to its typed nature. If a language provided that facility, then the implementor of __new__ could do many things in that method before returning the instance, including creating a totally new instance of a unrelated object in some cases. And, this approach also works out well for especially for immutable types in the case of Python.


回答 13

但是,对于为什么__init__总是被称为after ,我有点困惑__new__

我认为C ++类比在这里会很有用:

  1. __new__只需为对象分配内存。一个对象的实例变量需要内存来保存它,这就是该步骤__new__要做的。

  2. __init__ 将对象的内部变量初始化为特定值(可以是默认值)。

However, I’m a bit confused as to why __init__ is always called after __new__.

I think the C++ analogy would be useful here:

  1. __new__ simply allocates memory for the object. The instance variables of an object needs memory to hold it, and this is what the step __new__ would do.

  2. __init__ initialize the internal variables of the object to specific values (could be default).


回答 14

__init__经过被称为__new__所以,当你在子类中重写它,你添加的代码仍然会被调用。

如果您尝试对已经具有a的类进行子类化,则__new__对此一无所知的人可能会先改编__init__并将调用向下转发到子类__init__。这种呼叫__init__后的约定__new__有助于按预期工作。

__init__仍然需要允许超任何参数__new__需要的,但不这样做通常会建立一个清晰的运行时错误。并且__new__可能应该明确允许*args和’** kw’,以明确表示扩展名是可以的。

这是普遍不好的形式既有__new____init__在继承同级别在同一个Class,因为原来的海报中描述的行为。

The __init__ is called after __new__ so that when you override it in a subclass, your added code will still get called.

If you are trying to subclass a class that already has a __new__, someone unaware of this might start by adapting the __init__ and forwarding the call down to the subclass __init__. This convention of calling __init__ after __new__ helps that work as expected.

The __init__ still needs to allow for any parameters the superclass __new__ needed, but failing to do so will usually create a clear runtime error. And the __new__ should probably explicitly allow for *args and ‘**kw’, to make it clear that extension is OK.

It is generally bad form to have both __new__ and __init__ in the same class at the same level of inheritance, because of the behavior the original poster described.


回答 15

但是,对于为什么__init__总是被称为after ,我有点困惑__new__

除了这样做是没有其他原因的。__new__没有初始化类的责任,其他方法有责任(__call__,可能-我不确定)。

我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放入__new__hack之外)。

你可以有__init__做什么,如果它已经被初始化,或者你可以写一个新的一个新的元类__call__,只有调用__init__新的实例,否则直接返回__new__(...)

However, I’m a bit confused as to why __init__ is always called after __new__.

Not much of a reason other than that it just is done that way. __new__ doesn’t have the responsibility of initializing the class, some other method does (__call__, possibly– I don’t know for sure).

I wasn’t expecting this. Can anyone tell me why this is happening and how I implement this functionality otherwise? (apart from putting the implementation into the __new__ which feels quite hacky).

You could have __init__ do nothing if it’s already been initialized, or you could write a new metaclass with a new __call__ that only calls __init__ on new instances, and otherwise just returns __new__(...).


回答 16

原因很简单,函数用于创建实例,而init用于初始化实例。在初始化之前,应先创建实例。这就是为什么应该在init之前调用new的原因。

The simple reason is that the new is used for creating an instance, while init is used for initializing the instance. Before initializing, the instance should be created first. That’s why new should be called before init.


回答 17

现在我遇到了同样的问题,由于某些原因,我决定避免使用装饰器,工厂和元类。我这样做是这样的:

主文件

def _alt(func):
    import functools
    @functools.wraps(func)
    def init(self, *p, **k):
        if hasattr(self, "parent_initialized"):
            return
        else:
            self.parent_initialized = True
            func(self, *p, **k)

    return init


class Parent:
    # Empty dictionary, shouldn't ever be filled with anything else
    parent_cache = {}

    def __new__(cls, n, *args, **kwargs):

        # Checks if object with this ID (n) has been created
        if n in cls.parent_cache:

            # It was, return it
            return cls.parent_cache[n]

        else:

            # Check if it was modified by this function
            if not hasattr(cls, "parent_modified"):
                # Add the attribute
                cls.parent_modified = True
                cls.parent_cache = {}

                # Apply it
                cls.__init__ = _alt(cls.__init__)

            # Get the instance
            obj = super().__new__(cls)

            # Push it to cache
            cls.parent_cache[n] = obj

            # Return it
            return obj

示例类

class A(Parent):

    def __init__(self, n):
        print("A.__init__", n)


class B(Parent):

    def __init__(self, n):
        print("B.__init__", n)

正在使用

>>> A(1)
A.__init__ 1  # First A(1) initialized 
<__main__.A object at 0x000001A73A4A2E48>
>>> A(1)      # Returned previous A(1)
<__main__.A object at 0x000001A73A4A2E48>
>>> A(2)
A.__init__ 2  # First A(2) initialized
<__main__.A object at 0x000001A7395D9C88>
>>> B(2)
B.__init__ 2  # B class doesn't collide with A, thanks to separate cache
<__main__.B object at 0x000001A73951B080>
  • 警告:您不应该初始化Parent,它与其他类发生冲突-除非您在每个子代中都定义了单独的缓存,否则这不是我们想要的。
  • 警告:父辈的祖父母类看起来很奇怪。[未验证]

在线尝试!

Now I’ve got the same problem, and for some reasons I decided to avoid decorators, factories and metaclasses. I did it like this:

Main file

def _alt(func):
    import functools
    @functools.wraps(func)
    def init(self, *p, **k):
        if hasattr(self, "parent_initialized"):
            return
        else:
            self.parent_initialized = True
            func(self, *p, **k)

    return init


class Parent:
    # Empty dictionary, shouldn't ever be filled with anything else
    parent_cache = {}

    def __new__(cls, n, *args, **kwargs):

        # Checks if object with this ID (n) has been created
        if n in cls.parent_cache:

            # It was, return it
            return cls.parent_cache[n]

        else:

            # Check if it was modified by this function
            if not hasattr(cls, "parent_modified"):
                # Add the attribute
                cls.parent_modified = True
                cls.parent_cache = {}

                # Apply it
                cls.__init__ = _alt(cls.__init__)

            # Get the instance
            obj = super().__new__(cls)

            # Push it to cache
            cls.parent_cache[n] = obj

            # Return it
            return obj

Example classes

class A(Parent):

    def __init__(self, n):
        print("A.__init__", n)


class B(Parent):

    def __init__(self, n):
        print("B.__init__", n)

In use

>>> A(1)
A.__init__ 1  # First A(1) initialized 
<__main__.A object at 0x000001A73A4A2E48>
>>> A(1)      # Returned previous A(1)
<__main__.A object at 0x000001A73A4A2E48>
>>> A(2)
A.__init__ 2  # First A(2) initialized
<__main__.A object at 0x000001A7395D9C88>
>>> B(2)
B.__init__ 2  # B class doesn't collide with A, thanks to separate cache
<__main__.B object at 0x000001A73951B080>
  • Warning: You shouldn’t initialize Parent, it will collide with other classes – unless you defined separate cache in each of the children, that’s not what we want.
  • Warning: It seems a class with Parent as grandparent behaves weird. [Unverified]

Try it online!


使用pip找不到TensorFlow

问题:使用pip找不到TensorFlow

我正在尝试使用pip安装TensorFlow:

$ pip install tensorflow --user
Collecting tensorflow
Could not find a version that satisfies the requirement tensorflow (from versions: )
No matching distribution found for tensorflow

我究竟做错了什么?到目前为止,我使用Python和pip都没有问题。

I’m trying to intstall TensorFlow using pip:

$ pip install tensorflow --user
Collecting tensorflow
Could not find a version that satisfies the requirement tensorflow (from versions: )
No matching distribution found for tensorflow

What am I doing wrong? So far I’ve used Python and pip with no issues.


回答 0

我发现这终于奏效了。

python3 -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.12.0-py3-none-any.whl

编辑1:已在Windows(8、8.1、10),Mac和Linux上进行了测试。更改python3python根据您的配置。如果使用的是Python 2.x,请更改py3py2url。

编辑2:如果有人需要,列出不同版本:https : //storage.googleapis.com/tensorflow

编辑3:可用车轮包装的URL列表在此处:https : //www.tensorflow.org/install/pip#package-location

I found this to finally work.

python3 -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.12.0-py3-none-any.whl

Edit 1: This was tested on Windows (8, 8.1, 10), Mac and Linux. Change python3 to python according to your configuration. Change py3 to py2 in the url if you are using Python 2.x.

Edit 2: A list of different versions if someone needs: https://storage.googleapis.com/tensorflow

Edit 3: A list of urls for the available wheel packages is available here: https://www.tensorflow.org/install/pip#package-location


回答 1

您需要Python的64位版本,而您使用的是32位版本。到目前为止,Tensorflow仅64-bit versions of Python 3.5.x and 3.6.x在Windows上支持。请参阅安装文档以了解当前支持什么

要检查您正在运行的Python版本,请键入pythonpython3启动解释器,然后键入import struct;print(struct.calcsize("P") * 8)和将打印3264告诉您您正在运行的Python版本。

来自评论:

要下载适用于Windows的其他版本的Python,请访问python.org/downloads/windows并向下滚动,直到看到所需的版本以“ 64”结尾。那将是应该与tensorflow一起使用的64位版本

You need a 64-bit version of Python and in your case are using a 32-bit version. As of now Tensorflow only supports 64-bit versions of Python 3.5.x and 3.6.x on Windows. See the install docs to see what is currently supported

To check which version of Python you are running, type python or python3 to start the interpreter, and then type import struct;print(struct.calcsize("P") * 8) and that will print either 32 or 64 to tell you which bit version of Python you are running.

From comments:

To download a different version of Python for Windows, go to python.org/downloads/windows and scroll down until you see the version you want that ends in a “64”. That will be the 64 bit version that should work with tensorflow


回答 2

您需要使用正确版本的Python和 pip

在Windows 10(使用Python 3.6.X版本)上,我经过仔细检查后面临着相同的问题,然后发现我在64位计算机上安装了Python-32位。记住TensorFlow 仅与 python的64位安装兼容不是32位的Python

图片

如果我们从python.org下载Python,则默认安装为32位。因此,我们必须手动下载64位安装程序才能安装Python 64位。然后将以下内容添加到PATH环境中。

C:\Users\AppData\Local\Programs\Python\Python36
C:\Users\AppData\Local\Programs\Python\Python36\Scripts

然后gpupdate /Force在命令提示符下运行。如果python命令不适用于64位,请重新启动计算机。

然后在命令提示符下运行python。它应该显示64位

C:\Users\YOURNAME>python
Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

然后运行以下命令以安装tensorflow CPU版本(推荐)

pip3 install --upgrade tensorflow

更新-Python 3.7

目前仅正式支持Python 3.5和Python 3.6。Tensorflow尚未正式发布Python 3.7的二进制文件,我们可能需要稍等片刻才能发布它。您可以暂时使用Python 3.6.x或具有Python <3.7虚拟环境的Anaconda。

You need to use right version of Python and pip

On Windows 10, with Python 3.6.X version I was facing same then after checking deliberately , I noticed I had Python-32 bit installation on my 64 bit machine. Remember TensorFlow is only compatible with 64bit installation of python. Not 32 bit of Python

Image

If we download Python from python.org , the default installation would be 32 bit. So we have to download 64 bit installer manually to install Python 64 bit. And then add below to PATH environment.

C:\Users\AppData\Local\Programs\Python\Python36
C:\Users\AppData\Local\Programs\Python\Python36\Scripts

Then run gpupdate /Force on command prompt. If python command doesnt work for 64 bit restart your machine.

Then run python on command prompt. It should show 64 bit

C:\Users\YOURNAME>python
Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

Then run below command to install tensorflow CPU version(recommended)

pip3 install --upgrade tensorflow

Update – Python 3.7

Currently only Python 3.5 and Python 3.6 are supported officially. Tensorflow has not released binaries for Python 3.7 still officially, we might need to wait a little for it to be released. You can use Python 3.6.x alongside or Anaconda with Python<3.7 virtual environment for time being.


回答 3

从tensorflow网站:“您将需要pip版本8.1或更高版本,以下命令才能工作”。运行以下命令以升级您的pip,然后尝试再次安装tensorflow:

pip install --upgrade pip

From tensorflow website: “You will need pip version 8.1 or later for the following commands to work”. Run this command to upgrade your pip, then try install tensorflow again:

pip install --upgrade pip

回答 4

如果您尝试将其安装在Windows计算机上,则需要安装64位版本的python 3.5。这是实际安装它的唯一方法。从网站

TensorFlow在Windows上仅支持64位Python 3.5。我们已经使用以下Python发行版对pip包进行了测试:

Anaconda的Python 3.5

来自python.org的Python 3.5。

您可以从此处下载正确版本的python (确保您抓住显示“ Windows x86-64”的版本之一)

现在,您应该可以使用pip install tensorflow或进行安装python -m pip install tensorflow(如果同时安装了python2和python3,请确保使用的是来自python3的正确点子)

请记住要安装Anaconda 3-5.2.0,因为3-5.3.0的最新版本具有Tensorflow不支持的python 3.7版本。

If you are trying to install it on a windows machine you need to have a 64-bit version of python 3.5. This is the only way to actually install it. From the website:

TensorFlow supports only 64-bit Python 3.5 on Windows. We have tested the pip packages with the following distributions of Python:

Python 3.5 from Anaconda

Python 3.5 from python.org.

You can download the proper version of python from here (make sure you grab one of the ones that says “Windows x86-64”)

You should now be able to install with pip install tensorflow or python -m pip install tensorflow (make sure that you are using the right pip, from python3, if you have both python2 and python3 installed)

Remember to install Anaconda 3-5.2.0 as the latest version which is 3-5.3.0 have python version 3.7 which is not supported by Tensorflow.


回答 5

我发现TensorFlow 1.12.0仅适用于Python版本3.5.2。我有Python 3.7,但没有用。因此,我不得不降级Python,然后可以安装TensorFlow使其工作。

要将python版本从3.7降级到3.6

conda install python=3.6.8

I figured out that TensorFlow 1.12.0 only works with Python version 3.5.2. I had Python 3.7 but that didn’t work. So, I had to downgrade Python and then I could install TensorFlow to make it work.

To downgrade your python version from 3.7 to 3.6

conda install python=3.6.8

回答 6

2016年11月28日更新:从0.12版开始,PyPI中现已提供TensorFlow。您可以输入

pip install tensorflow

…要么…

pip install tensorflow-gpu

…分别安装仅CPU或GPU加速的TensorFlow版本。


先前的答案: TensorFlow尚未存在于PyPI存储库中,因此您必须为操作系统和Python版本指定适当的“ wheel文件”的URL。

TensorFlow网站上列出了受支持的配置的完整列表,但是例如,要仅使用CPU在Linux上为Python 2.7安装版本0.10,您可以键入以下命令:

$ pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl

Updated 11/28/2016: TensorFlow is now available in PyPI, starting with release 0.12. You can type

pip install tensorflow

…or…

pip install tensorflow-gpu

…to install the CPU-only or GPU-accelerated version of TensorFlow respectively.


Previous answer: TensorFlow is not yet in the PyPI repository, so you have to specify the URL to the appropriate “wheel file” for your operating system and Python version.

The full list of supported configurations is listed on the TensorFlow website, but for example, to install version 0.10 for Python 2.7 on Linux, using CPU only, you would type the following command:

$ pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl

回答 7

在此处安装Python 3.5.x 64位AMD版本。确保将Python添加到PATH变量中。然后打开命令提示符并键入

python -m pip install --upgrade pip

应该给您以下结果:

 Collecting pip
 Using cached pip-9.0.1-py2.py3-none-any.whl
 Installing collected packages: pip
 Found existing installation: pip 7.1.2
 Uninstalling pip-7.1.2:
 Successfully uninstalled pip-7.1.2
 Successfully installed pip-9.0.1

现在输入

 pip3 install --upgrade tensorflow

Install Python 3.5.x 64 bit amd version here. Make sure you add Python to your PATH variable. Then open a command prompt and type

python -m pip install --upgrade pip

should give you the following result :

 Collecting pip
 Using cached pip-9.0.1-py2.py3-none-any.whl
 Installing collected packages: pip
 Found existing installation: pip 7.1.2
 Uninstalling pip-7.1.2:
 Successfully uninstalled pip-7.1.2
 Successfully installed pip-9.0.1

Now type

 pip3 install --upgrade tensorflow

回答 8

我有同样的问题,并解决了这个问题:

# Ubuntu/Linux 64-bit, CPU only, Python 2.7
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.1-cp27-none-linux_x86_64.whl

# Ubuntu/Linux 64-bit, GPU enabled, Python 2.7
# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.

# Mac OS X, CPU only, Python 2.7:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py2-none-any.whl

# Mac OS X, GPU enabled, Python 2.7:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow_gpu-0.12.1-py2-none-any.whl

# Ubuntu/Linux 64-bit, CPU only, Python 3.4
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.1-cp34-cp34m-linux_x86_64.whl

# Ubuntu/Linux 64-bit, GPU enabled, Python 3.4
# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp34-cp34m-linux_x86_64.whl

# Ubuntu/Linux 64-bit, CPU only, Python 3.5
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.1-cp35-cp35m-linux_x86_64.whl

# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp35-cp35m-linux_x86_64.whl

# Mac OS X, CPU only, Python 3.4 or 3.5:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py3-none-any.whl

# Mac OS X, GPU enabled, Python 3.4 or 3.5:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow_gpu-0.12.1-py3-none-any.whl

加:

# Python 2
(tensorflow)$ pip install --upgrade $TF_BINARY_URL

# Python 3
(tensorflow)$ pip3 install --upgrade $TF_BINARY_URL

Docs上找到。

更新!

新版本的新链接

例如,要在OSX中安装tensorflow v1.0.0,您需要使用:

https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.0.0-py2-none-any.whl

代替

https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py2-none-any.whl

I had the same problem and solved with this:

# Ubuntu/Linux 64-bit, CPU only, Python 2.7
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.1-cp27-none-linux_x86_64.whl

# Ubuntu/Linux 64-bit, GPU enabled, Python 2.7
# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.

# Mac OS X, CPU only, Python 2.7:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py2-none-any.whl

# Mac OS X, GPU enabled, Python 2.7:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow_gpu-0.12.1-py2-none-any.whl

# Ubuntu/Linux 64-bit, CPU only, Python 3.4
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.1-cp34-cp34m-linux_x86_64.whl

# Ubuntu/Linux 64-bit, GPU enabled, Python 3.4
# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp34-cp34m-linux_x86_64.whl

# Ubuntu/Linux 64-bit, CPU only, Python 3.5
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.1-cp35-cp35m-linux_x86_64.whl

# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp35-cp35m-linux_x86_64.whl

# Mac OS X, CPU only, Python 3.4 or 3.5:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py3-none-any.whl

# Mac OS X, GPU enabled, Python 3.4 or 3.5:
(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow_gpu-0.12.1-py3-none-any.whl

Plus:

# Python 2
(tensorflow)$ pip install --upgrade $TF_BINARY_URL

# Python 3
(tensorflow)$ pip3 install --upgrade $TF_BINARY_URL

Found on Docs.

UPDATE!

There are new links for new versions

For example, for installing tensorflow v1.0.0 in OSX you need to use:

https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.0.0-py2-none-any.whl

instead of

https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py2-none-any.whl

回答 9

尝试在Mac上安装(使用Python 2.7)时出现相同的错误。根据Yash Kumar Verma在此页面上给出的不同答案,与我在此处提供的解决方案类似的解决方案似乎也适用于Windows 8.1上的Python 3。

步骤1:前往TensorFlow安装页面的TensorFlow Python软件包的URL部分,并复制与您的Python安装相关的链接的URL。

步骤2:打开终端/命令提示符并运行以下命令:
pip install --upgrade [paste copied url link here]

所以对我来说是这样的:
pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.2.0-py2-none-any.whl

更新(2017年7月21日):我与其他在运行Windows 3.6且使用Python 3.6的计算机上进行了尝试,他们不得不将步骤2中的行更改为: python -m pip install [paste copied url link here]

更新(2018年7月26日):对于Python 3.6.2(不是3.7,因为它在TF文档中的3.6.2中),您也可以pip3 install --upgrade [paste copied URL here]步骤2中使用。

I had the same error when trying to install on my Mac (using Python 2.7). A similar solution to the one I’m giving here also seemed to work for Python 3 on Windows 8.1 according to a different answer on this page by Yash Kumar Verma

Solution

Step 1: go to The URL of the TensorFlow Python package section of the TensorFlow installation page and copy the URL of the relevant link for your Python installation.

Step 2: open a terminal/command prompt and run the following command:
pip install --upgrade [paste copied url link here]

So for me it was the following:
pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.2.0-py2-none-any.whl

Update (July 21 2017): I tried this with some others who were running on Windows machines with Python 3.6 and they had to change the line in Step 2 to: python -m pip install [paste copied url link here]

Update (26 July 2018): For Python 3.6.2 (not 3.7 because it’s in 3.6.2 in TF Documentation), you can also use pip3 install --upgrade [paste copied URL here] in Step 2.


回答 10

试试这个,它应该可以工作:

 python.exe -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

Try this, it should work:

 python.exe -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

回答 11

尝试这个:

export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py3-none-any.whl
pip3 install --upgrade $TF_BINARY_URL

来源:https//www.tensorflow.org/get_started/os_setup(页面不再存在)

更新2/23/17 文档已移至:https : //www.tensorflow.org/install

Try this:

export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.1-py3-none-any.whl
pip3 install --upgrade $TF_BINARY_URL

Source: https://www.tensorflow.org/get_started/os_setup (page no longer exists)

Update 2/23/17 Documentation moved to: https://www.tensorflow.org/install


回答 12

  1. 通过选中将Python添加到路径来安装python
  2. pip3 install –upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

这适用于Windows 10.0

  1. Install python by checking Add Python to Path
  2. pip3 install –upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

This works for windows 10.0


回答 13

如果您最近遇到过此问题(例如,在2018年发布Python 3.7之后),则很可能是由于tensorflow方面缺少Python 3.7支持所致。如果您不介意,请尝试使用Python 3.6。您可以从https://github.com/tensorflow/tensorflow/issues/20444中找到一些技巧,但使用这些技巧需要您自担风险。我使用了建议的一个竖琴-首先下载了适用于Python 3.6的tensorflow轮,然后手动将其重命名…

cp tensorflow-1.11.0-cp36-cp36m-linux_x86_64.whl tensorflow-1.11.0-cp37-cp37m-linux_x86_64.whl
pip install tensorflow-1.11.0-cp37-cp37m-linux_x86_64.whl

好消息是已经有对3.7支持的请求。希望它将尽快发布。

If you run into this issue recently (say, after Python 3.7 release in 2018), most likely this is caused by the lack of Python 3.7 support (yet) from the tensorflow side. Try using Python 3.6 instead if you don’t mind. There are some tricks you can find from https://github.com/tensorflow/tensorflow/issues/20444, but use them at your own risk. I used the one harpone suggested – first downloaded the tensorflow wheel for Python 3.6 and then renamed it manually…

cp tensorflow-1.11.0-cp36-cp36m-linux_x86_64.whl tensorflow-1.11.0-cp37-cp37m-linux_x86_64.whl
pip install tensorflow-1.11.0-cp37-cp37m-linux_x86_64.whl

The good news is that there is a pull request for 3.7 support already. Hope it will be released soon.


回答 14

我有同样的问题。在卸载了32位版本的python并重新安装了64位版本之后,我尝试重新安装TensorFlow并成功了。

链接到TensorFlow指南:https ://www.tensorflow.org/install/install_windows

I had the same problem. After uninstalling the 32-bit version of python and reinstalling the 64-bit version I tried reinstalling TensorFlow and it worked.

Link to TensorFlow guide: https://www.tensorflow.org/install/install_windows


回答 15

如果您试图在anaconda中安装tensorflow并且它无法正常工作,则您可能需要降级python版本,因为只有3.6.xanaconda具有最新版本时才支持python 版本。

  1. 检查python版本: python --version

  2. 如果版本>,3.6.x然后执行步骤3,否则请停止,问题可能出在其他地方

  3. conda search python

  4. conda install python=3.6.6

  5. 再次检查版本: python --version

  6. 如果版本正确,请安装tensorflow(步骤7)

  7. pip install tensorflow

If you’re trying to install tensorflow in anaconda and it isn’t working, then you may need to downgrade python version because only 3.6.x is currently supported while anaconda has the latest version.

  1. check python version: python --version

  2. if version > 3.6.x then follow step 3, otherwise stop, the problem may be somewhere else

  3. conda search python

  4. conda install python=3.6.6

  5. Check version again: python --version

  6. If version is correct, install tensorflow (step 7)

  7. pip install tensorflow


回答 16

如果您正在使用Anaconda Python安装,pip install tensorflow将给出上述错误,如下所示:

Collecting tensorflow
Could not find a version that satisfies the requirement tensorflow (from versions: )
No matching distribution found for tensorflow

根据TensorFlow安装页面,--ignore-installed在运行pip install时需要使用该标志。

但是,在执行此操作之前,请先查看此链接, 以确保相对于希望安装的TensorFlow所需版本正确设置了TF_BINARY_URL变量。

If you are using the Anaconda Python installation, pip install tensorflow will give the error stated above, shown below:

Collecting tensorflow
Could not find a version that satisfies the requirement tensorflow (from versions: )
No matching distribution found for tensorflow

According to the TensorFlow installation page, you will need to use the --ignore-installed flag when running pip install.

However, before this can be done see this link to ensure the TF_BINARY_URL variable is set correctly in relation to the desired version of TensorFlow that you wish to install.


回答 17

不幸的是,我的声誉是在@Sujoy答案下无法控制的。

他们在文档中声称支持python 3.6。@mayur提供的链接表明它们确实只是一个python3.5 wheel软件包。这是我尝试安装tensorflow:

Microsoft Windows [Version 10.0.16299.371]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\>python3 -m pip install --upgrade pip
Requirement already up-to-date: pip in d:\python\v3\lib\site-packages (10.0.0)

C:\>python3 -m pip -V
pip 10.0.0 from D:\Python\V3\lib\site-packages\pip (python 3.6)

C:\>python3 -m pip install --upgrade tensorflow
Collecting tensorflow
Could not find a version that satisfies the requirement tensorflow (from versions: )
No matching distribution found for tensorflow

而python 3.5似乎已成功安装。我希望看到一个python3.6版本,因为他们声称它也可以在python3.6上运行。

引用:

"TensorFlow supports Python 3.5.x and 3.6.x on Windows. Note that Python 3 comes with the pip3 package manager, which is the program you'll use to install TensorFlow."

来源:https : //www.tensorflow.org/install/install_windows

Python3.5安装:

Microsoft Windows [Version 10.0.16299.371]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\>python3 -m pip install --upgrade pip
Requirement already up-to-date: pip in d:\python\v3\lib\site-packages (10.0.0)

C:\>python3 -m pip -V
pip 10.0.0 from D:\Python\V3_5\lib\site-packages\pip (python 3.5.2)

C:\>python3 -m pip install --upgrade tensorflow
Collecting tensorflow
  Downloading 
    ....
    ....

我希望我在这里错得很厉害,但是如果不敲响警钟😛

编辑:有人下面的几篇文章指出以下命令将起作用,并且确实起作用。

python3 -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

奇怪的点不起作用🤔

Unfortunately my reputation is to low to command underneath @Sujoy answer.

In their docs they claim to support python 3.6. The link provided by @mayur shows that their is indeed only a python3.5 wheel package. This is my try to install tensorflow:

Microsoft Windows [Version 10.0.16299.371]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\>python3 -m pip install --upgrade pip
Requirement already up-to-date: pip in d:\python\v3\lib\site-packages (10.0.0)

C:\>python3 -m pip -V
pip 10.0.0 from D:\Python\V3\lib\site-packages\pip (python 3.6)

C:\>python3 -m pip install --upgrade tensorflow
Collecting tensorflow
Could not find a version that satisfies the requirement tensorflow (from versions: )
No matching distribution found for tensorflow

while python 3.5 seems to install successfully. I would love to see a python3.6 version since they claim it should also work on python3.6.

Quoted :

"TensorFlow supports Python 3.5.x and 3.6.x on Windows. Note that Python 3 comes with the pip3 package manager, which is the program you'll use to install TensorFlow."

Source : https://www.tensorflow.org/install/install_windows

Python3.5 install :

Microsoft Windows [Version 10.0.16299.371]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\>python3 -m pip install --upgrade pip
Requirement already up-to-date: pip in d:\python\v3\lib\site-packages (10.0.0)

C:\>python3 -m pip -V
pip 10.0.0 from D:\Python\V3_5\lib\site-packages\pip (python 3.5.2)

C:\>python3 -m pip install --upgrade tensorflow
Collecting tensorflow
  Downloading 
    ....
    ....

I hope i am terrible wrong here but if not ring a alarm bell 😛

Edit: A couple of posts below someone pointed out that the following command would work and it did.

python3 -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

Strange pip is not working 🤔


回答 18

在Mac OS X Yosemite 10.10.5上的Python 2.7中,这对我有用:

sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.5.0-py2-none-any.whl

This worked for me with Python 2.7 on Mac OS X Yosemite 10.10.5:

sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.5.0-py2-none-any.whl

回答 19

这个问题有多组答案。该答案旨在概括一组答案:

可能没有与您的Python版本兼容的TensorFlow版本。如果您正在使用新版本的Python,则尤其如此。例如,在新版本的Python发行与该版本的Python的TensorFlow发行之间可能会有延迟。

在这种情况下,我相信您的选择是:1)降级到Python的先前版本。2)从源代码编译TensorFlow。3)等待TensorFlow的匹配版本。

There are multiple groups of answers to this question. This answer aims to generalize one group of answers:

There may not be a version of TensorFlow that is compatible with your version of Python. This is particularly true if you’re using a new release of Python. For example, there may be a delay between the release of a new version of Python and the release of TensorFlow for that version of Python.

In this case, I believe your options are to: 1) Downgrade to the previous version of Python. 2) Compile TensorFlow from the source code. 3) Wait for a matching version of TensorFlow.


回答 20

对于Windows,这对我有用

从此链接下载车轮。然后从命令行导航到存在转轮的下载文件夹,只需键入以下命令-

pip install tensorflow-1.0.0-cp36-cp36m-win_amd64.whl

For windows this worked for me,

Download the wheel from this link. Then from command line navigate to your download folder where the wheel is present and simply type in the following command –

pip install tensorflow-1.0.0-cp36-cp36m-win_amd64.whl


回答 21

我面临着同样的问题。我尝试了以下方法,它奏效了。为Mac OS X安装,anaconda python 2.7

pip uninstall tensorflow export TF_BINARY_URL=<get the correct url from http://tflearn.org/installation/> pip install --upgrade $TF_BINARY_URL

安装了tensorflow-1.0.0

I was facing the same issue. I tried the following and it worked. installing for Mac OS X, anaconda python 2.7

pip uninstall tensorflow export TF_BINARY_URL=<get the correct url from http://tflearn.org/installation/> pip install --upgrade $TF_BINARY_URL

Installed tensorflow-1.0.0


回答 22

  1. 具有管理权限启动命令提示符
  2. 输入以下命令 python -m pip install --upgrade pip
  3. 下一步输入命令 pip install tensorflow
  1. Start Command Prompt with Administrative Permission
  2. Enter following command python -m pip install --upgrade pip
  3. Next Enter command pip install tensorflow

回答 23

下面是在Windows中安装TensorFlow的URL。对我来说很好。

python -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

The URL to install TensorFlow in Windows, below is the URL. It worked fine for me.

python -m pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl

回答 24

在Windows 10上,这里没有任何内容适合我。也许下面的更新解决方案对我有用。

python -m pip install --upgrade tensorflow

这在Windows 10上使用Python 3.6tensorflow 1.5

Nothing here worked for me on Windows 10. Perhaps an updated solution below that did work for me.

python -m pip install --upgrade tensorflow.

This is using Python 3.6 and tensorflow 1.5 on Windows 10


回答 25

对于pyCharm用户:

  1. 检查pip版本: pip3 -V
  2. 如果pip早于9.0.1: py -3 -m pip install –upgrade pip
  3. 然后:** py -3 -m pip install –upgrade

https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl **

For pyCharm users:

  1. Check pip version: pip3 -V
  2. If pip is older than 9.0.1: py -3 -m pip install –upgrade pip
  3. Then: **py -3 -m pip install –upgrade

https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.12.0-py3-none-any.whl**


回答 26

以下步骤允许您安装tensorflow和keras

  1. https://repo.anaconda.com/archive/下载python 3.6随附的Anaconda3-5.2.0
  2. 安装Anaconda并打开Anaconda Prompt并执行以下命令 conda install jupyter conda install scipy pip install sklearn pip install msgpack pip install pandas pip install pandas-datareader pip install matplotlib pip install pillow pip install requests pip install h5py pip install tensorflow pip install keras

Following steps allows you to install tensorflow and keras

  1. downloading Anaconda3-5.2.0 which comes with python 3.6 from https://repo.anaconda.com/archive/
  2. Install Anaconda and open Anaconda Prompt and execute below commands conda install jupyter conda install scipy pip install sklearn pip install msgpack pip install pandas pip install pandas-datareader pip install matplotlib pip install pillow pip install requests pip install h5py pip install tensorflow pip install keras

回答 27

2019年更新:要在Google Colab中安装TensorFlow 2预览版,可以使用:

!wget https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64 -O cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64.deb !dpkg -i cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64.deb !apt-key add /var/cuda-repo-10-0-local-10.0.130-410.48/7fa2af80.pub !apt-get update !apt-get install cuda !pip install tf-nightly-gpu-2.0-preview

对于安装TensorFlow 2 bye pip,您可以使用: pip install tf-nightly-gpu-2.0-preview用于GPU和 pip install tf-nightly-2.0-preview CPU。

update 2019: for install the preview version of TensorFlow 2 in Google Colab you can use:

!wget https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64 -O cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64.deb !dpkg -i cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64.deb !apt-key add /var/cuda-repo-10-0-local-10.0.130-410.48/7fa2af80.pub !apt-get update !apt-get install cuda !pip install tf-nightly-gpu-2.0-preview

and for install the TensorFlow 2 bye pip you can use : pip install tf-nightly-gpu-2.0-preview for GPU and pip install tf-nightly-2.0-preview for CPU.


回答 28

我在OSX Sierra 10.12.2上遇到了这个问题。原来我安装了错误的Python版本(我安装了Python 3.4,但OSX的tensorflow pypi软件包仅适用于python 3.5及更高版本)。

解决方案是安装Python 3.6。这是我为使其正常工作所做的。注意:我使用Homebrew来安装Python 3.6,您可以通过在python.org上使用Python 3.6安装程序来做同样的事情

brew uninstall python3
brew install python3
python3 --version # Verify that you see "Python 3.6.0"
pip install tensorflow # With python 3.6 the install succeeds
pip install jupyter # "ipython notebook" didn't work for me until I installed jupyter
ipython notebook # Finally works!

I had this problem on OSX Sierra 10.12.2. It turns out I had the wrong version of Python installed (I had Python 3.4 but tensorflow pypi packages for OSX are only for python 3.5 and up).

The solution was to install Python 3.6. Here’s what I did to get it working. Note: I used Homebrew to install Python 3.6, you could do the same by using the Python 3.6 installer on python.org

brew uninstall python3
brew install python3
python3 --version # Verify that you see "Python 3.6.0"
pip install tensorflow # With python 3.6 the install succeeds
pip install jupyter # "ipython notebook" didn't work for me until I installed jupyter
ipython notebook # Finally works!

回答 29

摘自tensorflow网站 https://www.tensorflow.org/install/install_windows

使用本机pip安装

如果您的计算机上未安装以下版本的Python,请立即安装:

python.org中的Python 3.5.x TensorFlow在Windows上仅支持Python的3.5.x版本。请注意,Python 3.5.x随附pip3软件包管理器,这是您将用于安装TensorFlow的程序。

要安装TensorFlow,请启动终端。然后在该终端中发出适当的pip3 install命令。要安装TensorFlow的仅CPU版本,请输入以下命令:

C:\> pip3 install --upgrade tensorflow
To install the GPU version of TensorFlow, enter the following command:

C:\> pip3 install --upgrade tensorflow-gpu

Excerpt from tensorflow website https://www.tensorflow.org/install/install_windows

Installing with native pip

If the following version of Python is not installed on your machine, install it now:

Python 3.5.x from python.org TensorFlow only supports version 3.5.x of Python on Windows. Note that Python 3.5.x comes with the pip3 package manager, which is the program you’ll use to install TensorFlow.

To install TensorFlow, start a terminal. Then issue the appropriate pip3 install command in that terminal. To install the CPU-only version of TensorFlow, enter the following command:

C:\> pip3 install --upgrade tensorflow
To install the GPU version of TensorFlow, enter the following command:

C:\> pip3 install --upgrade tensorflow-gpu

“ super”在Python中做什么?

问题:“ super”在Python中做什么?

之间有什么区别:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

和:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

我看到super在只有单一继承的类中经常使用它。我知道为什么您会在多重继承中使用它,但不清楚在这种情况下使用它的好处。

What’s the difference between:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

and:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

I’ve seen super being used quite a lot in classes with only single inheritance. I can see why you’d use it in multiple inheritance but am unclear as to what the advantages are of using it in this kind of situation.


回答 0

super()单一继承的好处很小-大多数情况下,您不必将基类的名称硬编码到使用其父方法的每个方法中。

但是,如果不使用,几乎不可能使用多重继承super()。这包括常见的惯用语,例如mixin,接口,抽象类等。这扩展到了以后扩展您的代码的代码。如果以后有人要编写扩展的类Child和mixin,则他们的代码将无法正常工作。

The benefits of super() in single-inheritance are minimal — mostly, you don’t have to hard-code the name of the base class into every method that uses its parent methods.

However, it’s almost impossible to use multiple-inheritance without super(). This includes common idioms like mixins, interfaces, abstract classes, etc. This extends to code that later extends yours. If somebody later wanted to write a class that extended Child and a mixin, their code would not work properly.


回答 1

有什么不同?

SomeBaseClass.__init__(self) 

表示呼叫SomeBaseClass的方式__init__。而

super(Child, self).__init__()

表示__init__Child实例的方法解析顺序(MRO)中遵循的父类调用绑定。

如果实例是Child的子类,则MRO中可能紧随其后的是另一个父级。

简单解释

当编写一个类时,您希望其他类能够使用它。super()使其他类更容易使用您正在编写的类。

正如鲍勃·马丁(Bob Martin)所说,好的架构可以使您尽可能长地推迟决策。

super() 可以实现这种架构。

当另一个类对您编写的类进行子类化时,它也可能继承自其他类。而这些类可以有一个__init__在此之后来自__init__基于类的进行方法解析顺序。

如果没有super您,可能会硬编码您正在编写的类的父级(如示例中所示)。这意味着您将不会__init__在MRO中调用下一个,因此您将无法重用其中的代码。

如果您正在编写自己的代码供个人使用,则可能不必担心这种区别。但是,如果您希望其他人使用您的代码,则使用super一件事可以为代码用户提供更大的灵活性。

Python 2与3

这适用于Python 2和3:

super(Child, self).__init__()

这仅适用于Python 3:

super().__init__()

它不带任何参数,方法是在堆栈框架中上移并获取方法的第一个参数(通常self用于实例方法或cls类方法-但可以是其他名称),然后Child在自由变量中找到类(例如)(__class__在方法中将其作为自由闭合变量的名称进行查找)。

我更喜欢演示使用的交叉兼容方式super,但是如果您仅使用Python 3,则可以不带任何参数调用它。

具有前向兼容性的间接

它给你什么?对于单继承,从静态分析的角度来看,问题的示例实际上是相同的。但是,使用super会为您提供具有向前兼容性的间接层。

前向兼容性对经验丰富的开发人员非常重要。您希望代码在更改时保持最少的更改。当您查看修订历史记录时,您希望确切地看到更改的时间。

您可以从单一继承开始,但是如果您决定添加另一个基类,则只需要更改基数行即可-如果基类在您继承的类中发生了变化(例如添加了mixin),则可以进行更改这个班没什么。特别是在Python 2中,super很难正确获取参数和正确的方法参数。如果您知道super正确地使用了单继承,那么调试就不会那么困难了。

依赖注入

其他人可以使用您的代码并将父级注入方法解析中:

class SomeBaseClass(object):
    def __init__(self):
        print('SomeBaseClass.__init__(self) called')

class UnsuperChild(SomeBaseClass):
    def __init__(self):
        print('UnsuperChild.__init__(self) called')
        SomeBaseClass.__init__(self)

class SuperChild(SomeBaseClass):
    def __init__(self):
        print('SuperChild.__init__(self) called')
        super(SuperChild, self).__init__()

假设您向对象添加了另一个类,并想在Foo和Bar之间注入一个类(出于测试或其他原因):

class InjectMe(SomeBaseClass):
    def __init__(self):
        print('InjectMe.__init__(self) called')
        super(InjectMe, self).__init__()

class UnsuperInjector(UnsuperChild, InjectMe): pass

class SuperInjector(SuperChild, InjectMe): pass

使用un-super子级无法注入依赖项,因为您正在使用的子级已经硬编码了要在其自身之后调用的方法:

>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called

但是,带有子级的类super可以正确注入依赖项:

>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called

发表评论

为什么这在世界上有用?

Python通过C3线性化算法将复杂的继承树线性化,以创建方法解析顺序(MRO)。

我们希望按该顺序查找方法。

对于在父级中定义的方法,如果不按顺序查找下一个方法super,则必须

  1. 从实例的类型获取mro
  2. 寻找定义方法的类型
  3. 用该方法找到下一个类型
  4. 绑定该方法并使用所需的参数调用它

UnsuperChild不该访问InjectMe。为什么没有“总是避免使用super” 的结论?我在这里想念什么?

UnsuperChild不会访问InjectMe。可以UnsuperInjector访问InjectMe-却无法从其继承的方法调用该类的方法UnsuperChild

两个Child类都打算使用MRO中紧随其后的相同名称来调用方法,这可能是它在创建时不知道的另一个类。

没有super硬编码其父方法的方法-因此限制了其方法的行为,并且子类无法在调用链中注入功能。

在一个 super具有更大的灵活性。这些方法的调用链可以被拦截并注入功能。

您可能不需要该功能,但是代码的子类却可能需要。

结论

始终使用super引用父类而不是对其进行硬编码。

您打算引用的是下一行的父类,而不是您看到子级继承的父类。

不使用super会给您的代码用户带来不必要的限制。

What’s the difference?

SomeBaseClass.__init__(self) 

means to call SomeBaseClass‘s __init__. while

super(Child, self).__init__()

means to call a bound __init__ from the parent class that follows Child in the instance’s Method Resolution Order (MRO).

If the instance is a subclass of Child, there may be a different parent that comes next in the MRO.

Explained simply

When you write a class, you want other classes to be able to use it. super() makes it easier for other classes to use the class you’re writing.

As Bob Martin says, a good architecture allows you to postpone decision making as long as possible.

super() can enable that sort of architecture.

When another class subclasses the class you wrote, it could also be inheriting from other classes. And those classes could have an __init__ that comes after this __init__ based on the ordering of the classes for method resolution.

Without super you would likely hard-code the parent of the class you’re writing (like the example does). This would mean that you would not call the next __init__ in the MRO, and you would thus not get to reuse the code in it.

If you’re writing your own code for personal use, you may not care about this distinction. But if you want others to use your code, using super is one thing that allows greater flexibility for users of the code.

Python 2 versus 3

This works in Python 2 and 3:

super(Child, self).__init__()

This only works in Python 3:

super().__init__()

It works with no arguments by moving up in the stack frame and getting the first argument to the method (usually self for an instance method or cls for a class method – but could be other names) and finding the class (e.g. Child) in the free variables (it is looked up with the name __class__ as a free closure variable in the method).

I prefer to demonstrate the cross-compatible way of using super, but if you are only using Python 3, you can call it with no arguments.

Indirection with Forward Compatibility

What does it give you? For single inheritance, the examples from the question are practically identical from a static analysis point of view. However, using super gives you a layer of indirection with forward compatibility.

Forward compatibility is very important to seasoned developers. You want your code to keep working with minimal changes as you change it. When you look at your revision history, you want to see precisely what changed when.

You may start off with single inheritance, but if you decide to add another base class, you only have to change the line with the bases – if the bases change in a class you inherit from (say a mixin is added) you’d change nothing in this class. Particularly in Python 2, getting the arguments to super and the correct method arguments right can be difficult. If you know you’re using super correctly with single inheritance, that makes debugging less difficult going forward.

Dependency Injection

Other people can use your code and inject parents into the method resolution:

class SomeBaseClass(object):
    def __init__(self):
        print('SomeBaseClass.__init__(self) called')

class UnsuperChild(SomeBaseClass):
    def __init__(self):
        print('UnsuperChild.__init__(self) called')
        SomeBaseClass.__init__(self)

class SuperChild(SomeBaseClass):
    def __init__(self):
        print('SuperChild.__init__(self) called')
        super(SuperChild, self).__init__()

Say you add another class to your object, and want to inject a class between Foo and Bar (for testing or some other reason):

class InjectMe(SomeBaseClass):
    def __init__(self):
        print('InjectMe.__init__(self) called')
        super(InjectMe, self).__init__()

class UnsuperInjector(UnsuperChild, InjectMe): pass

class SuperInjector(SuperChild, InjectMe): pass

Using the un-super child fails to inject the dependency because the child you’re using has hard-coded the method to be called after its own:

>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called

However, the class with the child that uses super can correctly inject the dependency:

>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called

Addressing a comment

Why in the world would this be useful?

Python linearizes a complicated inheritance tree via the C3 linearization algorithm to create a Method Resolution Order (MRO).

We want methods to be looked up in that order.

For a method defined in a parent to find the next one in that order without super, it would have to

  1. get the mro from the instance’s type
  2. look for the type that defines the method
  3. find the next type with the method
  4. bind that method and call it with the expected arguments

The UnsuperChild should not have access to InjectMe. Why isn’t the conclusion “Always avoid using super“? What am I missing here?

The UnsuperChild does not have access to InjectMe. It is the UnsuperInjector that has access to InjectMe – and yet cannot call that class’s method from the method it inherits from UnsuperChild.

Both Child classes intend to call a method by the same name that comes next in the MRO, which might be another class it was not aware of when it was created.

The one without super hard-codes its parent’s method – thus is has restricted the behavior of its method, and subclasses cannot inject functionality in the call chain.

The one with super has greater flexibility. The call chain for the methods can be intercepted and functionality injected.

You may not need that functionality, but subclassers of your code may.

Conclusion

Always use super to reference the parent class instead of hard-coding it.

What you intend is to reference the parent class that is next-in-line, not specifically the one you see the child inheriting from.

Not using super can put unnecessary constraints on users of your code.


回答 2

我与玩了一点super(),并意识到我们可以更改通话顺序。

例如,我们有下一个层次结构:

    A
   / \
  B   C
   \ /
    D

在这种情况下,D的MRO将是(仅适用于Python 3):

In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)

让我们创建一个super()方法执行后调用的类。

In [23]: class A(object): #  or with Python 3 can define class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          print("I'm from B")
...:          super().__init__()
...:   
...: class C(A):
...:      def __init__(self):
...:          print("I'm from C")
...:          super().__init__()
...:  
...: class D(B, C):
...:      def __init__(self):
...:          print("I'm from D")
...:          super().__init__()
...: d = D()
...:
I'm from D
I'm from B
I'm from C
I'm from A

    A
   / 
  B  C
    /
    D

因此,我们可以看到解析顺序与MRO中的解析顺序相同。但是当我们super()在方法的开头调用时:

In [21]: class A(object):  # or class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          super().__init__()  # or super(B, self).__init_()
...:          print("I'm from B")
...:   
...: class C(A):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from C")
...:  
...: class D(B, C):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from D")
...: d = D()
...: 
I'm from A
I'm from C
I'm from B
I'm from D

我们有一个不同的顺序,它是MRO元组的相反顺序。

    A
   / 
  B  C
    /
    D 

如需其他阅读,我建议下一个答案:

  1. 具有超级(大型层次结构)的C3线性化示例
  2. 新旧样式类之间的重要行为更改
  3. 新型课堂的内幕故事

I had played a bit with super(), and had recognized that we can change calling order.

For example, we have next hierarchy structure:

    A
   / \
  B   C
   \ /
    D

In this case MRO of D will be (only for Python 3):

In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)

Let’s create a class where super() calls after method execution.

In [23]: class A(object): #  or with Python 3 can define class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          print("I'm from B")
...:          super().__init__()
...:   
...: class C(A):
...:      def __init__(self):
...:          print("I'm from C")
...:          super().__init__()
...:  
...: class D(B, C):
...:      def __init__(self):
...:          print("I'm from D")
...:          super().__init__()
...: d = D()
...:
I'm from D
I'm from B
I'm from C
I'm from A

    A
   / ⇖
  B ⇒ C
   ⇖ /
    D

So we can see that resolution order is same as in MRO. But when we call super() in the beginning of the method:

In [21]: class A(object):  # or class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          super().__init__()  # or super(B, self).__init_()
...:          print("I'm from B")
...:   
...: class C(A):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from C")
...:  
...: class D(B, C):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from D")
...: d = D()
...: 
I'm from A
I'm from C
I'm from B
I'm from D

We have a different order it is reversed a order of the MRO tuple.

    A
   / ⇘
  B ⇐ C
   ⇘ /
    D 

For additional reading I would recommend next answers:

  1. C3 linearization example with super (a large hierarchy)
  2. Important behavior changes between old and new style classes
  3. The Inside Story on New-Style Classes

回答 3

难道不是所有这些都假设基类是新型类吗?

class A:
    def __init__(self):
        print("A.__init__()")

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()

在Python 2中将无法使用。class A必须是新样式,即:class A(object)

Doesn’t all of this assume that the base class is a new-style class?

class A:
    def __init__(self):
        print("A.__init__()")

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()

Will not work in Python 2. class A must be new-style, i.e: class A(object)


回答 4

当调用super()解析为父方法的类方法,实例方法或静态方法时,我们希望将其所在范围的当前类作为第一个参数传递,以指示我们要解析为哪个父方法的范围,并作为第二个参数是感兴趣的对象,用于指示我们要将该范围应用于哪个对象。

考虑一个类层次结构AB以及C其中,每个类是一个跟随它的父,并且abc每个的相应实例。

super(B, b) 
# resolves to the scope of B's parent i.e. A 
# and applies that scope to b, as if b was an instance of A

super(C, c) 
# resolves to the scope of C's parent i.e. B
# and applies that scope to c

super(B, c) 
# resolves to the scope of B's parent i.e. A 
# and applies that scope to c

super与静态方法一起使用

例如super()__new__()方法中使用

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return super(A, cls).__new__(cls, *a, **kw)

说明:

1-尽管通常__new__()将对调用类的引用作为其第一个参数,但它不是在Python中作为类方法实现的,而是作为静态方法实现的。也就是说,在__new__()直接调用时,必须将对类的引用作为第一个参数显式传递:

# if you defined this
class A(object):
    def __new__(cls):
        pass

# calling this would raise a TypeError due to the missing argument
A.__new__()

# whereas this would be fine
A.__new__(A)

2-当调用super()到达父类时,我们将子类A作为其第一个参数传递,然后传递对感兴趣对象的引用,在这种情况下,它A.__new__(cls)是调用时传递的类引用。在大多数情况下,它也恰好是对子类的引用。在某些情况下,例如在多代继承的情况下,可能并非如此。

super(A, cls)

3-由于通常__new__()是静态方法,super(A, cls).__new__因此也将返回静态方法,并且需要显式提供所有参数,在这种情况下,包括对insterest对象的引用cls

super(A, cls).__new__(cls, *a, **kw)

4-没有做同样的事情 super

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return object.__new__(cls, *a, **kw)

使用super与实例方法

例如super()从内部使用__init__()

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        super(A, self).__init__(*a, **kw)

说明:

1- __init__是一个实例方法,这意味着它将实例的引用作为其第一个参数。当直接从实例调用时,引用将隐式传递,即您无需指定它:

# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...

# you create an instance
a = A()

# you call `__init__()` from that instance and it works
a.__init__()

# you can also call `__init__()` with the class and explicitly pass the instance 
A.__init__(a)

2-当super()在内部调用时,__init__()我们将子类作为第一个参数,将感兴趣的对象作为第二个参数,这通常是对子类实例的引用。

super(A, self)

3-调用super(A, self)返回一个代理,它将解析作用域并将其应用于self当前的父类实例。让我们称该代理s。由于__init__()是实例方法,因此调用s.__init__(...)将隐式地将的引用self作为第一个参数传递给父级的__init__()

4-要做同样的事情,而super无需将对实例的引用显式传递给父版本__init__()

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        object.__init__(self, *a, **kw)

super与类方法一起使用

class A(object):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        print "A.alternate_constructor called"
        return cls(*a, **kw)

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        return super(B, cls).alternate_constructor(*a, **kw)

说明:

1-可以直接从类中调用类方法,并将对类的引用作为其第一个参数。

# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()

2-通话时 super()在类方法中以解析为其父级的版本时,我们希望将当前子类作为第一个参数传递,以指示我们要解析到的父级范围,而感兴趣的对象作为第二个参数指示我们要将该范围应用于哪个对象,通常是对子类本身或其子类之一的引用。

super(B, cls_or_subcls)

3-呼叫super(B, cls)解析到的范围A并将其应用于cls。由于alternate_constructor()是类方法,因此调用super(B, cls).alternate_constructor(...)将隐式传递的引用cls作为A的版本的第一个参数alternate_constructor()

super(B, cls).alternate_constructor()

4-要在不使用的情况下执行相同的操作super(),则需要获取未绑定版本的引用A.alternate_constructor()(即函数的显式版本)。简单地这样做是行不通的:

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        return A.alternate_constructor(cls, *a, **kw)

上面的A.alternate_constructor()方法不起作用,因为该方法将隐式引用A作为其第一个参数。在cls这里传递的存在将是其第二个参数。

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        # first we get a reference to the unbound 
        # `A.alternate_constructor` function 
        unbound_func = A.alternate_constructor.im_func
        # now we call it and pass our own `cls` as its first argument
        return unbound_func(cls, *a, **kw)

When calling super() to resolve to a parent’s version of a classmethod, instance method, or staticmethod, we want to pass the current class whose scope we are in as the first argument, to indicate which parent’s scope we’re trying to resolve to, and as a second argument the object of interest to indicate which object we’re trying to apply that scope to.

Consider a class hierarchy A, B, and C where each class is the parent of the one following it, and a, b, and c respective instances of each.

super(B, b) 
# resolves to the scope of B's parent i.e. A 
# and applies that scope to b, as if b was an instance of A

super(C, c) 
# resolves to the scope of C's parent i.e. B
# and applies that scope to c

super(B, c) 
# resolves to the scope of B's parent i.e. A 
# and applies that scope to c

Using super with a staticmethod

e.g. using super() from within the __new__() method

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return super(A, cls).__new__(cls, *a, **kw)

Explanation:

1- even though it’s usual for __new__() to take as its first param a reference to the calling class, it is not implemented in Python as a classmethod, but rather a staticmethod. That is, a reference to a class has to be passed explicitly as the first argument when calling __new__() directly:

# if you defined this
class A(object):
    def __new__(cls):
        pass

# calling this would raise a TypeError due to the missing argument
A.__new__()

# whereas this would be fine
A.__new__(A)

2- when calling super() to get to the parent class we pass the child class A as its first argument, then we pass a reference to the object of interest, in this case it’s the class reference that was passed when A.__new__(cls) was called. In most cases it also happens to be a reference to the child class. In some situations it might not be, for instance in the case of multiple generation inheritances.

super(A, cls)

3- since as a general rule __new__() is a staticmethod, super(A, cls).__new__ will also return a staticmethod and needs to be supplied all arguments explicitly, including the reference to the object of insterest, in this case cls.

super(A, cls).__new__(cls, *a, **kw)

4- doing the same thing without super

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return object.__new__(cls, *a, **kw)

Using super with an instance method

e.g. using super() from within __init__()

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        super(A, self).__init__(*a, **kw)

Explanation:

1- __init__ is an instance method, meaning that it takes as its first argument a reference to an instance. When called directly from the instance, the reference is passed implicitly, that is you don’t need to specify it:

# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...

# you create an instance
a = A()

# you call `__init__()` from that instance and it works
a.__init__()

# you can also call `__init__()` with the class and explicitly pass the instance 
A.__init__(a)

2- when calling super() within __init__() we pass the child class as the first argument and the object of interest as a second argument, which in general is a reference to an instance of the child class.

super(A, self)

3- The call super(A, self) returns a proxy that will resolve the scope and apply it to self as if it’s now an instance of the parent class. Let’s call that proxy s. Since __init__() is an instance method the call s.__init__(...) will implicitly pass a reference of self as the first argument to the parent’s __init__().

4- to do the same without super we need to pass a reference to an instance explicitly to the parent’s version of __init__().

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        object.__init__(self, *a, **kw)

Using super with a classmethod

class A(object):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        print "A.alternate_constructor called"
        return cls(*a, **kw)

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        return super(B, cls).alternate_constructor(*a, **kw)

Explanation:

1- A classmethod can be called from the class directly and takes as its first parameter a reference to the class.

# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()

2- when calling super() within a classmethod to resolve to its parent’s version of it, we want to pass the current child class as the first argument to indicate which parent’s scope we’re trying to resolve to, and the object of interest as the second argument to indicate which object we want to apply that scope to, which in general is a reference to the child class itself or one of its subclasses.

super(B, cls_or_subcls)

3- The call super(B, cls) resolves to the scope of A and applies it to cls. Since alternate_constructor() is a classmethod the call super(B, cls).alternate_constructor(...) will implicitly pass a reference of cls as the first argument to A‘s version of alternate_constructor()

super(B, cls).alternate_constructor()

4- to do the same without using super() you would need to get a reference to the unbound version of A.alternate_constructor() (i.e. the explicit version of the function). Simply doing this would not work:

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        return A.alternate_constructor(cls, *a, **kw)

The above would not work because the A.alternate_constructor() method takes an implicit reference to A as its first argument. The cls being passed here would be its second argument.

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        # first we get a reference to the unbound 
        # `A.alternate_constructor` function 
        unbound_func = A.alternate_constructor.im_func
        # now we call it and pass our own `cls` as its first argument
        return unbound_func(cls, *a, **kw)

回答 5

有很多不错的答案,但是对于视觉学习者来说:首先让我们以super为参数进行探索,然后再以super为参数。 超级继承树示例

想象有一个jack从类创建的实例,该实例Jack具有继承链,如图中的绿色所示。调用:

super(Jack, jack).method(...)

将使用(jack按一定顺序的继承树)的MRO(方法解析顺序),并从开始搜索Jack。为什么可以提供家长班?好吧,如果我们从实例开始搜索jack,它将找到实例方法,重点是找到其父方法。

如果不向super提供参数,则其像传入的第一个参数是的类self,而传入的第二个参数是self。这些是在Python3中自动为您计算的。

但是请说我们不想使用Jack的方法,而不是传入Jack,我们可以传入从Jen开始向上搜索该方法Jen

它一次搜索一层(宽度而不是深度),例如,如果AdamSue两者都具有所需的方法,Sue将首先找到其中的一层。

如果CainSue都具有必需的方法,Cain则将首先调用的方法。这在代码中对应于:

Class Jen(Cain, Sue):

MRO是从左到右。

Many great answers, but for visual learners: Firstly lets explore with arguments to super, and then without. super inheritance tree example

Imagine theres an instance jack created from the class Jack, who has the inheritance chain as shown in green in the picture. Calling:

super(Jack, jack).method(...)

will use the MRO (Method Resolution Order) of jack (its inheritance tree in a certain order), and will start searching from Jack. Why can one provide a parent class? Well if we start searching from the instance jack, it would find the instance method, the whole point is to find its parents method.

If one does not supply arguments to super, its like the first argument passed in is the class of self, and the second argument passed in is self. These are auto-calculated for you in Python3.

However say we dont want to use Jack‘s method, instead of passing in Jack, we could of passed in Jen to start searching upwards for the method from Jen.

It searches one layer at a time (width not depth), e.g. if Adam and Sue both have the required method, the one from Sue will be found first.

If Cain and Sue both had the required method, Cain‘s method would be called first. This corresponds in code to:

Class Jen(Cain, Sue):

MRO is from left to right.


回答 6

这里有一些很好的答案,但是super()在层次结构中的不同类具有不同签名的情况下,它们并没有解决如何使用的问题……尤其是在__init__

为了回答这一部分并能够有效地使用,super()我建议阅读我的答案super()并更改合作方法的签名

这只是这种情况的解决方案:

  1. 层次结构中的顶级类必须继承自定义类,例如SuperObject
  2. 如果类可以采用不同的参数,则始终将您收到的所有参数作为关键字参数传递给超函数,并始终接受**kwargs
class SuperObject:        
    def __init__(self, **kwargs):
        print('SuperObject')
        mro = type(self).__mro__
        assert mro[-1] is object
        if mro[-2] is not SuperObject:
            raise TypeError(
                'all top-level classes in this hierarchy must inherit from SuperObject',
                'the last class in the MRO should be SuperObject',
                f'mro={[cls.__name__ for cls in mro]}'
            )

        # super().__init__ is guaranteed to be object.__init__        
        init = super().__init__
        init()

用法示例:

class A(SuperObject):
    def __init__(self, **kwargs):
        print("A")
        super(A, self).__init__(**kwargs)

class B(SuperObject):
    def __init__(self, **kwargs):
        print("B")
        super(B, self).__init__(**kwargs)

class C(A):
    def __init__(self, age, **kwargs):
        print("C",f"age={age}")
        super(C, self).__init__(age=age, **kwargs)

class D(B):
    def __init__(self, name, **kwargs):
        print("D", f"name={name}")
        super(D, self).__init__(name=name, **kwargs)

class E(C,D):
    def __init__(self, name, age, *args, **kwargs):
        print( "E", f"name={name}", f"age={age}")
        super(E, self).__init__(name=name, age=age, *args, **kwargs)

E(name='python', age=28)

输出:

E name=python age=28
C age=28
A
D name=python
B
SuperObject

some great answers here, but they do not tackle how to use super() in the case where different classes in the hierarchy have different signatures … especially in the case of __init__

to answer that part and to be able to effectively use super() i’d suggest reading my answer super() and changing the signature of cooperative methods.

here’s just the solution to this scenario:

  1. the top-level classes in your hierarchy must inherit from a custom class like SuperObject:
  2. if classes can take differing arguments, always pass all arguments you received on to the super function as keyword arguments, and, always accept **kwargs.
class SuperObject:        
    def __init__(self, **kwargs):
        print('SuperObject')
        mro = type(self).__mro__
        assert mro[-1] is object
        if mro[-2] is not SuperObject:
            raise TypeError(
                'all top-level classes in this hierarchy must inherit from SuperObject',
                'the last class in the MRO should be SuperObject',
                f'mro={[cls.__name__ for cls in mro]}'
            )

        # super().__init__ is guaranteed to be object.__init__        
        init = super().__init__
        init()

example usage:

class A(SuperObject):
    def __init__(self, **kwargs):
        print("A")
        super(A, self).__init__(**kwargs)

class B(SuperObject):
    def __init__(self, **kwargs):
        print("B")
        super(B, self).__init__(**kwargs)

class C(A):
    def __init__(self, age, **kwargs):
        print("C",f"age={age}")
        super(C, self).__init__(age=age, **kwargs)

class D(B):
    def __init__(self, name, **kwargs):
        print("D", f"name={name}")
        super(D, self).__init__(name=name, **kwargs)

class E(C,D):
    def __init__(self, name, age, *args, **kwargs):
        print( "E", f"name={name}", f"age={age}")
        super(E, self).__init__(name=name, age=age, *args, **kwargs)

E(name='python', age=28)

output:

E name=python age=28
C age=28
A
D name=python
B
SuperObject

回答 7

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

这很容易理解。

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

好的,如果您现在使用该super(Child,self)怎么办?

创建Child实例时,其MRO(方法解析顺序)基于继承的顺序为(Child,SomeBaseClass,对象)。(假设SomeBaseClass除默认对象外没有其他父对象)

通过传递Child, selfsuperself实例的MRO中搜索,然后返回Child的下一个代理对象(在本例中为SomeBaseClass),然后此对象调用__init__SomeBaseClass 的方法。换句话说,如果是super(SomeBaseClass,self),则super返回的代理对象将是object

对于多继承,MRO可以包含许多类,因此基本上super可以让您决定要在MRO中开始搜索的位置。

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

This is fairly easy to understand.

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

Ok, what happens now if you use super(Child,self)?

When a Child instance is created, its MRO(Method Resolution Order) is in the order of (Child, SomeBaseClass, object) based on the inheritance. (assume SomeBaseClass doesn’t have other parents except for the default object)

By passing Child, self, super searches in the MRO of the self instance, and return the proxy object next of Child, in this case it’s SomeBaseClass, this object then invokes the __init__ method of SomeBaseClass. In other word, if it’s super(SomeBaseClass,self), the proxy object that super returns would be object

For multi inheritance, the MRO could contain many classes, so basically super lets you decide where you want to start searching in the MRO.


回答 8

考虑以下代码:

class X():
    def __init__(self):
        print("X")

class Y(X):
    def __init__(self):
        # X.__init__(self)
        super(Y, self).__init__()
        print("Y")

class P(X):
    def __init__(self):
        super(P, self).__init__()
        print("P")

class Q(Y, P):
    def __init__(self):
        super(Q, self).__init__()
        print("Q")

Q()

如果将的构造函数更改YX.__init__,您将获得:

X
Y
Q

但是使用super(Y, self).__init__(),您将获得:

X
P
Y
Q

P或者Q甚至可以从当你写你不知道另一个文件参与XY。因此,基本上,即使Y的签名与一样简单,您也不知道super(Child, self)在编写时将引用什么内容。这就是为什么超级可能是更好的选择。class Y(X)Y(X)

Consider the following code:

class X():
    def __init__(self):
        print("X")

class Y(X):
    def __init__(self):
        # X.__init__(self)
        super(Y, self).__init__()
        print("Y")

class P(X):
    def __init__(self):
        super(P, self).__init__()
        print("P")

class Q(Y, P):
    def __init__(self):
        super(Q, self).__init__()
        print("Q")

Q()

If change constructor of Y to X.__init__, you will get:

X
Y
Q

But using super(Y, self).__init__(), you will get:

X
P
Y
Q

And P or Q may even be involved from another file which you don’t know when you writing X and Y. So, basically, you won’t know what super(Child, self) will reference to when you are writing class Y(X), even the signature of Y is as simple as Y(X). That’s why super could be a better choice.


要求用户提供输入,直到他们给出有效的答复

问题:要求用户提供输入,直到他们给出有效的答复

我正在编写一个接受用户输入的程序。

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

只要用户输入有意义的数据,该程序就会按预期运行。

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

但是如果用户输入无效数据,它将失败:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

除了崩溃,我希望程序再次请求输入。像这样:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

输入非意义的数据时,如何使程序要求有效的输入而不是崩溃?

在这种情况下-1,我如何才能拒绝类似的值,这是有效的int,但却毫无意义?

I am writing a program that accepts an input from the user.

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

The program works as expected as long as the the user enters meaningful data.

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

But it fails if the user enters invalid data:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

Instead of crashing, I would like the program to ask for the input again. Like this:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

How can I make the program ask for valid inputs instead of crashing when non-sensical data is entered?

How can I reject values like -1, which is a valid int, but nonsensical in this context?


回答 0

完成此操作的最简单方法是将input方法置于while循环中。continue当输入错误时使用,break当您感到满意时使用。

当您的输入可能引发异常时

使用tryexcept检测用户何时输入无法解析的数据。

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

实施您自己的验证规则

如果要拒绝Python可以成功解析的值,则可以添加自己的验证逻辑。

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

结合异常处理和自定义验证

以上两种技术都可以组合成一个循环。

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0:
        print("Sorry, your response must not be negative.")
        continue
    else:
        #age was successfully parsed, and we're happy with its value.
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

将其全部封装在一个函数中

如果您需要询问用户许多不同的值,则将此代码放入函数中可能会很有用,因此不必每次都重新键入。

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

放在一起

您可以扩展此思想,以创建非常通用的输入函数:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_:
        raise ValueError("min_ must be less than or equal to max_.")
    while True:
        ui = input(prompt)
        if type_ is not None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Input type must be {0}.".format(type_.__name__))
                continue
        if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {0}."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

用法如下:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))

常见的陷阱以及为什么要避免它们

冗余input语句的冗余使用

此方法有效,但通常被认为是较差的样式:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

由于它比while True方法短,一开始可能看起来很吸引人,但是它违反了软件开发的“ 不要重复自己”的原理。这增加了系统中错误的可能性。如果要更改inputraw_input,将其反向移植到2.7 input,怎么办?这SyntaxError只是一个等待发生的事情。

递归会毁了你的栈

如果您刚刚了解了递归,则可能会想使用它,get_non_negative_int以便可以处理while循环。

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

在大多数情况下,这似乎可以正常工作,但是如果用户输入无效数据的次数足够多,脚本将以终止RuntimeError: maximum recursion depth exceeded。您可能会认为“没有傻瓜会连续犯1000个错误”,但是您却低估了傻瓜的创造力!

The simplest way to accomplish this is to put the input method in a while loop. Use continue when you get bad input, and break out of the loop when you’re satisfied.

When Your Input Might Raise an Exception

Use try and except to detect when the user enters data that can’t be parsed.

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Implementing Your Own Validation Rules

If you want to reject values that Python can successfully parse, you can add your own validation logic.

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

Combining Exception Handling and Custom Validation

Both of the above techniques can be combined into one loop.

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0:
        print("Sorry, your response must not be negative.")
        continue
    else:
        #age was successfully parsed, and we're happy with its value.
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Encapsulating it All in a Function

If you need to ask your user for a lot of different values, it might be useful to put this code in a function, so you don’t have to retype it every time.

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

Putting It All Together

You can extend this idea to make a very generic input function:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_:
        raise ValueError("min_ must be less than or equal to max_.")
    while True:
        ui = input(prompt)
        if type_ is not None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Input type must be {0}.".format(type_.__name__))
                continue
        if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {0}."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

With usage such as:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))

Common Pitfalls, and Why you Should Avoid Them

The Redundant Use of Redundant input Statements

This method works but is generally considered poor style:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

It might look attractive initially because it’s shorter than the while True method, but it violates the Don’t Repeat Yourself principle of software development. This increases the likelihood of bugs in your system. What if you want to backport to 2.7 by changing input to raw_input, but accidentally change only the first input above? It’s a SyntaxError just waiting to happen.

Recursion Will Blow Your Stack

If you’ve just learned about recursion, you might be tempted to use it in get_non_negative_int so you can dispose of the while loop.

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

This appears to work fine most of the time, but if the user enters invalid data enough times, the script will terminate with a RuntimeError: maximum recursion depth exceeded. You may think “no fool would make 1000 mistakes in a row”, but you’re underestimating the ingenuity of fools!


回答 1

您为什么要先执行a while True然后再退出此循环,而您也可以只将需求放在while语句中,因为您想要的只是在达到年龄后就停止?

age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
if age >= 18:
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

这将导致以下结果:

Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

这是可行的,因为年龄永远不会有没有意义的值,并且代码遵循“业务流程”的逻辑

Why would you do a while True and then break out of this loop while you can also just put your requirements in the while statement since all you want is to stop once you have the age?

age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
if age >= 18:
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

This would result in the following:

Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

this will work since age will never have a value that will not make sense and the code follows the logic of your “business process”


回答 2

尽管公认的答案是惊人的。我也想分享一个快速解决此问题的方法。(这也解决了负面的年龄问题。)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

PS此代码适用于python3.x。

Though the accepted answer is amazing. I would also like to share a quick hack for this problem. (This takes care of the negative age problem as well.)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

P.S. This code is for python 3.x.


回答 3

因此,我最近在搞些类似的事情,于是我想到了以下解决方案,该解决方案使用了一种获取垃圾输入的方式,甚至可以以任何逻辑方式对其进行检查。

read_single_keypress()https://stackoverflow.com/a/6599441/4532996提供

def read_single_keypress() -> str:
    """Waits for a single keypress on stdin.
    -- from :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    try:
        ret = sys.stdin.read(1) # returns a single character
    except KeyboardInterrupt:
        ret = 0
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """read stdin until !(chars)"""
    import sys
    chars = list(chars)
    y = ""
    sys.stdout.flush()
    while True:
        i = read_single_keypress()
        _ = sys.stdout.write(i)
        sys.stdout.flush()
        if i not in chars:
            break
        y += i
    return y

def _can_you_vote() -> str:
    """a practical example:
    test if a user can vote based purely on keypresses"""
    print("can you vote? age : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nsorry, age can only consist of digits.")
        return
    print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")

_can_you_vote()

您可以在此处找到完整的模块。

例:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _

请注意,此实现的性质是,一旦读取了不是数字的内容,它将立即关闭stdin。我没有按回车键a,但是我需要按数字。

您可以将此thismany()功能与同一模块中的功能合并,以仅允许输入三位数。

So, I was messing around with something similar to this recently, and I came up with the following solution, which uses a way of getting input that rejects junk, before it’s even checked in any logical way.

read_single_keypress() courtesy https://stackoverflow.com/a/6599441/4532996

def read_single_keypress() -> str:
    """Waits for a single keypress on stdin.
    -- from :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    try:
        ret = sys.stdin.read(1) # returns a single character
    except KeyboardInterrupt:
        ret = 0
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """read stdin until !(chars)"""
    import sys
    chars = list(chars)
    y = ""
    sys.stdout.flush()
    while True:
        i = read_single_keypress()
        _ = sys.stdout.write(i)
        sys.stdout.flush()
        if i not in chars:
            break
        y += i
    return y

def _can_you_vote() -> str:
    """a practical example:
    test if a user can vote based purely on keypresses"""
    print("can you vote? age : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nsorry, age can only consist of digits.")
        return
    print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")

_can_you_vote()

You can find the complete module here.

Example:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _

Note that the nature of this implementation is it closes stdin as soon as something that isn’t a digit is read. I didn’t hit enter after a, but I needed to after the numbers.

You could merge this with the thismany() function in the same module to only allow, say, three digits.


回答 4

功能性方法或“ 看起来没有循环! ”:

from itertools import chain, repeat

prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

或者,如果您想将“错误输入”消息与输入提示分开,如其他答案所示:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

它是如何工作的?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    的组合itertools.chainitertools.repeat将创建一个迭代器,这将产生串"Enter a number: "一次,"Not a number! Try again: "中无数次:
    for prompt in prompts:
        print(prompt)
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
  2. replies = map(input, prompts)-这里map会将prompts上一步中的所有字符串应用于input函数。例如:
    for reply in replies:
        print(reply)
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
  3. 我们使用filterstr.isdigit过滤掉那些只包含数字的字符串:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    并且仅使用第一个数字字符串next

其他验证规则:

  1. 字符串方法:当然,您可以使用其他字符串方法,例如str.isalpha仅获取字母字符串或str.isupper仅获取大写字母。请参阅文档以获取完整列表。

  2. 成员资格测试:
    有几种不同的执行方式。其中之一是通过使用__contains__方法:

    from itertools import chain, repeat
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
  3. 数字比较:
    这里有一些有用的比较方法。例如,对于__lt__<):

    from itertools import chain, repeat
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0

    或者,如果您不喜欢使用dunder方法(dunder =双下划线),则始终可以定义自己的函数,也可以使用 operator模块中。

  4. 路径存在:
    这里可以使用pathlib库及其Path.exists方法:

    from itertools import chain, repeat
    from pathlib import Path
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt

限制尝试次数:

如果您不想无限次地问某人来折磨他,可以在呼叫中指定一个限制itertools.repeat。这可以与为next函数提供默认值结合使用:

from itertools import chain, repeat

prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

预处理输入数据:

有时,如果用户不小心以大写形式提供了输入,或者在字符串的开头或结尾有空格,我们就不想拒绝输入。为了考虑这些简单的错误,我们可以通过应用str.lowerstr.strip方法对输入数据进行预处理。例如,对于成员资格测试,代码如下所示:

from itertools import chain, repeat

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

如果要使用许多函数进行预处理,则使用执行函数合成的函数可能会更容易。例如,使用此处的一个:

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

合并验证规则:

例如,在一个简单的情况下,当程序要求输入1到120岁之间的年龄时,可以添加另一个filter

from itertools import chain, repeat

prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

但是,在规则很多的情况下,最好实现执行逻辑合取的函数。在下面的例子中我将使用一个现成的一个位置

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


def is_one_letter(string: str) -> bool:
    return len(string) == 1


rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]

prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

不幸的是,如果有人需要为每个失败的情况下,自定义消息,然后,我很害怕,也没有漂亮的功能性的方式。或者,至少,我找不到一个。

Functional approach or “look mum no loops!“:

from itertools import chain, repeat

prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

or if you want to have a “bad input” message separated from an input prompt as in other answers:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

How does it work?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    
    This combination of itertools.chain and itertools.repeat will create an iterator which will yield strings "Enter a number: " once, and "Not a number! Try again: " an infinite number of times:
    for prompt in prompts:
        print(prompt)
    
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
    
  2. replies = map(input, prompts) – here map will apply all the prompts strings from the previous step to the input function. E.g.:
    for reply in replies:
        print(reply)
    
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
    
  3. We use filter and str.isdigit to filter out those strings that contain only digits:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    
    And to get only the first digits-only string we use next.

Other validation rules:

  1. String methods: Of course you can use other string methods like str.isalpha to get only alphabetic strings, or str.isupper to get only uppercase. See docs for the full list.

  2. Membership testing:
    There are several different ways to perform it. One of them is by using __contains__ method:

    from itertools import chain, repeat
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
    
  3. Numbers comparison:
    There are useful comparison methods which we can use here. For example, for __lt__ (<):

    from itertools import chain, repeat
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0
    

    Or, if you don’t like using dunder methods (dunder = double-underscore), you can always define your own function, or use the ones from the operator module.

  4. Path existance:
    Here one can use pathlib library and its Path.exists method:

    from itertools import chain, repeat
    from pathlib import Path
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt
    

Limiting number of tries:

If you don’t want to torture a user by asking him something an infinite number of times, you can specify a limit in a call of itertools.repeat. This can be combined with providing a default value to the next function:

from itertools import chain, repeat

prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

Preprocessing input data:

Sometimes we don’t want to reject an input if the user accidentally supplied it IN CAPS or with a space in the beginning or an end of the string. To take these simple mistakes into account we can preprocess the input data by applying str.lower and str.strip methods. For example, for the case of membership testing the code will look like this:

from itertools import chain, repeat

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

In the case when you have many functions to use for preprocessing, it might be easier to use a function performing a function composition. For example, using the one from here:

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

Combining validation rules:

For a simple case, for example, when the program asks for age between 1 and 120, one can just add another filter:

from itertools import chain, repeat

prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

But in the case when there are many rules, it’s better to implement a function performing a logical conjunction. In the following example I will use a ready one from here:

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


def is_one_letter(string: str) -> bool:
    return len(string) == 1


rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]

prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

Unfortunately, if someone needs a custom message for each failed case, then, I’m afraid, there is no pretty functional way. Or, at least, I couldn’t find one.


回答 5

使用点击

请点击是一个用于命令行界面的库,它提供了向用户询问有效响应的功能。

简单的例子:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0

注意如何将字符串值自动转换为浮点数。

检查值是否在范围内:

提供了不同的自定义类型。要获得特定范围内的数字,我们可以使用IntRange

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?: 
 a
Error: a is not a valid integer
What's your age?: 
 0
Error: 0 is not in the valid range of 1 to 120.
What's your age?: 
 5
5

我们还可以只指定其中一个限制,minmax

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18

会员资格测试:

使用click.Choice类型。默认情况下,此检查区分大小写。

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange

使用路径和文件:

使用click.Path类型,我们可以检查现有路径并解决它们:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path: 
 nonexistent
Error: Path "nonexistent" does not exist.
Provide path: 
 existing_folder
'/path/to/existing_folder

读写文件可以通过以下方式完成click.File

file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
In which file to write data?: 
         # <-- provided an empty string, which is an illegal name for a file
In which file to write data?: 
 some_file.txt
Which file you wanna read?: 
 nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?: 
 some_file.txt
Hello!

其他例子:

确认密码:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password: 
 ······
Repeat for confirmation: 
 ·
Error: the two entered values do not match
Enter password: 
 ······
Repeat for confirmation: 
 ······
qwerty

默认值:

在这种情况下,只需按Enter(或您使用的任何键)而不输入值,即可得到默认值:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]: 
 a
Error: a is not a valid integer
Please enter a number [42]: 

42

Using Click:

Click is a library for command-line interfaces and it provides functionality for asking a valid response from a user.

Simple example:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0

Note how it converted the string value to a float automatically.

Checking if a value is within a range:

There are different custom types provided. To get a number in a specific range we can use IntRange:

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?: 
 a
Error: a is not a valid integer
What's your age?: 
 0
Error: 0 is not in the valid range of 1 to 120.
What's your age?: 
 5
5

We can also specify just one of the limits, min or max:

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18

Membership testing:

Using click.Choice type. By default this check is case-sensitive.

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange

Working with paths and files:

Using a click.Path type we can check for existing paths and also resolve them:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path: 
 nonexistent
Error: Path "nonexistent" does not exist.
Provide path: 
 existing_folder
'/path/to/existing_folder

Reading and writing files can be done by click.File:

file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
In which file to write data?: 
         # <-- provided an empty string, which is an illegal name for a file
In which file to write data?: 
 some_file.txt
Which file you wanna read?: 
 nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?: 
 some_file.txt
Hello!

Other examples:

Password confirmation:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password: 
 ······
Repeat for confirmation: 
 ·
Error: the two entered values do not match
Enter password: 
 ······
Repeat for confirmation: 
 ······
qwerty

Default values:

In this case, simply pressing Enter (or whatever key you use) without entering a value, will give you a default one:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]: 
 a
Error: a is not a valid integer
Please enter a number [42]: 

42

回答 6

def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Please enter your age:"))
        if validate_age(age): break
    except ValueError:
        print "Error: Invalid age."
def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Please enter your age:"))
        if validate_age(age): break
    except ValueError:
        print "Error: Invalid age."

回答 7

在Daniel Q和Patrick Artner的出色建议的基础上,这是一个更为通用的解决方案。

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

我选择了显式ifraise语句而不是assert,因为断言检查可能已关闭,而验证应始终处于打开状态以提供鲁棒性。

这可用于获取具有不同验证条件的不同种类的输入。例如:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

或者,回答原始问题:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Building upon Daniel Q’s and Patrick Artner’s excellent suggestions, here is an even more generalized solution.

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

I opted for explicit if and raise statements instead of an assert, because assertion checking may be turned off, whereas validation should always be on to provide robustness.

This may be used to get different kinds of input, with different validation conditions. For example:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

Or, to answer the original question:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

回答 8

试试这个:

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')

Try this one:-

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')

回答 9

尽管try/ except块可以工作,但使用可以更快,更干净地完成此任务str.isdigit()

while True:
    age = input("Please enter your age: ")
    if age.isdigit():
        age = int(age)
        break
    else:
        print("Invalid number '{age}'. Try again.".format(age=age))

if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

While a try/except block will work, a much faster and cleaner way to accomplish this task would be to use str.isdigit().

while True:
    age = input("Please enter your age: ")
    if age.isdigit():
        age = int(age)
        break
    else:
        print("Invalid number '{age}'. Try again.".format(age=age))

if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

回答 10

好问题!您可以尝试以下代码。=)

此代码使用ast.literal_eval()找到输入的数据类型age)。然后遵循以下算法:

  1. 要求用户输入她/他的age

    1.1。如果agefloatint数据类型:

    • 检查是否age>=18。如果为age>=18,则输出适当的输出并退出。

    • 检查是否0<age<18。如果为0<age<18,则输出适当的输出并退出。

    • 如果为age<=0,则要求用户再次输入有效的年龄编号(返回步骤1)。

    1.2。如果age不是floatint数据类型,则要求用户再次输入他/他的年龄(返回步骤1)。

这是代码。

from ast import literal_eval

''' This function is used to identify the data type of input data.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Please enter your age: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("You are able to vote in the United States!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("You are not able to vote in the United States.") 
            flag = False
        else: print("Please enter a valid number as your age.")

    else: print("Sorry, I didn't understand that.") 

Good question! You can try the following code for this. =)

This code uses ast.literal_eval() to find the data type of the input (age). Then it follows the following algorithm:

  1. Ask user to input her/his age.

    1.1. If age is float or int data type:

    • Check if age>=18. If age>=18, print appropriate output and exit.

    • Check if 0<age<18. If 0<age<18, print appropriate output and exit.

    • If age<=0, ask the user to input a valid number for age again, (i.e. go back to step 1.)

    1.2. If age is not float or int data type, then ask user to input her/his age again (i.e. go back to step 1.)

Here is the code.

from ast import literal_eval

''' This function is used to identify the data type of input data.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Please enter your age: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("You are able to vote in the United States!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("You are not able to vote in the United States.") 
            flag = False
        else: print("Please enter a valid number as your age.")

    else: print("Sorry, I didn't understand that.") 

回答 11

您始终可以应用简单的if-else逻辑,并if在代码和for循环中添加一个或多个逻辑。

while True:
     age = int(input("Please enter your age: "))
     if (age >= 18)  : 
         print("You are able to vote in the United States!")
     if (age < 18) & (age > 0):
         print("You are not able to vote in the United States.")
     else:
         print("Wrong characters, the input must be numeric")
         continue

这将是一个无限的厕所,并且您将被要求无限期地输入年龄。

You can always apply simple if-else logic and add one more if logic to your code along with a for loop.

while True:
     age = int(input("Please enter your age: "))
     if (age >= 18)  : 
         print("You are able to vote in the United States!")
     if (age < 18) & (age > 0):
         print("You are not able to vote in the United States.")
     else:
         print("Wrong characters, the input must be numeric")
         continue

This will be an infinite loo and you would be asked to enter the age, indefinitely.


回答 12

您可以编写更通用的逻辑,以允许用户仅输入特定的次数,因为在许多实际应用程序中会出现相同的用例。

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.

You can write more general logic to allow user to enter only specific number of times, as the same use-case arises in many real-world applications.

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.

回答 13

您可以将输入语句设置为True循环,以便它反复询问用户输入,然后在用户输入您想要的响应时中断该循环。您可以使用try和except块来处理无效响应。

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

var变量只是这样,如果用户输入字符串而不是整数,程序将不会返回“您无法在美国投票”。

You can make the input statement a while True loop so it repeatedly asks for the users input and then break that loop if the user enters the response you would like. And you can use try and except blocks to handle invalid responses.

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

The var variable is just so that if the user enters a string instead of a integer the program wont return “You are not able to vote in the United States.”


回答 14

使用“ while”语句,直到用户输入一个真值,并且如果输入值不是数字或它是一个空值,请跳过该语句并尝试再次询问,依此类推。例如,我试图真正回答您的问题。如果我们认为年龄在1到150之间,则接受输入值,否则输入的值是错误的。对于终止程序,用户可以使用0键并将其作为值输入。

注意:阅读代码顶部的注释。

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
    Value = None
    while Value == None or Value.isdigit() == False:
        try:        
            Value = str(input(Message)).strip()
        except InputError:
            Value = None
    return Value

# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
    age = int(Input("Please enter your age: "))
    # For terminating program, the user can use 0 key and enter it as an a value.
    if age == 0:
        print("Terminating ...")
        exit(0)

if age >= 18 and age <=150: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Use “while” statement till user enter a true value and if the input value is not a number or it’s a null value skip it and try to ask again and so on. In example I tried to answer truly your question. If we suppose that our age is between 1 and 150 then input value accepted, else it’s a wrong value. For terminating program, the user can use 0 key and enter it as a value.

Note: Read comments top of code.

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
    Value = None
    while Value == None or Value.isdigit() == False:
        try:        
            Value = str(input(Message)).strip()
        except InputError:
            Value = None
    return Value

# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
    age = int(Input("Please enter your age: "))
    # For terminating program, the user can use 0 key and enter it as an a value.
    if age == 0:
        print("Terminating ...")
        exit(0)

if age >= 18 and age <=150: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

回答 15

使用输入验证的另一种解决方案是ValidationError对整数输入使用定制的(可选)范围验证:

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))

用法:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)

输出:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2

One more solution for using input validation using a customized ValidationError and a (optional) range validation for integer inputs:

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))

Usage:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)

Output:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2

回答 16

这是一个更干净,更通用的解决方案,避免了重复的if / else块:在字典中编写一个接受(错误,错误提示)对的函数,并使用断言进行所有值检查。

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

用法:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)

Here’s a cleaner, more generalized solution that avoids repetitive if/else blocks: write a function that takes (Error, error prompt) pairs in a dictionary and do all your value-checking with assertions.

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

Usage:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)

回答 17

使用递归功能的持久性用户输入:

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

整数

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

最后,问题要求:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)

Persistent user input using recursive function:

String

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

Integer

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

and finally, the question requirement:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)

回答 18

简单的解决方案是:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        if age>=18:
            print("You are able to vote in the United States!")
        else:
            print("You are not able to vote in the United States.")
        break

上面的代码说明: 为了使年龄有效,它应该是正数,并且不应超过正常的身体年龄,例如,最大年龄为120。

然后,我们可以询问用户年龄,如果年龄输入为负数或大于120,我们将其视为无效输入,然后要求用户重试。

输入有效输入后,我们将检查(使用嵌套的if-else语句)年龄是否大于等于18,反之亦然,并显示一条消息,说明用户是否有资格投票

The simple solution would be:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        if age>=18:
            print("You are able to vote in the United States!")
        else:
            print("You are not able to vote in the United States.")
        break

Explanation of above code: In order for a valid age,it should be positive and should not be more than normal physical age,say for example maximum age is 120.

Then we can ask user for age and if age input is negative or more than 120,we consider it invalid input and ask the user to try again.

Once the valid input is entered, we perform a check (using nested if-else statement) whether the age is >=18 or vice versa and print a message whether the user is eligible to vote


回答 19

将输入作为字符串并使用isdigit()来检查输入是否只有数字,不能为空,不能为-ve

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False

take input as string and use isdigit() to check input only has digits, not empty, cant be -ve

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False


如何在Python中表示一个无限数?

问题:如何在Python中表示一个无限数?

如何在python中表示无穷大?无论您在程序中输入哪个数字,任何数字都不得大于此无穷大表示形式。

How can I represent an infinite number in python? No matter which number you enter in the program, no number should be greater than this representation of infinity.


回答 0

在Python中,您可以执行以下操作:

test = float("inf")

在Python 3.5中,您可以执行以下操作:

import math
test = math.inf

然后:

test > 1
test > 10000
test > x

永远是真的。当然,除非指出,否则x也是无穷大或“ nan”(“非数字”)。

另外(Python的ONLY 2.X)中,在比较Ellipsisfloat(inf)较小,例如:

float('inf') < Ellipsis

将返回true。

In Python, you can do:

test = float("inf")

In Python 3.5, you can do:

import math
test = math.inf

And then:

test > 1
test > 10000
test > x

Will always be true. Unless of course, as pointed out, x is also infinity or “nan” (“not a number”).

Additionally (Python 2.x ONLY), in a comparison to Ellipsis, float(inf) is lesser, e.g:

float('inf') < Ellipsis

would return true.


回答 1

从Python 3.5开始,您可以使用math.inf

>>> import math
>>> math.inf
inf

Since Python 3.5 you can use math.inf:

>>> import math
>>> math.inf
inf

回答 2

似乎没有人明确提到负无穷大,因此我认为应该添加它。

对于正无穷大(仅出于完整性考虑):

math.inf

对于负无穷大:

-math.inf

No one seems to have mentioned about the negative infinity explicitly, so I think I should add it.

For positive infinity (just for the sake of completeness):

math.inf

For negative infinity:

-math.inf

回答 3

我不知道您在做什么,但是float("inf")给您的是float Infinity,它比其他任何数字都大。

I don’t know exactly what you are doing, but float("inf") gives you a float Infinity, which is greater than any other number.


回答 4

有一个在与NumPy库的无边:from numpy import inf。要获得负无穷大,可以简单地写-inf

There is an infinity in the NumPy library: from numpy import inf. To get negative infinity one can simply write -inf.


回答 5

另一种较不方便的方法是使用Decimal类:

from decimal import Decimal
pos_inf = Decimal('Infinity')
neg_inf = Decimal('-Infinity')

Another, less convenient, way to do it is to use Decimal class:

from decimal import Decimal
pos_inf = Decimal('Infinity')
neg_inf = Decimal('-Infinity')

回答 6

在python2.x中,有一个肮脏的hack可以达到这个目的(除非绝对必要,否则不要使用它):

None < any integer < any string

因此,检查i < ''适用True于任何整数i

在python3中已合理弃用了它。现在这样的比较最终

TypeError: unorderable types: str() < int()

In python2.x there was a dirty hack that served this purpose (NEVER use it unless absolutely necessary):

None < any integer < any string

Thus the check i < '' holds True for any integer i.

It has been reasonably deprecated in python3. Now such comparisons end up with

TypeError: unorderable types: str() < int()

回答 7

另外,如果您使用SymPy,则可以使用 sympy.oo

>>> from sympy import oo
>>> oo + 1
oo
>>> oo - oo
nan

等等

Also if you use SymPy you can use sympy.oo

>>> from sympy import oo
>>> oo + 1
oo
>>> oo - oo
nan

etc.


Python的time.time()返回本地或UTC时间戳吗?

问题:Python的time.time()返回本地或UTC时间戳吗?

是否time.time()Python的时间模块系统返回的时间或UTC时间?

Does time.time() in the Python time module return the system’s time or the time in UTC?


回答 0

time.time()函数返回自纪元以来的秒数,以秒为单位。请注意,“时代”定义为UTC的1970年1月1日开始。因此,以UTC定义时代,并确定全球时间。无论您身在何处,“ time.time()”都会在同一时刻返回相同的值。

这是我在计算机上运行的一些示例输出,也将其转换为字符串。

Python 2.7.3 (default, Apr 24 2012, 00:00:54) 
[GCC 4.7.0 20120414 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> ts = time.time()
>>> print ts
1355563265.81
>>> import datetime
>>> st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
>>> print st
2012-12-15 01:21:05
>>>

ts变量是在几秒钟内返回的时间。然后,我使用datetime库将其转换为字符串,从而使其成为人类可读的字符串。

The time.time() function returns the number of seconds since the epoch, as seconds. Note that the “epoch” is defined as the start of January 1st, 1970 in UTC. So the epoch is defined in terms of UTC and establishes a global moment in time. No matter where you are “seconds past epoch” (time.time()) returns the same value at the same moment.

Here is some sample output I ran on my computer, converting it to a string as well.

Python 2.7.3 (default, Apr 24 2012, 00:00:54) 
[GCC 4.7.0 20120414 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> ts = time.time()
>>> print ts
1355563265.81
>>> import datetime
>>> st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
>>> print st
2012-12-15 01:21:05
>>>

The ts variable is the time returned in seconds. I then converted it to a string using the datetime library making it a string that is human readable.


回答 1

这是用于时间戳记文本形式可以在文本文件中使用。(问题的标题在过去是不同的,因此对该答案的介绍进行了更改,以阐明如何将其解释为时间。[2016年1月14日更新])

您可以使用.now().utcnow()来将时间戳记作为字符串获取datetime.datetime

>>> import datetime
>>> print datetime.datetime.utcnow()
2012-12-15 10:14:51.898000

now不同之处utcnow与预期的不同-否则它们以相同的方式工作:

>>> print datetime.datetime.now()
2012-12-15 11:15:09.205000

您可以将时间戳显式呈现给字符串:

>>> str(datetime.datetime.now())
'2012-12-15 11:15:24.984000'

或者,您甚至可以更明确地以自己喜欢的方式格式化时间戳记:

>>> datetime.datetime.now().strftime("%A, %d. %B %Y %I:%M%p")
'Saturday, 15. December 2012 11:19AM'

如果要使用ISO格式,请使用.isoformat()对象的方法:

>>> datetime.datetime.now().isoformat()
'2013-11-18T08:18:31.809000'

您可以在变量中使用这些变量来进行计算和打印,而无需进行转换。

>>> ts = datetime.datetime.now()
>>> tf = datetime.datetime.now()
>>> te = tf - ts
>>> print ts
2015-04-21 12:02:19.209915
>>> print tf
2015-04-21 12:02:30.449895
>>> print te
0:00:11.239980

This is for the text form of a timestamp that can be used in your text files. (The title of the question was different in the past, so the introduction to this answer was changed to clarify how it could be interpreted as the time. [updated 2016-01-14])

You can get the timestamp as a string using the .now() or .utcnow() of the datetime.datetime:

>>> import datetime
>>> print datetime.datetime.utcnow()
2012-12-15 10:14:51.898000

The now differs from utcnow as expected — otherwise they work the same way:

>>> print datetime.datetime.now()
2012-12-15 11:15:09.205000

You can render the timestamp to the string explicitly:

>>> str(datetime.datetime.now())
'2012-12-15 11:15:24.984000'

Or you can be even more explicit to format the timestamp the way you like:

>>> datetime.datetime.now().strftime("%A, %d. %B %Y %I:%M%p")
'Saturday, 15. December 2012 11:19AM'

If you want the ISO format, use the .isoformat() method of the object:

>>> datetime.datetime.now().isoformat()
'2013-11-18T08:18:31.809000'

You can use these in variables for calculations and printing without conversions.

>>> ts = datetime.datetime.now()
>>> tf = datetime.datetime.now()
>>> te = tf - ts
>>> print ts
2015-04-21 12:02:19.209915
>>> print tf
2015-04-21 12:02:30.449895
>>> print te
0:00:11.239980

回答 2

根据#squiguy的答案,要获得真实的时间戳,我会键入从float转换的时间戳。

>>> import time
>>> ts = int(time.time())
>>> print(ts)
1389177318

至少那是概念。

Based on the answer from #squiguy, to get a true timestamp I would type cast it from float.

>>> import time
>>> ts = int(time.time())
>>> print(ts)
1389177318

At least that’s the concept.


回答 3

答案可能不是两者皆有。

  • 都不:time.time()返回距新纪元已过去的秒数。结果不取决于时区,因此它既不是UTC也不是本地时间。这是“自大纪元以来的第二个”POSIX定义

  • 两者:time.time()不需要同步系统时钟,因此它可以反映其值(尽管它与本地时区无关)。不同的计算机可能同时获得不同的结果。另一方面,如果您的计算机时间同步的,那么很容易从时间戳中获取UTC时间(如果我们忽略leap秒):

    from datetime import datetime
    
    utc_dt = datetime.utcfromtimestamp(timestamp)

有关如何从各种Python版本的UTC时间获取时间戳的信息,请参见如何根据UTC将日期转换为自纪元以来的秒数?

The answer could be neither or both.

  • neither: time.time() returns approximately the number of seconds elapsed since the Epoch. The result doesn’t depend on timezone so it is neither UTC nor local time. Here’s POSIX defintion for “Seconds Since the Epoch”.

  • both: time.time() doesn’t require your system’s clock to be synchronized so it reflects its value (though it has nothing to do with local timezone). Different computers may get different results at the same time. On the other hand if your computer time is synchronized then it is easy to get UTC time from the timestamp (if we ignore leap seconds):

    from datetime import datetime
    
    utc_dt = datetime.utcfromtimestamp(timestamp)
    

On how to get timestamps from UTC time in various Python versions, see How can I get a date converted to seconds since epoch according to UTC?


回答 4

我最终选择了:

>>> import time
>>> time.mktime(time.gmtime())
1509467455.0

I eventually settled for:

>>> import time
>>> time.mktime(time.gmtime())
1509467455.0

回答 5

在特定的时区没有“时代”这样的东西。纪元已明确定义为特定时间,因此,如果您更改时区,则时间本身也会改变。具体来说,这次是Jan 1 1970 00:00:00 UTC。因此time.time()返回自纪元以来的秒数。

There is no such thing as an “epoch” in a specific timezone. The epoch is well-defined as a specific moment in time, so if you change the timezone, the time itself changes as well. Specifically, this time is Jan 1 1970 00:00:00 UTC. So time.time() returns the number of seconds since the epoch.


回答 6

时间戳始终是utc中的时间,但是当您调用datetime.datetime.fromtimestamp 它时,它会返回与该时间戳相对应的本地时区中的时间,因此结果取决于您的语言环境。

>>> import time, datetime

>>> time.time()
1564494136.0434234

>>> datetime.datetime.now()
datetime.datetime(2019, 7, 30, 16, 42, 3, 899179)
>>> datetime.datetime.fromtimestamp(time.time())
datetime.datetime(2019, 7, 30, 16, 43, 12, 4610)

存在arrow具有不同行为的漂亮的库。在相同情况下,它会返回带有UTC时区的时间对象。

>>> import arrow
>>> arrow.now()
<Arrow [2019-07-30T16:43:27.868760+03:00]>
>>> arrow.get(time.time())
<Arrow [2019-07-30T13:43:56.565342+00:00]>

timestamp is always time in utc, but when you call datetime.datetime.fromtimestamp it returns you time in your local timezone corresponding to this timestamp, so result depend of your locale.

>>> import time, datetime

>>> time.time()
1564494136.0434234

>>> datetime.datetime.now()
datetime.datetime(2019, 7, 30, 16, 42, 3, 899179)
>>> datetime.datetime.fromtimestamp(time.time())
datetime.datetime(2019, 7, 30, 16, 43, 12, 4610)

There exist nice library arrow with different behaviour. In same case it returns you time object with UTC timezone.

>>> import arrow
>>> arrow.now()
<Arrow [2019-07-30T16:43:27.868760+03:00]>
>>> arrow.get(time.time())
<Arrow [2019-07-30T13:43:56.565342+00:00]>

获取当前目录中所有子目录的列表

问题:获取当前目录中所有子目录的列表

有没有办法在Python中返回当前目录中所有子目录的列表?

我知道您可以使用文件来执行此操作,但是我需要获取目录列表。

Is there a way to return a list of all the subdirectories in the current directory in Python?

I know you can do this with files, but I need to get the list of directories instead.


回答 0

您是指直接子目录,还是树下的每个目录?

无论哪种方式,您都可以使用os.walk以下方法:

os.walk(directory)

将为每个子目录生成一个元组。该三元组中的第一个条目是目录名称,因此

[x[0] for x in os.walk(directory)]

应该递归地给你所有的子目录。

请注意,该元组中的第二个条目是该条目的子目录列表的第一个位置,因此您可以改用它,但是不太可能为您节省很多。

但是,您可以使用它来为您提供直接的子目录:

next(os.walk('.'))[1]

或者使用os.listdir和查看已经发布的其他解决方案os.path.isdir,包括“ 如何在Python中获取所有直接子目录 ”中的解决方案。

Do you mean immediate subdirectories, or every directory right down the tree?

Either way, you could use os.walk to do this:

os.walk(directory)

will yield a tuple for each subdirectory. Ths first entry in the 3-tuple is a directory name, so

[x[0] for x in os.walk(directory)]

should give you all of the subdirectories, recursively.

Note that the second entry in the tuple is the list of child directories of the entry in the first position, so you could use this instead, but it’s not likely to save you much.

However, you could use it just to give you the immediate child directories:

next(os.walk('.'))[1]

Or see the other solutions already posted, using os.listdir and os.path.isdir, including those at “How to get all of the immediate subdirectories in Python“.


回答 1

import os

d = '.'
[os.path.join(d, o) for o in os.listdir(d) 
                    if os.path.isdir(os.path.join(d,o))]
import os

d = '.'
[os.path.join(d, o) for o in os.listdir(d) 
                    if os.path.isdir(os.path.join(d,o))]

回答 2

你可以用 glob.glob

from glob import glob
glob("/path/to/directory/*/")

别忘了/之后的尾随*

You could just use glob.glob

from glob import glob
glob("/path/to/directory/*/")

Don’t forget the trailing / after the *.


回答 3

比上面的要好得多,因为您不需要几个os.path.join(),并且可以直接获取完整路径(如果需要),因此可以在Python 3.5及更高版本中执行此操作。

subfolders = [ f.path for f in os.scandir(folder) if f.is_dir() ]

这将提供到子目录的完整路径。如果只希望使用子目录的名称,f.name而不是f.path

https://docs.python.org/3/library/os.html#os.scandir


OT:如果您需要递归所有子文件夹和/或所有文件,请看一下此功能,它比os.walk&快,glob并且将返回所有子文件夹以及这些(子)子文件夹中的所有文件的列表:https://stackoverflow.com/a/59803793/2441026

如果您只需要递归所有子文件夹

def fast_scandir(dirname):
    subfolders= [f.path for f in os.scandir(dirname) if f.is_dir()]
    for dirname in list(subfolders):
        subfolders.extend(fast_scandir(dirname))
    return subfolders

返回所有子文件夹及其完整路径的列表。这又比os.walk和快得多glob


所有功能分析

tl; dr:
-如果要获取文件夹使用的所有直接子目录os.scandir
-如果要获取所有子目录,甚至嵌套的子目录,请使用os.walk或-稍微快一点- fast_scandir上面的函数。
-从来不使用os.walk只顶级子目录,因为它可以是数百倍慢于(!) os.scandir

  • 如果您运行下面的代码,请确保运行一次,以便您的操作系统可以访问该文件夹,丢弃结果并运行测试,否则结果将被弄乱。
  • 您可能想混淆函数调用,但是我对其进行了测试,但这并不重要。
  • 所有示例都将提供文件夹的完整路径。pathlib示例作为(Windows)Path对象。
  • 的第一个元素os.walk将是基本文件夹。因此,您将不会仅获得子目录。您可以使用fu.pop(0)将其删除。
  • 所有结果都不会使用自然排序。这意味着将对结果进行如下排序:1、10、2。要进行自然排序(1、2、10),请查看https://stackoverflow.com/a/48030307/2441026


结果

os.scandir      took   1 ms. Found dirs: 439
os.walk         took 463 ms. Found dirs: 441 -> it found the nested one + base folder.
glob.glob       took  20 ms. Found dirs: 439
pathlib.iterdir took  18 ms. Found dirs: 439
os.listdir      took  18 ms. Found dirs: 439

已在W7x64,Python 3.8.1中测试。

# -*- coding: utf-8 -*-
# Python 3


import time
import os
from glob import glob
from pathlib import Path


directory = r"<insert_folder>"
RUNS = 1


def run_os_walk():
    a = time.time_ns()
    for i in range(RUNS):
        fu = [x[0] for x in os.walk(directory)]
    print(f"os.walk\t\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_glob():
    a = time.time_ns()
    for i in range(RUNS):
        fu = glob(directory + "/*/")
    print(f"glob.glob\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_pathlib_iterdir():
    a = time.time_ns()
    for i in range(RUNS):
        dirname = Path(directory)
        fu = [f for f in dirname.iterdir() if f.is_dir()]
    print(f"pathlib.iterdir\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_listdir():
    a = time.time_ns()
    for i in range(RUNS):
        dirname = Path(directory)
        fu = [os.path.join(directory, o) for o in os.listdir(directory) if os.path.isdir(os.path.join(directory, o))]
    print(f"os.listdir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_scandir():
    a = time.time_ns()
    for i in range(RUNS):
        fu = [f.path for f in os.scandir(directory) if f.is_dir()]
    print(f"os.scandir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms.\tFound dirs: {len(fu)}")


if __name__ == '__main__':
    run_os_scandir()
    run_os_walk()
    run_glob()
    run_pathlib_iterdir()
    run_os_listdir()

Much nicer than the above, because you don’t need several os.path.join() and you will get the full path directly (if you wish), you can do this in Python 3.5 and above.

subfolders = [ f.path for f in os.scandir(folder) if f.is_dir() ]

This will give the complete path to the subdirectory. If you only want the name of the subdirectory use f.name instead of f.path

https://docs.python.org/3/library/os.html#os.scandir


Slightly OT: In case you need all subfolder recursively and/or all files recursively, have a look at this function, that is faster than os.walk & glob and will return a list of all subfolders as well as all files inside those (sub-)subfolders: https://stackoverflow.com/a/59803793/2441026

In case you want only all subfolders recursively:

def fast_scandir(dirname):
    subfolders= [f.path for f in os.scandir(dirname) if f.is_dir()]
    for dirname in list(subfolders):
        subfolders.extend(fast_scandir(dirname))
    return subfolders

Returns a list of all subfolders with their full paths. This again is faster than os.walk and a lot faster than glob.


An analysis of all functions

tl;dr:
– If you want to get all immediate subdirectories for a folder use os.scandir.
– If you want to get all subdirectories, even nested ones, use os.walk or – slightly faster – the fast_scandir function above.
– Never use os.walk for only top-level subdirectories, as it can be hundreds(!) of times slower than os.scandir.

  • If you run the code below, make sure to run it once so that your OS will have accessed the folder, discard the results and run the test, otherwise results will be screwed.
  • You might want to mix up the function calls, but I tested it, and it did not really matter.
  • All examples will give the full path to the folder. The pathlib example as a (Windows)Path object.
  • The first element of os.walk will be the base folder. So you will not get only subdirectories. You can use fu.pop(0) to remove it.
  • None of the results will use natural sorting. This means results will be sorted like this: 1, 10, 2. To get natural sorting (1, 2, 10), please have a look at https://stackoverflow.com/a/48030307/2441026


Results:

os.scandir      took   1 ms. Found dirs: 439
os.walk         took 463 ms. Found dirs: 441 -> it found the nested one + base folder.
glob.glob       took  20 ms. Found dirs: 439
pathlib.iterdir took  18 ms. Found dirs: 439
os.listdir      took  18 ms. Found dirs: 439

Tested with W7x64, Python 3.8.1.

# -*- coding: utf-8 -*-
# Python 3


import time
import os
from glob import glob
from pathlib import Path


directory = r"<insert_folder>"
RUNS = 1


def run_os_walk():
    a = time.time_ns()
    for i in range(RUNS):
        fu = [x[0] for x in os.walk(directory)]
    print(f"os.walk\t\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_glob():
    a = time.time_ns()
    for i in range(RUNS):
        fu = glob(directory + "/*/")
    print(f"glob.glob\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_pathlib_iterdir():
    a = time.time_ns()
    for i in range(RUNS):
        dirname = Path(directory)
        fu = [f for f in dirname.iterdir() if f.is_dir()]
    print(f"pathlib.iterdir\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_listdir():
    a = time.time_ns()
    for i in range(RUNS):
        dirname = Path(directory)
        fu = [os.path.join(directory, o) for o in os.listdir(directory) if os.path.isdir(os.path.join(directory, o))]
    print(f"os.listdir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_scandir():
    a = time.time_ns()
    for i in range(RUNS):
        fu = [f.path for f in os.scandir(directory) if f.is_dir()]
    print(f"os.scandir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms.\tFound dirs: {len(fu)}")


if __name__ == '__main__':
    run_os_scandir()
    run_os_walk()
    run_glob()
    run_pathlib_iterdir()
    run_os_listdir()

回答 4

如果您需要一个可在子目录中找到所有子目录的递归解决方案,请按照之前的建议使用walk。

如果仅需要当前目录的子目录,请os.listdiros.path.isdir

If you need a recursive solution that will find all the subdirectories in the subdirectories, use walk as proposed before.

If you only need the current directory’s child directories, combine os.listdir with os.path.isdir


回答 5

我更喜欢使用过滤器(https://docs.python.org/2/library/functions.html#filter),但这只是一个问题。

d='.'
filter(lambda x: os.path.isdir(os.path.join(d, x)), os.listdir(d))

I prefer using filter (https://docs.python.org/2/library/functions.html#filter), but this is just a matter of taste.

d='.'
filter(lambda x: os.path.isdir(os.path.join(d, x)), os.listdir(d))

回答 6

使用python-os-walk实现了这一点。(http://www.pythonforbeginners.com/code-snippets-source-code/python-os-walk/

import os

print("root prints out directories only from what you specified")
print("dirs prints out sub-directories from root")
print("files prints out all files from root and directories")
print("*" * 20)

for root, dirs, files in os.walk("/var/log"):
    print(root)
    print(dirs)
    print(files)

Implemented this using python-os-walk. (http://www.pythonforbeginners.com/code-snippets-source-code/python-os-walk/)

import os

print("root prints out directories only from what you specified")
print("dirs prints out sub-directories from root")
print("files prints out all files from root and directories")
print("*" * 20)

for root, dirs, files in os.walk("/var/log"):
    print(root)
    print(dirs)
    print(files)

回答 7

您可以使用os.listdir(path)获取Python 2.7中的子目录(和文件)列表

import os
os.listdir(path)  # list of subdirectories and files

You can get the list of subdirectories (and files) in Python 2.7 using os.listdir(path)

import os
os.listdir(path)  # list of subdirectories and files

回答 8

仅列出目录

print("\nWe are listing out only the directories in current directory -")
directories_in_curdir = filter(os.path.isdir, os.listdir(os.curdir))
print(directories_in_curdir)

仅列出当前目录中的文件

files = filter(os.path.isfile, os.listdir(os.curdir))
print("\nThe following are the list of all files in the current directory -")
print(files)

Listing Out only directories

print("\nWe are listing out only the directories in current directory -")
directories_in_curdir = filter(os.path.isdir, os.listdir(os.curdir))
print(directories_in_curdir)

Listing Out only files in current directory

files = filter(os.path.isfile, os.listdir(os.curdir))
print("\nThe following are the list of all files in the current directory -")
print(files)

回答 9

蟒3.4引入pathlib模块到标准库,它提供了一个面向对象的方法来处理的文件系统的路径:

from pathlib import Path

p = Path('./')

# List comprehension
[f for f in p.iterdir() if f.is_dir()]

# The trailing slash to glob indicated directories
# This will also include the current directory '.'
list(p.glob('**/'))

也可以通过PyPi上的pathlib2模块在 Python 2.7 上使用Pathlib。

Python 3.4 introduced the pathlib module into the standard library, which provides an object oriented approach to handle filesystem paths:

from pathlib import Path

p = Path('./')

# List comprehension
[f for f in p.iterdir() if f.is_dir()]

# The trailing slash to glob indicated directories
# This will also include the current directory '.'
list(p.glob('**/'))

Pathlib is also available on Python 2.7 via the pathlib2 module on PyPi.


回答 10

由于我使用Python 3.4和Windows UNC路径偶然发现了此问题,因此以下是此环境的变体:

from pathlib import WindowsPath

def SubDirPath (d):
    return [f for f in d.iterdir() if f.is_dir()]

subdirs = SubDirPath(WindowsPath(r'\\file01.acme.local\home$'))
print(subdirs)

Pathlib是Python 3.4中的新增功能,它使在不同操作系统下使用路径变得更加容易:https ://docs.python.org/3.4/library/pathlib.html

Since I stumbled upon this problem using Python 3.4 and Windows UNC paths, here’s a variant for this environment:

from pathlib import WindowsPath

def SubDirPath (d):
    return [f for f in d.iterdir() if f.is_dir()]

subdirs = SubDirPath(WindowsPath(r'\\file01.acme.local\home$'))
print(subdirs)

Pathlib is new in Python 3.4 and makes working with paths under different OSes much easier: https://docs.python.org/3.4/library/pathlib.html


回答 11

尽管很久以前就回答了这个问题。我想建议使用该pathlib模块,因为这是在Windows和Unix OS上工作的可靠方法。

因此,要获取特定目录(包括子目录)中的所有路径:

from pathlib import Path
paths = list(Path('myhomefolder', 'folder').glob('**/*.txt'))

# all sorts of operations
file = paths[0]
file.name
file.stem
file.parent
file.suffix

等等

Although this question is answered a long time ago. I want to recommend to use the pathlib module since this is a robust way to work on Windows and Unix OS.

So to get all paths in a specific directory including subdirectories:

from pathlib import Path
paths = list(Path('myhomefolder', 'folder').glob('**/*.txt'))

# all sorts of operations
file = paths[0]
file.name
file.stem
file.parent
file.suffix

etc.


回答 12

谢谢提醒伙计。我遇到了一个以dirs返回的软链接(无限递归)的问题。软链接?我们不希望没有臭味的软链接!所以…

这仅显示目录,而不显示软链接:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']

Thanks for the tips, guys. I ran into an issue with softlinks (infinite recursion) being returned as dirs. Softlinks? We don’t want no stinkin’ soft links! So…

This rendered just the dirs, not softlinks:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']

回答 13

复制粘贴友好ipython

import os
d='.'
folders = list(filter(lambda x: os.path.isdir(os.path.join(d, x)), os.listdir(d)))

来自的输出print(folders)

['folderA', 'folderB']

Copy paste friendly in ipython:

import os
d='.'
folders = list(filter(lambda x: os.path.isdir(os.path.join(d, x)), os.listdir(d)))

Output from print(folders):

['folderA', 'folderB']

回答 14

这就是我的方法。

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)

This is how I do it.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)

回答 15

这是基于@Blair Conrad的示例的几个简单函数-

import os

def get_subdirs(dir):
    "Get a list of immediate subdirectories"
    return next(os.walk(dir))[1]

def get_subfiles(dir):
    "Get a list of immediate subfiles"
    return next(os.walk(dir))[2]

Here are a couple of simple functions based on @Blair Conrad’s example –

import os

def get_subdirs(dir):
    "Get a list of immediate subdirectories"
    return next(os.walk(dir))[1]

def get_subfiles(dir):
    "Get a list of immediate subfiles"
    return next(os.walk(dir))[2]

回答 16

在Eli Bendersky解决方案的基础上,使用以下示例:

import os
test_directory = <your_directory>
for child in os.listdir(test_directory):
    test_path = os.path.join(test_directory, child)
    if os.path.isdir(test_path):
        print test_path
        # Do stuff to the directory "test_path"

<your_directory>您要遍历的目录的路径在哪里。

Building upon Eli Bendersky’s solution, use the following example:

import os
test_directory = <your_directory>
for child in os.listdir(test_directory):
    test_path = os.path.join(test_directory, child)
    if os.path.isdir(test_path):
        print test_path
        # Do stuff to the directory "test_path"

where <your_directory> is the path to the directory you want to traverse.


回答 17

有了完整路径和占路感...\\..\\..\\subfolder,等:

import os, pprint
pprint.pprint([os.path.join(os.path.abspath(path), x[0]) \
    for x in os.walk(os.path.abspath(path))])

With full path and accounting for path being ., .., \\, ..\\..\\subfolder, etc:

import os, pprint
pprint.pprint([os.path.join(os.path.abspath(path), x[0]) \
    for x in os.walk(os.path.abspath(path))])

回答 18

这个答案似乎还不存在。

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]

This answer didn’t seem to exist already.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]

回答 19

我最近有一个类似的问题,我发现python 3.6(作为用户havlock添加)的最佳答案是使用os.scandir。由于似乎没有使用它的解决方案,因此我将添加自己的解决方案。首先,一种非递归解决方案,仅列出直接位于根目录下的子目录。

def get_dirlist(rootdir):

    dirlist = []

    with os.scandir(rootdir) as rit:
        for entry in rit:
            if not entry.name.startswith('.') and entry.is_dir():
                dirlist.append(entry.path)

    dirlist.sort() # Optional, in case you want sorted directory names
    return dirlist

递归版本如下所示:

def get_dirlist(rootdir):

    dirlist = []

    with os.scandir(rootdir) as rit:
        for entry in rit:
            if not entry.name.startswith('.') and entry.is_dir():
                dirlist.append(entry.path)
                dirlist += get_dirlist(entry.path)

    dirlist.sort() # Optional, in case you want sorted directory names
    return dirlist

请记住,这entry.path将使用子目录的绝对路径。如果只需要文件夹名称,则可以entry.name改用。有关该对象的更多详细信息,请参考os.DirEntryentry

I’ve had a similar question recently, and I found out that the best answer for python 3.6 (as user havlock added) is to use os.scandir. Since it seems there is no solution using it, I’ll add my own. First, a non-recursive solution that lists only the subdirectories directly under the root directory.

def get_dirlist(rootdir):

    dirlist = []

    with os.scandir(rootdir) as rit:
        for entry in rit:
            if not entry.name.startswith('.') and entry.is_dir():
                dirlist.append(entry.path)

    dirlist.sort() # Optional, in case you want sorted directory names
    return dirlist

The recursive version would look like this:

def get_dirlist(rootdir):

    dirlist = []

    with os.scandir(rootdir) as rit:
        for entry in rit:
            if not entry.name.startswith('.') and entry.is_dir():
                dirlist.append(entry.path)
                dirlist += get_dirlist(entry.path)

    dirlist.sort() # Optional, in case you want sorted directory names
    return dirlist

keep in mind that entry.path wields the absolute path to the subdirectory. In case you only need the folder name, you can use entry.name instead. Refer to os.DirEntry for additional details about the entry object.


回答 20

os.path.isdiros.listdir() 这样的东西使用过滤器功能filter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])

use a filter function os.path.isdir over os.listdir() something like this filter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])


回答 21

这将在文件树的右边列出所有子目录。

import pathlib


def list_dir(dir):
    path = pathlib.Path(dir)
    dir = []
    try:
        for item in path.iterdir():
            if item.is_dir():
                dir.append(item)
                dir = dir + list_dir(item)
        return dir
    except FileNotFoundError:
        print('Invalid directory')

pathlib 是3.4版的新功能

This will list all subdirectories right down the file tree.

import pathlib


def list_dir(dir):
    path = pathlib.Path(dir)
    dir = []
    try:
        for item in path.iterdir():
            if item.is_dir():
                dir.append(item)
                dir = dir + list_dir(item)
        return dir
    except FileNotFoundError:
        print('Invalid directory')

pathlib is new in version 3.4


回答 22

返回给定文件路径中所有子目录的列表的函数。将搜索整个文件树。

import os

def get_sub_directory_paths(start_directory, sub_directories):
    """
    This method iterates through all subdirectory paths of a given 
    directory to collect all directory paths.

    :param start_directory: The starting directory path.
    :param sub_directories: A List that all subdirectory paths will be 
        stored to.
    :return: A List of all sub-directory paths.
    """

    for item in os.listdir(start_directory):
        full_path = os.path.join(start_directory, item)

        if os.path.isdir(full_path):
            sub_directories.append(full_path)

            # Recursive call to search through all subdirectories.
            get_sub_directory_paths(full_path, sub_directories)

return sub_directories

Function to return a List of all subdirectories within a given file path. Will search through the entire file tree.

import os

def get_sub_directory_paths(start_directory, sub_directories):
    """
    This method iterates through all subdirectory paths of a given 
    directory to collect all directory paths.

    :param start_directory: The starting directory path.
    :param sub_directories: A List that all subdirectory paths will be 
        stored to.
    :return: A List of all sub-directory paths.
    """

    for item in os.listdir(start_directory):
        full_path = os.path.join(start_directory, item)

        if os.path.isdir(full_path):
            sub_directories.append(full_path)

            # Recursive call to search through all subdirectories.
            get_sub_directory_paths(full_path, sub_directories)

return sub_directories

回答 23

我们可以使用os.walk()获取所有文件夹的列表

import os

path = os.getcwd()

pathObject = os.walk(path)

这个pathObject是一个对象,我们可以通过

arr = [x for x in pathObject]

arr is of type [('current directory', [array of folder in current directory], [files in current directory]),('subdirectory', [array of folder in subdirectory], [files in subdirectory]) ....]

我们可以通过遍历arr并打印中间数组来获取所有子目录的列表

for i in arr:
   for j in i[1]:
      print(j)

这将打印所有子目录。

要获取所有文件:

for i in arr:
   for j in i[2]:
      print(i[0] + "/" + j)

we can get list of all the folders by using os.walk()

import os

path = os.getcwd()

pathObject = os.walk(path)

this pathObject is a object and we can get an array by

arr = [x for x in pathObject]

arr is of type [('current directory', [array of folder in current directory], [files in current directory]),('subdirectory', [array of folder in subdirectory], [files in subdirectory]) ....]

We can get list of all the subdirectory by iterating through the arr and printing the middle array

for i in arr:
   for j in i[1]:
      print(j)

This will print all the subdirectory.

To get all the files:

for i in arr:
   for j in i[2]:
      print(i[0] + "/" + j)

回答 24

具有给定父级的该函数以递归方式directory遍历其所有函数directories以及printsfilenames其中找到的所有函数。太有用了。

import os

def printDirectoryFiles(directory):
   for filename in os.listdir(directory):  
        full_path=os.path.join(directory, filename)
        if not os.path.isdir(full_path): 
            print( full_path + "\n")


def checkFolders(directory):

    dir_list = next(os.walk(directory))[1]

    #print(dir_list)

    for dir in dir_list:           
        print(dir)
        checkFolders(directory +"/"+ dir) 

    printDirectoryFiles(directory)       

main_dir="C:/Users/S0082448/Desktop/carpeta1"

checkFolders(main_dir)


input("Press enter to exit ;")

This function, with a given parent directory iterates over all its directories recursively and prints all the filenames which it founds inside. Too useful.

import os

def printDirectoryFiles(directory):
   for filename in os.listdir(directory):  
        full_path=os.path.join(directory, filename)
        if not os.path.isdir(full_path): 
            print( full_path + "\n")


def checkFolders(directory):

    dir_list = next(os.walk(directory))[1]

    #print(dir_list)

    for dir in dir_list:           
        print(dir)
        checkFolders(directory +"/"+ dir) 

    printDirectoryFiles(directory)       

main_dir="C:/Users/S0082448/Desktop/carpeta1"

checkFolders(main_dir)


input("Press enter to exit ;")


回答 25

通过从此处加入多个解决方案,这就是我最终使用的方法:

import os
import glob

def list_dirs(path):
    return [os.path.basename(x) for x in filter(
        os.path.isdir, glob.glob(os.path.join(path, '*')))]

By joining multiple solutions from here, this is what I ended up using:

import os
import glob

def list_dirs(path):
    return [os.path.basename(x) for x in filter(
        os.path.isdir, glob.glob(os.path.join(path, '*')))]