标签归档:reflection

如何在Python中枚举对象的属性?

问题:如何在Python中枚举对象的属性?

IC#我们通过反思来做到。在Javascript中,它很简单:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

如何在Python中完成?

I C# we do it through reflection. In Javascript it is simple as:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

How to do it in Python?


回答 0

for property, value in vars(theObject).iteritems():
    print property, ": ", value

请注意,在极少数情况下,有一个__slots__属性,此类通常没有属性__dict__

for property, value in vars(theObject).items():
    print(property, ":", value)

Be aware that in some rare cases there’s a __slots__ property, such classes often have no __dict__.


回答 1

请参阅inspect.getmembers(object[, predicate])

返回按名称排序的(名称,值)对列表中的对象的所有成员。如果提供了可选的谓词参数,则仅包含谓词为其返回真值的成员。

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 

See inspect.getmembers(object[, predicate]).

Return all the members of an object in a list of (name, value) pairs sorted by name. If the optional predicate argument is supplied, only members for which the predicate returns a true value are included.

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 

回答 2

dir()是简单的方法。看这里:

Python自省指南


回答 3

__dict__对象的属性是其所有其他定义的属性的字典。请注意,Python类可以覆盖getattr 并使内容看起来像属性,而不是in __dict__。还有一些内置函数vars()dir()它们在微妙的方式上有所不同。并且__slots__可以代替__dict__一些不寻常的类。

Python中的对象很复杂。__dict__是开始进行反射式编程的正确位置。dir()如果您是在交互式shell中四处乱逛,那么这是一个开始的地方。

The __dict__ property of the object is a dictionary of all its other defined properties. Note that Python classes can override getattr and make things that look like properties but are not in__dict__. There’s also the builtin functions vars() and dir() which are different in subtle ways. And __slots__ can replace __dict__ in some unusual classes.

Objects are complicated in Python. __dict__ is the right place to start for reflection-style programming. dir() is the place to start if you’re hacking around in an interactive shell.


回答 4

georg scholly短版

print vars(theObject)

for one-liners:

print vars(theObject)

回答 5

如果您正在寻找所有属性的反映,那么上面的答案很好。

如果您只是想获取字典的键(与Python中的“对象”不同),请使用

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

If you’re looking for reflection of all properties, the answers above are great.

If you’re simply looking to get the keys of a dictionary (which is different from an ‘object’ in Python), use

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

回答 6

其他答案完全涵盖了这一点,但我将使其明确。对象可以具有类属性以及静态和动态实例属性。

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasis是静态的,dyno是动态的(请参阅属性装饰器),并且classy是类属性。如果我们简单地做,__dict__否则vars我们只会得到静态的。

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

因此,如果我们希望其他人__dict__都能得到一切(甚至更多)。这包括魔术方法和属性以及法线绑定方法。因此,请避免这些情况:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

type具有属性修饰方法(动态属性)的调用将为您提供返回值的类型,而不是method。为了证明这一点,让我们用json将其字符串化:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

如果这是一种方法,它将崩溃。

TL; DR。尝试同时调用extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}这三个方法,但不要调用方法或魔术。

This is totally covered by the other answers, but I’ll make it explicit. An object may have class attributes and static and dynamic instance attributes.

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasis is static, dyno is dynamic (cf. property decorator) and classy is a class attribute. If we simply do __dict__ or vars we will only get the static one.

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

So if we want the others __dict__ will get everything (and more). This includes magic methods and attributes and normal bound methods. So lets avoid those:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

The type called with a property decorated method (a dynamic attribute) will give you the type of the returned value, not method. To prove this let’s json stringify it:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

Had it been a method it would have crashed.

TL;DR. try calling extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'} for all three, but not methods nor magic.


如何动态加载Python类

问题:如何动态加载Python类

给定一个Python类的字符串,例如my_package.my_module.MyClass,最好的加载方式是什么?

换句话说,我正在寻找Class.forName()Java中等效的Python函数。它需要在Google App Engine上工作。

最好是一个函数,该函数接受类的FQN作为字符串,并返回对该类的引用:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

Given a string of a Python class, e.g. my_package.my_module.MyClass, what is the best possible way to load it?

In other words I am looking for a equivalent Class.forName() in Java, function in Python. It needs to work on Google App Engine.

Preferably this would be a function that accepts the FQN of the class as a string, and returns a reference to the class:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

回答 0

在python文档中,这是您想要的功能:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

一个简单的方法__import__不起作用的原因是,任何超出包字符串中第一个点的导入都是您要导入的模块的属性。因此,类似这样的方法将不起作用:

__import__('foo.bar.baz.qux')

您必须像这样调用上述函数:

my_import('foo.bar.baz.qux')

或以您的示例为例:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

编辑:我对此有些反对。您基本上想做的是这样的:

from my_package.my_module import my_class

仅当您的发件人列表为空时,才需要上述功能。因此,适当的调用将如下所示:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

From the python documentation, here’s the function you want:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

The reason a simple __import__ won’t work is because any import of anything past the first dot in a package string is an attribute of the module you’re importing. Thus, something like this won’t work:

__import__('foo.bar.baz.qux')

You’d have to call the above function like so:

my_import('foo.bar.baz.qux')

Or in the case of your example:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

EDIT: I was a bit off on this. What you’re basically wanting to do is this:

from my_package.my_module import my_class

The above function is only necessary if you have a empty fromlist. Thus, the appropriate call would be like this:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

回答 1

如果您不想自己动手,则pydoc模块中有一个函数可以完全执行此操作:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

与此处列出的其他方法相比,此方法的优势在于,locate它将在提供的虚线路径中找到任何 python对象,而不仅仅是直接在模块内的对象。例如my_package.my_module.MyClass.attr

如果您想知道他们的食谱是什么,请使用以下功能:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

它依赖pydoc.safeimport功能。这是该文档:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

If you don’t want to roll your own, there is a function available in the pydoc module that does exactly this:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

The advantage of this approach over the others listed here is that locate will find any python object at the provided dotted path, not just an object directly within a module. e.g. my_package.my_module.MyClass.attr.

If you’re curious what their recipe is, here’s the function:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

It relies on pydoc.safeimport function. Here are the docs for that:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

回答 2

import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()

回答 3

def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)

回答 4

如果您使用的是Django,则可以使用它。是的,我知道OP并没有要求使用django,但是我遇到了一个问题,寻找Django解决方案,没有找到一个解决方案,并将其放在这里供下一个寻找它的下一个男孩/女孩使用。

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

请记住,如果您要导入不带.re或的东西,请argparse使用:

re = __import__('re')

If you’re using Django you can use this. Yes i’m aware OP did not ask for django, but i ran across this question looking for a Django solution, didn’t find one, and put it here for the next boy/gal that looks for it.

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

Keep in mind, if you want to import something that doesn’t have a ., like re or argparse use:

re = __import__('re')

回答 5

这里是分享我在__import__和发现的东西importlib试图解决这个问题。

我正在使用Python 3.7.3。

当我尝试进入d模块中的类时a.b.c

mod = __import__('a.b.c')

mod变量引用顶部命名空间a

所以要上课d,我需要

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

如果我们尝试去做

mod = __import__('a.b.c')
d = getattr(mod, 'd')

我们实际上是在寻找a.d

使用时importlib,我想该库已getattr为我们完成了递归操作。因此,当我们使用时importlib.import_module,我们实际上得到了最深模块的句柄。

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

Here is to share something I found on __import__ and importlib while trying to solve this problem.

I am using Python 3.7.3.

When I try to get to the class d in module a.b.c,

mod = __import__('a.b.c')

The mod variable refer to the top namespace a.

So to get to the class d, I need to

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

If we try to do

mod = __import__('a.b.c')
d = getattr(mod, 'd')

we are actually trying to look for a.d.

When using importlib, I suppose the library has done the recursive getattr for us. So, when we use importlib.import_module, we actually get a handle on the deepest module.

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

回答 6

好的,对我来说,这就是它的工作方式(我正在使用Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

然后,b是类’MyClass’的实例

OK, for me that is the way it worked (I am using Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

Then, b is an instance of class ‘MyClass’


回答 7

如果您碰巧已经有了所需类的实例,则可以使用’type’函数提取其类类型,并使用它来构造新的实例:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

If you happen to already have an instance of your desired class, you can use the ‘type’ function to extract its class type and use this to construct a new instance:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

回答 8

module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()

回答 9

在Google App Engine中,有一个webapp2名为的函数import_string。有关更多信息,请参见此处: https //webapp-improved.appspot.com/api/webapp2.html

所以,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

例如,webapp2.Route在可以使用处理程序或字符串的地方使用它。

In Google App Engine there is a webapp2 function called import_string. For more info see here:https://webapp-improved.appspot.com/api/webapp2.html

So,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

For example this is used in the webapp2.Route where you can either use a handler or a string.


将python’type’对象转换为字符串

问题:将python’type’对象转换为字符串

我想知道如何使用python的反射功能将python’type’对象转换为字符串。

例如,我想打印一个对象的类型

print "My type is " + type(someObject) # (which obviously doesn't work like this)

I’m wondering how to convert a python ‘type’ object into a string using python’s reflective capabilities.

For example, I’d like to print the type of an object

print "My type is " + type(someObject) # (which obviously doesn't work like this)

回答 0

print type(someObject).__name__

如果那不适合您,请使用此:

print some_instance.__class__.__name__

例:

class A:
    pass
print type(A())
# prints <type 'instance'>
print A().__class__.__name__
# prints A

另外,type()使用新样式的类和旧样式的类(即从继承object)之间似乎也存在差异。对于新型类,type(someObject).__name__返回名称,对于旧样式的类,返回instance

print type(someObject).__name__

If that doesn’t suit you, use this:

print some_instance.__class__.__name__

Example:

class A:
    pass
print type(A())
# prints <type 'instance'>
print A().__class__.__name__
# prints A

Also, it seems there are differences with type() when using new-style classes vs old-style (that is, inheritance from object). For a new-style class, type(someObject).__name__ returns the name, and for old-style classes it returns instance.


回答 1

>>> class A(object): pass

>>> e = A()
>>> e
<__main__.A object at 0xb6d464ec>
>>> print type(e)
<class '__main__.A'>
>>> print type(e).__name__
A
>>> 

转换为字符串是什么意思?您可以定义自己的reprstr _方法:

>>> class A(object):
    def __repr__(self):
        return 'hei, i am A or B or whatever'

>>> e = A()
>>> e
hei, i am A or B or whatever
>>> str(e)
hei, i am A or B or whatever

还是我不知道..请添加说明;)

>>> class A(object): pass

>>> e = A()
>>> e
<__main__.A object at 0xb6d464ec>
>>> print type(e)
<class '__main__.A'>
>>> print type(e).__name__
A
>>> 

what do you mean by convert into a string? you can define your own repr and str_ methods:

>>> class A(object):
    def __repr__(self):
        return 'hei, i am A or B or whatever'

>>> e = A()
>>> e
hei, i am A or B or whatever
>>> str(e)
hei, i am A or B or whatever

or i dont know..please add explainations ;)


回答 2

print("My type is %s" % type(someObject)) # the type in python

要么…

print("My type is %s" % type(someObject).__name__) # the object's type (the class you defined)
print("My type is %s" % type(someObject)) # the type in python

or…

print("My type is %s" % type(someObject).__name__) # the object's type (the class you defined)

回答 3

使用str()

 typeOfOneAsString=str(type(1))

Using str()

 typeOfOneAsString=str(type(1))

回答 4

如果您想使用str()和自定义str方法。这也适用于代表。

class TypeProxy:
    def __init__(self, _type):
        self._type = _type

    def __call__(self, *args, **kwargs):
        return self._type(*args, **kwargs)

    def __str__(self):
        return self._type.__name__

    def __repr__(self):
        return "TypeProxy(%s)" % (repr(self._type),)

>>> str(TypeProxy(str))
'str'
>>> str(TypeProxy(type("")))
'str'

In case you want to use str() and a custom str method. This also works for repr.

class TypeProxy:
    def __init__(self, _type):
        self._type = _type

    def __call__(self, *args, **kwargs):
        return self._type(*args, **kwargs)

    def __str__(self):
        return self._type.__name__

    def __repr__(self):
        return "TypeProxy(%s)" % (repr(self._type),)

>>> str(TypeProxy(str))
'str'
>>> str(TypeProxy(type("")))
'str'

一行Python代码可以知道其缩进嵌套级别吗?

问题:一行Python代码可以知道其缩进嵌套级别吗?

从这样的事情:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

我想得到这样的东西:

1
2
3

代码可以这样读取吗?

我想要的只是更多嵌套代码部分的输出。以使代码易于阅读的方式,使输出易于阅读。

当然,我可以使用eg手动实现此功能.format(),但是我想到的是自定义打印功能,该功能print(i*' ' + string)在哪里i是缩进级别。这将是使终端上的输出可读的一种快速方法。

有没有更好的方法可以避免麻烦的手动格式化?

From something like this:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

I would like to get something like this:

1
2
3

Can the code read itself in this way?

All I want is the output from the more nested parts of the code to be more nested. In the same way that this makes code easier to read, it would make the output easier to read.

Of course I could implement this manually, using e.g. .format(), but what I had in mind was a custom print function which would print(i*' ' + string) where i is the indentation level. This would be a quick way to make readable output on my terminal.

Is there a better way to do this which avoids painstaking manual formatting?


回答 0

如果您想缩进而不是使用空格和制表符来嵌套级别,那么事情就会变得棘手。例如,在以下代码中:

if True:
    print(
get_nesting_level())

get_nesting_level尽管实际上在行的行上没有前导空格,但对的调用实际上嵌套了一层深度get_nesting_level呼叫。同时,在以下代码中:

print(1,
      2,
      get_nesting_level())

调用 get_nesting_level尽管该行中存在领先的空格,对仍嵌套在零级深度。

在下面的代码中:

if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())

两次调用 get_nesting_level尽管前导空白是相同的,但这处于不同的嵌套级别。

在下面的代码中:

if True: print(get_nesting_level())

是嵌套的零级,还是一级?在INDENTDEDENT形式语法中标记,深度为零,但是您可能会感觉不一样。


如果要执行此操作,则必须标记整个文件,直到调用,计数INDENTDEDENT标记为止。该tokenize模块对于此类功能非常有用:

import inspect
import tokenize

def get_nesting_level():
    caller_frame = inspect.currentframe().f_back
    filename, caller_lineno, _, _, _ = inspect.getframeinfo(caller_frame)
    with open(filename) as f:
        indentation_level = 0
        for token_record in tokenize.generate_tokens(f.readline):
            token_type, _, (token_lineno, _), _, _ = token_record
            if token_lineno > caller_lineno:
                break
            elif token_type == tokenize.INDENT:
                indentation_level += 1
            elif token_type == tokenize.DEDENT:
                indentation_level -= 1
        return indentation_level

If you want indentation in terms of nesting level rather than spaces and tabs, things get tricky. For example, in the following code:

if True:
    print(
get_nesting_level())

the call to get_nesting_level is actually nested one level deep, despite the fact that there is no leading whitespace on the line of the get_nesting_level call. Meanwhile, in the following code:

print(1,
      2,
      get_nesting_level())

the call to get_nesting_level is nested zero levels deep, despite the presence of leading whitespace on its line.

In the following code:

if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())

the two calls to get_nesting_level are at different nesting levels, despite the fact that the leading whitespace is identical.

In the following code:

if True: print(get_nesting_level())

is that nested zero levels, or one? In terms of INDENT and DEDENT tokens in the formal grammar, it’s zero levels deep, but you might not feel the same way.


If you want to do this, you’re going to have to tokenize the whole file up to the point of the call and count INDENT and DEDENT tokens. The tokenize module would be very useful for such a function:

import inspect
import tokenize

def get_nesting_level():
    caller_frame = inspect.currentframe().f_back
    filename, caller_lineno, _, _, _ = inspect.getframeinfo(caller_frame)
    with open(filename) as f:
        indentation_level = 0
        for token_record in tokenize.generate_tokens(f.readline):
            token_type, _, (token_lineno, _), _, _ = token_record
            if token_lineno > caller_lineno:
                break
            elif token_type == tokenize.INDENT:
                indentation_level += 1
            elif token_type == tokenize.DEDENT:
                indentation_level -= 1
        return indentation_level

回答 1

是的,绝对有可能,这是一个可行的示例:

import inspect

def get_indentation_level():
    callerframerecord = inspect.stack()[1]
    frame = callerframerecord[0]
    info = inspect.getframeinfo(frame)
    cc = info.code_context[0]
    return len(cc) - len(cc.lstrip())

if 1:
    print get_indentation_level()
    if 1:
        print get_indentation_level()
        if 1:
            print get_indentation_level()

Yeah, that’s definitely possible, here’s a working example:

import inspect

def get_indentation_level():
    callerframerecord = inspect.stack()[1]
    frame = callerframerecord[0]
    info = inspect.getframeinfo(frame)
    cc = info.code_context[0]
    return len(cc) - len(cc.lstrip())

if 1:
    print get_indentation_level()
    if 1:
        print get_indentation_level()
        if 1:
            print get_indentation_level()

回答 2

您可以使用sys.current_frame.f_lineno以获取行号。然后,为了找到压痕级别的数量,您需要找到压痕为零的前一行,然后从该行的数量中减去当前行号,您将获得压痕数量:

import sys
current_frame = sys._getframe(0)

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()
    current_line_no = current_frame.f_lineno
    to_current = lines[:current_line_no]
    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())
    return current_line_no - previous_zoro_ind

演示:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
3
5
6

如果您想要基于先前行的缩进级别编号,:则只需稍作更改即可:

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()

    current_line_no = current_frame.f_lineno
    to_current = lines[:current_line_no]
    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())
    return sum(1 for line in lines[previous_zoro_ind-1:current_line_no] if line.strip().endswith(':'))

演示:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
2
3
3

作为替代答案,这里是一个用于获取缩进数量(空格)的函数:

import sys
from itertools import takewhile
current_frame = sys._getframe(0)

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()
    return sum(1 for _ in takewhile(str.isspace, lines[current_frame.f_lineno - 1]))

You can use sys.current_frame.f_lineno in order to get the line number. Then in order to find the number of indentation level you need to find the previous line with zero indentation then be subtracting the current line number from that line’s number you’ll get the number of indentation:

import sys
current_frame = sys._getframe(0)

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()
    current_line_no = current_frame.f_lineno
    to_current = lines[:current_line_no]
    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())
    return current_line_no - previous_zoro_ind

Demo:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
3
5
6

If you want the number of the indentation level based on the previouse lines with : you can just do it with a little change:

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()

    current_line_no = current_frame.f_lineno
    to_current = lines[:current_line_no]
    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())
    return sum(1 for line in lines[previous_zoro_ind-1:current_line_no] if line.strip().endswith(':'))

Demo:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
2
3
3

And as an alternative answer here is a function for getting the number of indentation (whitespace):

import sys
from itertools import takewhile
current_frame = sys._getframe(0)

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()
    return sum(1 for _ in takewhile(str.isspace, lines[current_frame.f_lineno - 1]))

回答 3

为了解决导致您提出问题的“实际”问题,您可以实现一个contextmanager,它可以跟踪缩进级别并使with代码中的块结构与输出的缩进级别相对应。这样,代码缩进仍然可以反映输出缩进,而不会造成过多的耦合。仍然可以将代码重构为不同的功能,并基于代码结构使用其他缩进,而不会干扰输出缩进。

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function


class IndentedPrinter(object):

    def __init__(self, level=0, indent_with='  '):
        self.level = level
        self.indent_with = indent_with

    def __enter__(self):
        self.level += 1
        return self

    def __exit__(self, *_args):
        self.level -= 1

    def print(self, arg='', *args, **kwargs):
        print(self.indent_with * self.level + str(arg), *args, **kwargs)


def main():
    indented = IndentedPrinter()
    indented.print(indented.level)
    with indented:
        indented.print(indented.level)
        with indented:
            indented.print('Hallo', indented.level)
            with indented:
                indented.print(indented.level)
            indented.print('and back one level', indented.level)


if __name__ == '__main__':
    main()

输出:

0
  1
    Hallo 2
      3
    and back one level 2

To solve the ”real” problem that lead to your question you could implement a contextmanager which keeps track of the indention level and make the with block structure in the code correspond to the indentation levels of the output. This way the code indentation still reflects the output indentation without coupling both too much. It is still possible to refactor the code into different functions and have other indentations based on code structure not messing with the output indentation.

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function


class IndentedPrinter(object):

    def __init__(self, level=0, indent_with='  '):
        self.level = level
        self.indent_with = indent_with

    def __enter__(self):
        self.level += 1
        return self

    def __exit__(self, *_args):
        self.level -= 1

    def print(self, arg='', *args, **kwargs):
        print(self.indent_with * self.level + str(arg), *args, **kwargs)


def main():
    indented = IndentedPrinter()
    indented.print(indented.level)
    with indented:
        indented.print(indented.level)
        with indented:
            indented.print('Hallo', indented.level)
            with indented:
                indented.print(indented.level)
            indented.print('and back one level', indented.level)


if __name__ == '__main__':
    main()

Output:

0
  1
    Hallo 2
      3
    and back one level 2

回答 4

>>> import inspect
>>> help(inspect.indentsize)
Help on function indentsize in module inspect:

indentsize(line)
    Return the indent size, in spaces, at the start of a line of text.
>>> import inspect
>>> help(inspect.indentsize)
Help on function indentsize in module inspect:

indentsize(line)
    Return the indent size, in spaces, at the start of a line of text.

如何检查变量是否为类?

问题:如何检查变量是否为类?

我想知道如何检查变量是否是类(不是实例!)。

我试图使用该函数isinstance(object, class_or_type_or_tuple)来执行此操作,但我不知道类将具有哪种类型。

例如,在以下代码中

class Foo: pass  
isinstance(Foo, **???**) # i want to make this return True.

我试图class???代替“ ” ,但我意识到这class是python中的关键字。

I was wondering how to check whether a variable is a class (not an instance!) or not.

I’ve tried to use the function isinstance(object, class_or_type_or_tuple) to do this, but I don’t know what type would a class will have.

For example, in the following code

class Foo: pass  
isinstance(Foo, **???**) # i want to make this return True.

I tried to substitute “class” with ???, but I realized that class is a keyword in python.


回答 0

更好的是:使用该inspect.isclass功能。

>>> import inspect
>>> class X(object):
...     pass
... 
>>> inspect.isclass(X)
True

>>> x = X()
>>> isinstance(x, X)
True
>>> y = 25
>>> isinstance(y, X)
False

Even better: use the inspect.isclass function.

>>> import inspect
>>> class X(object):
...     pass
... 
>>> inspect.isclass(X)
True

>>> x = X()
>>> isinstance(x, X)
True
>>> y = 25
>>> isinstance(y, X)
False

回答 1

inspect.isclass可能是最好的解决方案,并且很容易看到它是如何实现的

def isclass(object):
    """Return true if the object is a class.

    Class objects provide these attributes:
        __doc__         documentation string
        __module__      name of module in which this class was defined"""
    return isinstance(object, (type, types.ClassType))

The inspect.isclass is probably the best solution, and it’s really easy to see how it’s actually implemented

def isclass(object):
    """Return true if the object is a class.

    Class objects provide these attributes:
        __doc__         documentation string
        __module__      name of module in which this class was defined"""
    return isinstance(object, (type, types.ClassType))

回答 2

>>> class X(object):
...     pass
... 
>>> type(X)
<type 'type'>
>>> isinstance(X,type)
True
>>> class X(object):
...     pass
... 
>>> type(X)
<type 'type'>
>>> isinstance(X,type)
True

回答 3

isinstance(X, type)

返回Trueif X是class,False如果不是,则返回。

isinstance(X, type)

Return True if X is class and False if not.


回答 4

此检查与Python 2.x和Python 3.x兼容。

import six
isinstance(obj, six.class_types)

这基本上是一个包装函数,执行与andrea_crotti答案中相同的检查。

例:

>>> import datetime
>>> isinstance(datetime.date, six.class_types)
>>> True
>>> isinstance(datetime.date.min, six.class_types)
>>> False

This check is compatible with both Python 2.x and Python 3.x.

import six
isinstance(obj, six.class_types)

This is basically a wrapper function that performs the same check as in andrea_crotti answer.

Example:

>>> import datetime
>>> isinstance(datetime.date, six.class_types)
>>> True
>>> isinstance(datetime.date.min, six.class_types)
>>> False

回答 5

Foo类:被称为旧样式类,X(object)类:被称为新样式类。

选中此选项,Python中的旧样式类和新样式类之间有什么区别?。推荐新样式。阅读有关“ 统一类型和类

class Foo: is called old style class and class X(object): is called new style class.

Check this What is the difference between old style and new style classes in Python? . New style is recommended. Read about “unifying types and classes


回答 6

最简单的方法是使用inspect.isclass投票最多的答案中的内容。
实现细节可以在python2 inspectpython3 inspect中找到
对于新型类:isinstance(object, type)
对于老式类:isinstance(object, types.ClassType)
em,对于老式类,它正在使用types.ClassType,这是来自types.py的代码:

class _C:
    def _m(self): pass
ClassType = type(_C)

simplest way is to use inspect.isclass as posted in the most-voted answer.
the implementation details could be found at python2 inspect and python3 inspect.
for new-style class: isinstance(object, type)
for old-style class: isinstance(object, types.ClassType)
em, for old-style class, it is using types.ClassType, here is the code from types.py:

class _C:
    def _m(self): pass
ClassType = type(_C)

回答 7

本杰明·彼得森(Benjamin Peterson)inspect.isclass()对于这项工作的使用是正确的。但是请注意,您可以使用内置函数issubclass来测试Class对象是否是特定对象Class,因此是否是隐式对象。根据您的用例,这可能更像pythonic。Class

from typing import Type, Any
def isclass(cl: Type[Any]):
    try:
        return issubclass(cl, cl)
    except TypeError:
        return False

然后可以这样使用:

>>> class X():
...     pass
... 
>>> isclass(X)
True
>>> isclass(X())
False

Benjamin Peterson is correct about the use of inspect.isclass() for this job. But note that you can test if a Class object is a specific Class, and therefore implicitly a Class, using the built-in function issubclass. Depending on your use-case this can be more pythonic.

from typing import Type, Any
def isclass(cl: Type[Any]):
    try:
        return issubclass(cl, cl)
    except TypeError:
        return False

Can then be used like this:

>>> class X():
...     pass
... 
>>> isclass(X)
True
>>> isclass(X())
False

回答 8

这里已经有一些可行的解决方案,但这是另一个解决方案:

>>> import types
>>> class Dummy: pass
>>> type(Dummy) is types.ClassType
True

There are some working solutions here already, but here’s another one:

>>> import types
>>> class Dummy: pass
>>> type(Dummy) is types.ClassType
True

如何获取Python当前模块中所有类的列表?

问题:如何获取Python当前模块中所有类的列表?

我见过很多人从一个模块中提取所有类的示例,通常是这样的:

# foo.py
class Foo:
    pass

# test.py
import inspect
import foo

for name, obj in inspect.getmembers(foo):
    if inspect.isclass(obj):
        print obj

太棒了

但是我无法找到如何从当前模块中获取所有类。

# foo.py
import inspect

class Foo:
    pass

def print_classes():
    for name, obj in inspect.getmembers(???): # what do I do here?
        if inspect.isclass(obj):
            print obj

# test.py
import foo

foo.print_classes()

这可能确实很明显,但是我什么也找不到。谁能帮我吗?

I’ve seen plenty of examples of people extracting all of the classes from a module, usually something like:

# foo.py
class Foo:
    pass

# test.py
import inspect
import foo

for name, obj in inspect.getmembers(foo):
    if inspect.isclass(obj):
        print obj

Awesome.

But I can’t find out how to get all of the classes from the current module.

# foo.py
import inspect

class Foo:
    pass

def print_classes():
    for name, obj in inspect.getmembers(???): # what do I do here?
        if inspect.isclass(obj):
            print obj

# test.py
import foo

foo.print_classes()

This is probably something really obvious, but I haven’t been able to find anything. Can anyone help me out?


回答 0

尝试这个:

import sys
current_module = sys.modules[__name__]

在您的情况下:

import sys, inspect
def print_classes():
    for name, obj in inspect.getmembers(sys.modules[__name__]):
        if inspect.isclass(obj):
            print(obj)

甚至更好:

clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)

因为inspect.getmembers()带谓语。

Try this:

import sys
current_module = sys.modules[__name__]

In your context:

import sys, inspect
def print_classes():
    for name, obj in inspect.getmembers(sys.modules[__name__]):
        if inspect.isclass(obj):
            print(obj)

And even better:

clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)

Because inspect.getmembers() takes a predicate.


回答 1

关于什么

g = globals().copy()
for name, obj in g.iteritems():

What about

g = globals().copy()
for name, obj in g.iteritems():

?


回答 2

我不知道是否有“适当的”方法来执行此操作,但是您的代码片段import foo处在正确的轨道上:只需将其添加到foo.py中,do inspect.getmembers(foo),它就可以正常工作。

I don’t know if there’s a ‘proper’ way to do it, but your snippet is on the right track: just add import foo to foo.py, do inspect.getmembers(foo), and it should work fine.


回答 3

我能够从dir内置plus中获得所需的一切getattr

# Works on pretty much everything, but be mindful that 
# you get lists of strings back

print dir(myproject)
print dir(myproject.mymodule)
print dir(myproject.mymodule.myfile)
print dir(myproject.mymodule.myfile.myclass)

# But, the string names can be resolved with getattr, (as seen below)

虽然,它的确看起来像个毛线球:

def list_supported_platforms():
    """
        List supported platforms (to match sys.platform)

        @Retirms:
            list str: platform names
    """
    return list(itertools.chain(
        *list(
            # Get the class's constant
            getattr(
                # Get the module's first class, which we wrote
                getattr(
                    # Get the module
                    getattr(platforms, item),
                    dir(
                        getattr(platforms, item)
                    )[0]
                ),
                'SYS_PLATFORMS'
            )
            # For each include in platforms/__init__.py 
            for item in dir(platforms)
            # Ignore magic, ourselves (index.py) and a base class.
            if not item.startswith('__') and item not in ['index', 'base']
        )
    ))

I was able to get all I needed from the dir built in plus getattr.

# Works on pretty much everything, but be mindful that 
# you get lists of strings back

print dir(myproject)
print dir(myproject.mymodule)
print dir(myproject.mymodule.myfile)
print dir(myproject.mymodule.myfile.myclass)

# But, the string names can be resolved with getattr, (as seen below)

Though, it does come out looking like a hairball:

def list_supported_platforms():
    """
        List supported platforms (to match sys.platform)

        @Retirms:
            list str: platform names
    """
    return list(itertools.chain(
        *list(
            # Get the class's constant
            getattr(
                # Get the module's first class, which we wrote
                getattr(
                    # Get the module
                    getattr(platforms, item),
                    dir(
                        getattr(platforms, item)
                    )[0]
                ),
                'SYS_PLATFORMS'
            )
            # For each include in platforms/__init__.py 
            for item in dir(platforms)
            # Ignore magic, ourselves (index.py) and a base class.
            if not item.startswith('__') and item not in ['index', 'base']
        )
    ))

回答 4

import pyclbr
print(pyclbr.readmodule(__name__).keys())

请注意,stdlib的Python类浏览器模块使用静态源分析,因此它仅适用于由实际.py文件支持的模块。

import pyclbr
print(pyclbr.readmodule(__name__).keys())

Note that the stdlib’s Python class browser module uses static source analysis, so it only works for modules that are backed by a real .py file.


回答 5

如果要拥有属于当前模块的所有类,则可以使用以下方法:

import sys, inspect
def print_classes():
    is_class_member = lambda member: inspect.isclass(member) and member.__module__ == __name__
    clsmembers = inspect.getmembers(sys.modules[__name__], is_class_member)

如果您使用Nadia的答案并且要在模块上导入其他类,则这些类也将被导入。

因此,这就是为什么member.__module__ == __name__要添加到上使用的谓词的原因is_class_member。该语句检查该类是否确实属于该模块。

谓词是一个函数(可调用),它返回布尔值。

If you want to have all the classes, that belong to the current module, you could use this :

import sys, inspect
def print_classes():
    is_class_member = lambda member: inspect.isclass(member) and member.__module__ == __name__
    clsmembers = inspect.getmembers(sys.modules[__name__], is_class_member)

If you use Nadia’s answer and you were importing other classes on your module, that classes will be being imported too.

So that’s why member.__module__ == __name__ is being added to the predicate used on is_class_member. This statement checks that the class really belongs to the module.

A predicate is a function (callable), that returns a boolean value.


回答 6

另一个可在Python 2和3中使用的解决方案:

#foo.py
import sys

class Foo(object):
    pass

def print_classes():
    current_module = sys.modules[__name__]
    for key in dir(current_module):
        if isinstance( getattr(current_module, key), type ):
            print(key)

# test.py
import foo
foo.print_classes()

Another solution which works in Python 2 and 3:

#foo.py
import sys

class Foo(object):
    pass

def print_classes():
    current_module = sys.modules[__name__]
    for key in dir(current_module):
        if isinstance( getattr(current_module, key), type ):
            print(key)

# test.py
import foo
foo.print_classes()

回答 7

这是我用来获取当前模块中已定义(即未导入)的所有类的行。根据PEP-8,它有点长,但是您可以根据需要进行更改。

import sys
import inspect

classes = [name for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass) 
          if obj.__module__ is __name__]

这为您提供了一个类名列表。如果您想要类对象本身,只需保留obj即可。

classes = [obj for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass)
          if obj.__module__ is __name__]

根据我的经验,这是更有用的。

This is the line that I use to get all of the classes that have been defined in the current module (ie not imported). It’s a little long according to PEP-8 but you can change it as you see fit.

import sys
import inspect

classes = [name for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass) 
          if obj.__module__ is __name__]

This gives you a list of the class names. If you want the class objects themselves just keep obj instead.

classes = [obj for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass)
          if obj.__module__ is __name__]

This is has been more useful in my experience.


回答 8

import Foo 
dir(Foo)

import collections
dir(collections)
import Foo 
dir(Foo)

import collections
dir(collections)

回答 9

我认为您可以做这样的事情。

class custom(object):
    __custom__ = True
class Alpha(custom):
    something = 3
def GetClasses():
    return [x for x in globals() if hasattr(globals()[str(x)], '__custom__')]
print(GetClasses())`

如果您需要自己的类

I think that you can do something like this.

class custom(object):
    __custom__ = True
class Alpha(custom):
    something = 3
def GetClasses():
    return [x for x in globals() if hasattr(globals()[str(x)], '__custom__')]
print(GetClasses())`

if you need own classes


回答 10

我经常发现自己在编写命令行实用程序,其中第一个参数旨在引用许多不同类中的一个。例如./something.py feature command —-arguments,where Feature是一个类,并且command是该类上的一个方法。这是一个使这变得容易的基类。

假设该基类与所有子类都位于一个目录中。然后ArgBaseClass(foo = bar).load_subclasses(),您可以拨打电话,这将返回字典。例如,如果目录如下所示:

  • arg_base_class.py
  • feature.py

假设feature.py工具class Feature(ArgBaseClass),则上述调用load_subclasses将返回{ 'feature' : <Feature object> }。相同的kwargsfoo = bar)将传递给Feature该类。

#!/usr/bin/env python3
import os, pkgutil, importlib, inspect

class ArgBaseClass():
    # Assign all keyword arguments as properties on self, and keep the kwargs for later.
    def __init__(self, **kwargs):
        self._kwargs = kwargs
        for (k, v) in kwargs.items():
            setattr(self, k, v)
        ms = inspect.getmembers(self, predicate=inspect.ismethod)
        self.methods = dict([(n, m) for (n, m) in ms if not n.startswith('_')])

    # Add the names of the methods to a parser object.
    def _parse_arguments(self, parser):
        parser.add_argument('method', choices=list(self.methods))
        return parser

    # Instantiate one of each of the subclasses of this class.
    def load_subclasses(self):
        module_dir = os.path.dirname(__file__)
        module_name = os.path.basename(os.path.normpath(module_dir))
        parent_class = self.__class__
        modules = {}
        # Load all the modules it the package:
        for (module_loader, name, ispkg) in pkgutil.iter_modules([module_dir]):
            modules[name] = importlib.import_module('.' + name, module_name)

        # Instantiate one of each class, passing the keyword arguments.
        ret = {}
        for cls in parent_class.__subclasses__():
            path = cls.__module__.split('.')
            ret[path[-1]] = cls(**self._kwargs)
        return ret

I frequently find myself writing command line utilities wherein the first argument is meant to refer to one of many different classes. For example ./something.py feature command —-arguments, where Feature is a class and command is a method on that class. Here’s a base class that makes this easy.

The assumption is that this base class resides in a directory alongside all of its subclasses. You can then call ArgBaseClass(foo = bar).load_subclasses() which will return a dictionary. For example, if the directory looks like this:

  • arg_base_class.py
  • feature.py

Assuming feature.py implements class Feature(ArgBaseClass), then the above invocation of load_subclasses will return { 'feature' : <Feature object> }. The same kwargs (foo = bar) will be passed into the Feature class.

#!/usr/bin/env python3
import os, pkgutil, importlib, inspect

class ArgBaseClass():
    # Assign all keyword arguments as properties on self, and keep the kwargs for later.
    def __init__(self, **kwargs):
        self._kwargs = kwargs
        for (k, v) in kwargs.items():
            setattr(self, k, v)
        ms = inspect.getmembers(self, predicate=inspect.ismethod)
        self.methods = dict([(n, m) for (n, m) in ms if not n.startswith('_')])

    # Add the names of the methods to a parser object.
    def _parse_arguments(self, parser):
        parser.add_argument('method', choices=list(self.methods))
        return parser

    # Instantiate one of each of the subclasses of this class.
    def load_subclasses(self):
        module_dir = os.path.dirname(__file__)
        module_name = os.path.basename(os.path.normpath(module_dir))
        parent_class = self.__class__
        modules = {}
        # Load all the modules it the package:
        for (module_loader, name, ispkg) in pkgutil.iter_modules([module_dir]):
            modules[name] = importlib.import_module('.' + name, module_name)

        # Instantiate one of each class, passing the keyword arguments.
        ret = {}
        for cls in parent_class.__subclasses__():
            path = cls.__module__.split('.')
            ret[path[-1]] = cls(**self._kwargs)
        return ret

如何列出Python模块中的所有功能?

问题:如何列出Python模块中的所有功能?

我的系统上安装了python模块,我希望能够看到其中可用的函数/类/方法。

我想在每个函数上调用doc函数。在ruby中,我可以执行ClassName.methods之类的操作来获取该类上所有可用方法的列表。python中是否有类似的东西?

例如。就像是:

from somemodule import foo
print foo.methods # or whatever is the correct method to call

I have a python module installed on my system and I’d like to be able to see what functions/classes/methods are available in it.

I want to call the doc function on each one. In ruby I can do something like ClassName.methods to get a list of all the methods available on that class. Is there something similar in python?

eg. something like:

from somemodule import foo
print foo.methods # or whatever is the correct method to call

回答 0

inspect模块。另请参阅pydoc模块,help()交互式解释器中的功能以及pydoc生成所需文档的命令行工具。您可以给他们想要查看其文档的类。他们还可以生成例如HTML输出并将其写入磁盘。

The inspect module. Also see the pydoc module, the help() function in the interactive interpreter and the pydoc command-line tool which generates the documentation you are after. You can just give them the class you wish to see the documentation of. They can also generate, for instance, HTML output and write it to disk.


回答 1

您可以dir(module)用来查看所有可用的方法/属性。还要检查PyDocs。

You can use dir(module) to see all available methods/attributes. Also check out PyDocs.


回答 2

一旦你import编的模块,你可以做:

 help(modulename)

…要一次以交互方式获取所有功能的文档。或者您可以使用:

 dir(modulename)

…简单列出模块中定义的所有函数和变量的名称。

Once you’ve imported the module, you can just do:

 help(modulename)

… To get the docs on all the functions at once, interactively. Or you can use:

 dir(modulename)

… To simply list the names of all the functions and variables defined in the module.


回答 3

带inspect的例子:

from inspect import getmembers, isfunction
from my_project import my_module

functions_list = [o for o in getmembers(my_module) if isfunction(o[1])]

getmembers返回(object_name,object_type)元组的列表。

您可以在检查模块中将isfunction替换为任何其他isXXX函数。

An example with inspect:

from inspect import getmembers, isfunction
from my_project import my_module

functions_list = [o for o in getmembers(my_module) if isfunction(o[1])]

getmembers returns a list of (object_name, object_type) tuples.

You can replace isfunction with any of the other isXXX functions in the inspect module.


回答 4

import types
import yourmodule

print([getattr(yourmodule, a) for a in dir(yourmodule)
  if isinstance(getattr(yourmodule, a), types.FunctionType)])
import types
import yourmodule

print([getattr(yourmodule, a) for a in dir(yourmodule)
  if isinstance(getattr(yourmodule, a), types.FunctionType)])

回答 5

为了完整起见,我想指出,有时您可能想解析代码而不是导入代码。一个import执行最高水平的表达,这可能是一个问题。

例如,我让用户为zipapp制作的软件包选择入口点功能。使用误入歧途的代码importinspect冒着导致误入歧途的风险,从而导致崩溃,打印帮助信息,弹出GUI对话框等。

相反,我使用ast模块列出所有顶级功能:

import ast
import sys

def top_level_functions(body):
    return (f for f in body if isinstance(f, ast.FunctionDef))

def parse_ast(filename):
    with open(filename, "rt") as file:
        return ast.parse(file.read(), filename=filename)

if __name__ == "__main__":
    for filename in sys.argv[1:]:
        print(filename)
        tree = parse_ast(filename)
        for func in top_level_functions(tree.body):
            print("  %s" % func.name)

将这段代码放入list.py并用作输入,我得到:

$ python list.py list.py
list.py
  top_level_functions
  parse_ast

当然,即使对于像Python这样的相对简单的语言,导航AST有时也会很棘手,因为AST的层次很低。但是,如果您有一个简单明了的用例,那么它既可行又安全。

不过,缺点是您无法检测到运行时生成的函数,例如foo = lambda x,y: x*y

For completeness’ sake, I’d like to point out that sometimes you may want to parse code instead of importing it. An import will execute top-level expressions, and that could be a problem.

For example, I’m letting users select entry point functions for packages being made with zipapp. Using import and inspect risks running astray code, leading to crashes, help messages being printed out, GUI dialogs popping up and so on.

Instead I use the ast module to list all the top-level functions:

import ast
import sys

def top_level_functions(body):
    return (f for f in body if isinstance(f, ast.FunctionDef))

def parse_ast(filename):
    with open(filename, "rt") as file:
        return ast.parse(file.read(), filename=filename)

if __name__ == "__main__":
    for filename in sys.argv[1:]:
        print(filename)
        tree = parse_ast(filename)
        for func in top_level_functions(tree.body):
            print("  %s" % func.name)

Putting this code in list.py and using itself as input, I get:

$ python list.py list.py
list.py
  top_level_functions
  parse_ast

Of course, navigating an AST can be tricky sometimes, even for a relatively simple language like Python, because the AST is quite low-level. But if you have a simple and clear use case, it’s both doable and safe.

Though, a downside is that you can’t detect functions that are generated at runtime, like foo = lambda x,y: x*y.


回答 6

对于您不希望解析的代码,我建议上面使用基于AST的@csl方法。

对于其他所有内容,inspect模块都是正确的:

import inspect

import <module_to_inspect> as module

functions = inspect.getmembers(module, inspect.isfunction)

这给出了形式为2元组的列表[(<name:str>, <value:function>), ...]

上面的简单答案在各种回复和评论中都有提示,但没有明确指出。

For code that you do not wish to parse, I recommend the AST-based approach of @csl above.

For everything else, the inspect module is correct:

import inspect

import <module_to_inspect> as module

functions = inspect.getmembers(module, inspect.isfunction)

This gives a list of 2-tuples in the form [(<name:str>, <value:function>), ...].

The simple answer above is hinted at in various responses and comments, but not called out explicitly.


回答 7

这将达到目的:

dir(module) 

但是,如果您发现读取返回的列表很烦人,则只需使用以下循环即可获得每行一个名称。

for i in dir(module): print i

This will do the trick:

dir(module) 

However, if you find it annoying to read the returned list, just use the following loop to get one name per line.

for i in dir(module): print i

回答 8

dir(module) 如大多数答案中所述,这是使用脚本或标准解释器时的标准方法。

但是,使用像IPython这样的交互式python shell,您可以使用tab-completion来概述模块中定义的所有对象。这比使用脚本并print查看模块中定义的内容要方便得多。

  • module.<tab> 将向您显示模块中定义的所有对象(函数,类等)
  • module.ClassX.<tab> 将向您展示类的方法和属性
  • module.function_xy?module.ClassX.method_xy?将向您显示该函数/方法的文档字符串
  • module.function_x??module.SomeClass.method_xy??将显示函数/方法的源代码。

dir(module) is the standard way when using a script or the standard interpreter, as mentioned in most answers.

However with an interactive python shell like IPython you can use tab-completion to get an overview of all objects defined in the module. This is much more convenient, than using a script and print to see what is defined in the module.

  • module.<tab> will show you all objects defined in the module (functions, classes and so on)
  • module.ClassX.<tab> will show you the methods and attributes of a class
  • module.function_xy? or module.ClassX.method_xy? will show you the docstring of that function / method
  • module.function_x?? or module.SomeClass.method_xy?? will show you the source code of the function / method.

回答 9

对于全局函数,dir()是要使用的命令(如大多数答案中所提到的),但是此命令同时列出了公共函数和非公共函数。

例如运行:

>>> import re
>>> dir(re)

返回类似的函数/类:

'__all__', '_MAXCACHE', '_alphanum_bytes', '_alphanum_str', '_pattern_type', '_pickle', '_subx'

其中一些通常不用于一般编程用途(但由模块本身提供,除非在DunderAliases之类的情况下, __doc____file__ECT)。因此,将它们与公开对象一起列出可能没有用(这是Python知道使用时会得到什么的方式from module import *)。

__all__可用于解决此问题,它会返回模块中所有公共函数和类的列表(这些函数和类以下划线开头-_)。请参见 有人可以用Python解释__all__吗?用于__all__

这是一个例子:

>>> import re
>>> re.__all__
['match', 'fullmatch', 'search', 'sub', 'subn', 'split', 'findall', 'finditer', 'compile', 'purge', 'template', 'escape', 'error', 'A', 'I', 'L', 'M', 'S', 'X', 'U', 'ASCII', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', 'VERBOSE', 'UNICODE']
>>>

所有带下划线的函数和类均已删除,仅保留那些定义为public的函数和类,因此可以通过来使用import *

请注意,__all__并非总是定义。如果不包括在内,则AttributeError则引发一个。

ast模块就是一个例子:

>>> import ast
>>> ast.__all__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'ast' has no attribute '__all__'
>>>

For global functions dir() is the command to use (as mentioned in most of these answers), however this lists both public functions and non-public functions together.

For example running:

>>> import re
>>> dir(re)

Returns functions/classes like:

'__all__', '_MAXCACHE', '_alphanum_bytes', '_alphanum_str', '_pattern_type', '_pickle', '_subx'

Some of which are not generally meant for general programming use (but by the module itself, except in the case of DunderAliases like __doc__, __file__ ect). For this reason it may not be useful to list them with the public ones (this is how Python knows what to get when using from module import *).

__all__ could be used to solve this problem, it returns a list of all the public functions and classes in a module (those that do not start with underscores – _). See Can someone explain __all__ in Python? for the use of __all__.

Here is an example:

>>> import re
>>> re.__all__
['match', 'fullmatch', 'search', 'sub', 'subn', 'split', 'findall', 'finditer', 'compile', 'purge', 'template', 'escape', 'error', 'A', 'I', 'L', 'M', 'S', 'X', 'U', 'ASCII', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', 'VERBOSE', 'UNICODE']
>>>

All the functions and classes with underscores have been removed, leaving only those that are defined as public and can therefore be used via import *.

Note that __all__ is not always defined. If it is not included then an AttributeError is raised.

A case of this is with the ast module:

>>> import ast
>>> ast.__all__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'ast' has no attribute '__all__'
>>>

回答 10

如果您无法在没有导入错误的情况下导入所述Python文件,则这些答案均无效。当我检查文件时,我的情况就是这样,该文件来自具有很多依赖关系的大型代码库。下面将以文本形式处理文件,并搜索所有以“ def”开头的方法名称,并打印它们及其行号。

import re
pattern = re.compile("def (.*)\(")
for i, line in enumerate(open('Example.py')):
  for match in re.finditer(pattern, line):
    print '%s: %s' % (i+1, match.groups()[0])

None of these answers will work if you are unable to import said Python file without import errors. This was the case for me when I was inspecting a file which comes from a large code base with a lot of dependencies. The following will process the file as text and search for all method names that start with “def” and print them and their line numbers.

import re
pattern = re.compile("def (.*)\(")
for i, line in enumerate(open('Example.py')):
  for match in re.finditer(pattern, line):
    print '%s: %s' % (i+1, match.groups()[0])

回答 11

除了前面的答案中提到的dir(模块)或help(模块),您还可以尝试:
-打开ipython-
导入module_name-
键入module_name,然后按tab。它将打开一个小窗口,其中列出了python模块中的所有功能。
看起来很整洁。

这是列出hashlib模块所有功能的代码段

(C:\Program Files\Anaconda2) C:\Users\lenovo>ipython
Python 2.7.12 |Anaconda 4.2.0 (64-bit)| (default, Jun 29 2016, 11:07:13) [MSC v.1500 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.

IPython 5.1.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import hashlib

In [2]: hashlib.
             hashlib.algorithms            hashlib.new                   hashlib.sha256
             hashlib.algorithms_available  hashlib.pbkdf2_hmac           hashlib.sha384
             hashlib.algorithms_guaranteed hashlib.sha1                  hashlib.sha512
             hashlib.md5                   hashlib.sha224

Except dir(module) or help(module) mentioned in previous answers, you can also try:
– Open ipython
– import module_name
– type module_name, press tab. It’ll open a small window with listing all functions in the python module.
It looks very neat.

Here is snippet listing all functions of hashlib module

(C:\Program Files\Anaconda2) C:\Users\lenovo>ipython
Python 2.7.12 |Anaconda 4.2.0 (64-bit)| (default, Jun 29 2016, 11:07:13) [MSC v.1500 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.

IPython 5.1.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import hashlib

In [2]: hashlib.
             hashlib.algorithms            hashlib.new                   hashlib.sha256
             hashlib.algorithms_available  hashlib.pbkdf2_hmac           hashlib.sha384
             hashlib.algorithms_guaranteed hashlib.sha1                  hashlib.sha512
             hashlib.md5                   hashlib.sha224

回答 12

这将在列表中附加在your_module中定义的所有功能。

result=[]
for i in dir(your_module):
    if type(getattr(your_module, i)).__name__ == "function":
        result.append(getattr(your_module, i))

This will append all the functions that are defined in your_module in a list.

result=[]
for i in dir(your_module):
    if type(getattr(your_module, i)).__name__ == "function":
        result.append(getattr(your_module, i))

回答 13

您可以使用以下方法从shell列出模块中的所有功能:

import module

module.*?

You can use the following method to get list all the functions in your module from shell:

import module

module.*?

回答 14

import sys
from inspect import getmembers, isfunction
fcn_list = [o[0] for o in getmembers(sys.modules[__name__], isfunction)]
import sys
from inspect import getmembers, isfunction
fcn_list = [o[0] for o in getmembers(sys.modules[__name__], isfunction)]

回答 15

r = globals()
sep = '\n'+100*'*'+'\n' # To make it clean to read.
for k in list(r.keys()):
    try:
        if str(type(r[k])).count('function'):
            print(sep+k + ' : \n' + str(r[k].__doc__))
    except Exception as e:
        print(e)

输出:

******************************************************************************************
GetNumberOfWordsInTextFile : 

    Calcule et retourne le nombre de mots d'un fichier texte
    :param path_: le chemin du fichier à analyser
    :return: le nombre de mots du fichier

******************************************************************************************

    write_in : 

        Ecrit les donnees (2nd arg) dans un fichier txt (path en 1st arg) en mode a,
        :param path_: le path du fichier texte
        :param data_: la liste des données à écrire ou un bloc texte directement
        :return: None


 ******************************************************************************************
    write_in_as_w : 

            Ecrit les donnees (2nd arg) dans un fichier txt (path en 1st arg) en mode w,
            :param path_: le path du fichier texte
            :param data_: la liste des données à écrire ou un bloc texte directement
            :return: None
r = globals()
sep = '\n'+100*'*'+'\n' # To make it clean to read.
for k in list(r.keys()):
    try:
        if str(type(r[k])).count('function'):
            print(sep+k + ' : \n' + str(r[k].__doc__))
    except Exception as e:
        print(e)

Output :

******************************************************************************************
GetNumberOfWordsInTextFile : 

    Calcule et retourne le nombre de mots d'un fichier texte
    :param path_: le chemin du fichier à analyser
    :return: le nombre de mots du fichier

******************************************************************************************

    write_in : 

        Ecrit les donnees (2nd arg) dans un fichier txt (path en 1st arg) en mode a,
        :param path_: le path du fichier texte
        :param data_: la liste des données à écrire ou un bloc texte directement
        :return: None


 ******************************************************************************************
    write_in_as_w : 

            Ecrit les donnees (2nd arg) dans un fichier txt (path en 1st arg) en mode w,
            :param path_: le path du fichier texte
            :param data_: la liste des données à écrire ou un bloc texte directement
            :return: None