Làm thế nào để tôi có được danh sách các phương thức trong một lớp Python?


329

1
Nguồn ..... nguồn ...
RickyA

4
@JonCrowell đó không phải là cách mà Lực lượng hoạt động.
Ken Williams

Đối với Cython bằng cách sử dụng chỉ thị của trình biên dịch binding: stackoverflow.com/a/46041480/1959808
Ioannis Filippidis

4
Trên python3: [f for f in dir(ClassName) if not f.startswith('_')]hoặc chỉ dir(ClassName)cho tất cả mọi thứ
Seraf

@Seraf Xin vui lòng không gửi câu trả lời trong các ý kiến. Gửi một câu trả lời thay thế.
wjandrea

Câu trả lời:


331

Một ví dụ (liệt kê các phương thức của optparse.OptionParserlớp):

>>> from optparse import OptionParser
>>> import inspect
#python2
>>> inspect.getmembers(OptionParser, predicate=inspect.ismethod)
[([('__init__', <unbound method OptionParser.__init__>),
...
 ('add_option', <unbound method OptionParser.add_option>),
 ('add_option_group', <unbound method OptionParser.add_option_group>),
 ('add_options', <unbound method OptionParser.add_options>),
 ('check_values', <unbound method OptionParser.check_values>),
 ('destroy', <unbound method OptionParser.destroy>),
 ('disable_interspersed_args',
  <unbound method OptionParser.disable_interspersed_args>),
 ('enable_interspersed_args',
  <unbound method OptionParser.enable_interspersed_args>),
 ('error', <unbound method OptionParser.error>),
 ('exit', <unbound method OptionParser.exit>),
 ('expand_prog_name', <unbound method OptionParser.expand_prog_name>),
 ...
 ]
# python3
>>> inspect.getmembers(OptionParser, predicate=inspect.isfunction)
...

Lưu ý rằng getmemberstrả về một danh sách 2 tuple. Mục đầu tiên là tên của thành viên, mục thứ hai là giá trị.

Bạn cũng có thể truyền một ví dụ cho getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...

4
hoàn hảo, phần vị ngữ là chìa khóa, nếu không, bạn sẽ có được điều tương tự như dict với thông tin meta bổ sung. Cảm ơn.
Purrell

2
Điều này sẽ tạo ra một danh sách tất cả các phương thức trong lớp (bao gồm cả các phương thức được kế thừa từ các lớp khác), hay nó sẽ chỉ liệt kê các phương thức được định nghĩa rõ ràng trong lớp đó?
Anderson Green

10
inspect.isroutinecó thể là một vị ngữ thích hợp hơn; inspect.ismethodkhông hoạt động cho tất cả các phương thức của đối tượng.
Gavin S. Yancey

1
Điều này chỉ hoạt động khi sử dụng một thể hiện của lớp (ví dụ này cũng vậy). Đây có phải là hành vi dự kiến?
Christian Reall-Fluharty

2
trên python 3.7 ít nhất điều này không hoạt động, bạn phải khởi tạo lớp
kederrac

222

dir(theobject)phương pháp liệt kê tất cả các trường và phương thức của đối tượng của bạn (dưới dạng tuple) và mô-đun kiểm tra (dưới dạng mã hóa) để liệt kê các trường và phương thức với tài liệu của chúng (trong "" ").

Vì mọi thứ (thậm chí các trường) có thể được gọi bằng Python, tôi không chắc có hàm tích hợp để liệt kê các phương thức. Bạn có thể muốn thử nếu đối tượng bạn vượt qua dirthể gọi được hay không.


3
dir (đối tượng) là giải pháp đơn giản nhất mà tôi đã sử dụng.
lstodd

1
Làm thế nào để điều này khác với các giải pháp được chấp nhận?
skjerns

@skjerns Phải mất 5 ký hiệu để gõ nó. :)
Dr_Zaszuś

117

Câu trả lời Python 3.x không có thư viện bên ngoài

method_list = [func for func in dir(Foo) if callable(getattr(Foo, func))]

kết quả loại trừ dunder:

method_list = [func for func in dir(Foo) if callable(getattr(Foo, func)) and not func.startswith("__")]

38

Giả sử bạn muốn biết tất cả các phương thức được liên kết với lớp danh sách Chỉ cần gõ Sau đây

 print (dir(list))

Ở trên sẽ cung cấp cho bạn tất cả các phương thức của lớp danh sách


2
Đây là giải pháp tốt nhất
Zeeshan Ahmad

3
print([ m for m in dir(my_class) if not m.startswith('__')])
Evhz

32

Hãy thử tài sản __dict__.


16
Tôi nghĩ bạn có nghĩa là dict . Nhưng điều đó liệt kê các thuộc tính của thể hiện, không phải các phương thức.
me_and

1
Tôi cũng không làm việc cho tôi. Đã tham khảo cú pháp Markdown, tôi nghĩ ý tôi là __dict__.
me_and

3
@me_and có lẽ bạn đang thực hiện "tự .__ dict__" hoặc nói chung hơn là gọi phiên bản cá thể của __dict__. Tuy nhiên, các lớp cũng có __dict__và điều đó sẽ hiển thị các phương thức lớp :)
Seaux

21

bạn cũng có thể nhập FunctionType từ các loại và kiểm tra nó bằng class.__dict__:

from types import FunctionType

class Foo:
    def bar(self): pass
    def baz(self): pass

def methods(cls):
    return [x for x, y in cls.__dict__.items() if type(y) == FunctionType]

methods(Foo)  # ['bar', 'baz']

Điều này làm việc tốt cho tôi. Tôi đã thêm and not x.startswith('_')vào cuối phần hiểu danh sách để sử dụng để bỏ qua __init__các phương thức riêng tư và riêng tư.
Christopher Pearson

2
Bạn có thể thoát khỏi sự importcủa FunctionTypebằng cách sử dụng một lambda throwaway với type():type(lambda:0)
Tersosauros

isinstancesẽ tốt hơn type(y) == FunctionTypeở đây
Gloweye

13

Lưu ý rằng bạn cần xem xét liệu bạn có muốn các phương thức từ các lớp cơ sở được kế thừa (nhưng không bị ghi đè) trong kết quả hay không. Các hoạt động dir()inspect.getmembers()bao gồm các phương thức lớp cơ sở, nhưng việc sử dụng __dict__thuộc tính thì không.


3

Điều này cũng hoạt động:

mymodule.py

def foo(x)
   return 'foo'
def bar()
   return 'bar'

Trong một tập tin khác

import inspect
import mymodule
method_list = [ func[0] for func in inspect.getmembers(mymodule, predicate=inspect.isroutine) if callable(getattr(mymodule, func[0])) ]

đầu ra:

['foo', 'bar']

Từ tài liệu python:

Kiểm tra.isroutine (đối tượng)

Return true if the object is a user-defined or built-in function or method.

2
def find_defining_class(obj, meth_name):
    for ty in type(obj).mro():
        if meth_name in ty.__dict__:
            return ty

Vì thế

print find_defining_class(car, 'speedometer') 

Hãy suy nghĩ Python trang 210


3
Lõm 5? Viết hoa từ khóa? Khoảng cách không pep8?
Florrie

1
Không một lần hội nghị mã hóa nazis có được nó!
rbennell

1
Làm thế nào để trả lời câu hỏi này?
Aran-Fey

2

Có cách tiếp cận này:

[getattr(obj, m) for m in dir(obj) if not m.startswith('__')]

Khi giao dịch với một lớp dụ , có lẽ nó muốn được tốt hơn để trả về một danh sách với các tài liệu tham khảo phương pháp thay vì chỉ names¹. Nếu đó là mục tiêu của bạn, cũng như

  1. Không dùng import
  2. Loại trừ các phương thức riêng tư (ví dụ __init__) khỏi danh sách

Nó có thể được sử dụng. Tóm lại, cho một lớp học như

class Ghost:
    def boo(self, who):
        return f'Who you gonna call? {who}'

Chúng tôi có thể kiểm tra truy xuất cá thể với

>>> g = Ghost()
>>> methods = [getattr(g, m) for m in dir(g) if not m.startswith('__')]
>>> print(methods)
[<bound method Ghost.boo of <__main__.Ghost object at ...>>]

Vì vậy, bạn có thể gọi nó ngay lập tức:

>>> for method in methods:
...     print(method('GHOSTBUSTERS'))
...
Who you gonna call? GHOSTBUSTERS

Case Một trường hợp sử dụng:

Tôi đã sử dụng điều này để thử nghiệm đơn vị . Có một lớp trong đó tất cả các phương thức thực hiện các biến thể của cùng một quy trình - dẫn đến các bài kiểm tra dài, mỗi phương thức chỉ cách một bước so với các phương thức khác. KHÔ là một giấc mơ xa vời.

Nghĩ rằng tôi nên có một thử nghiệm duy nhất cho tất cả các phương pháp, vì vậy tôi đã thực hiện các bước lặp ở trên.

Mặc dù tôi nhận ra rằng thay vào đó tôi nên cấu trúc lại để tuân thủ DRY ... điều này vẫn có thể phục vụ một linh hồn nitpicky ngẫu nhiên trong tương lai.


2

Tôi chỉ giữ điều này ở đó, bởi vì câu trả lời được xếp hạng hàng đầu không rõ ràng .

Đây là bài kiểm tra đơn giản với lớp không thông thường dựa trên Enum.

# -*- coding: utf-8 -*-
import sys, inspect
from enum import Enum

class my_enum(Enum):
    """Enum base class my_enum"""
    M_ONE = -1
    ZERO = 0
    ONE = 1
    TWO = 2
    THREE = 3

    def is_natural(self):
            return (self.value > 0)
    def is_negative(self):
            return (self.value < 0)

def is_clean_name(name):
    return not name.startswith('_') and not name.endswith('_')
def clean_names(lst):
    return [ n for n in lst if is_clean_name(n) ]
def get_items(cls,lst):
    try:
            res = [ getattr(cls,n) for n in lst ]
    except Exception as e:
            res = (Exception, type(e), e)
            pass
    return res


print( sys.version )

dir_res = clean_names( dir(my_enum) )
inspect_res = clean_names( [ x[0] for x in inspect.getmembers(my_enum) ] )
dict_res = clean_names( my_enum.__dict__.keys() )

print( '## names ##' )
print( dir_res )
print( inspect_res )
print( dict_res )

print( '## items ##' )
print( get_items(my_enum,dir_res) )
print( get_items(my_enum,inspect_res) )
print( get_items(my_enum,dict_res) )

Và đây là kết quả đầu ra.

3.7.7 (default, Mar 10 2020, 13:18:53) 
[GCC 9.2.1 20200306]
## names ##
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO']
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO', 'name', 'value']
['is_natural', 'is_negative', 'M_ONE', 'ZERO', 'ONE', 'TWO', 'THREE']
## items ##
[<my_enum.M_ONE: -1>, <my_enum.ONE: 1>, <my_enum.THREE: 3>, <my_enum.TWO: 2>, <my_enum.ZERO: 0>]
(<class 'Exception'>, <class 'AttributeError'>, AttributeError('name'))
[<function my_enum.is_natural at 0xb78a1fa4>, <function my_enum.is_negative at 0xb78ae854>, <my_enum.M_ONE: -1>, <my_enum.ZERO: 0>, <my_enum.ONE: 1>, <my_enum.TWO: 2>, <my_enum.THREE: 3>]

Vì vậy, những gì chúng ta có:

  • dir cung cấp dữ liệu không đầy đủ
  • inspect.getmembers cung cấp dữ liệu không đầy đủ và cung cấp các khóa nội bộ không thể truy cập được với getattr()
  • __dict__.keys()cung cấp kết quả đầy đủ và đáng tin cậy

Tại sao phiếu bầu sai lầm như vậy? Và tôi sai ở đâu? Và những người khác trả lời có số phiếu thấp như vậy?


1
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]

đưa ra một danh sách giống hệt như

methods = inspect.getmembers(o, predicate=inspect.ismethod)

làm.


0

Nếu phương pháp của bạn là phương pháp "thông thường" chứ không phải statimethod, classmethodv.v.
Có một chút hack tôi đã nghĩ ra -

for k, v in your_class.__dict__.items():
    if "function" in str(v):
        print(k)

Điều này có thể được mở rộng sang loại phương thức khác bằng cách thay đổi "hàm" trong ifđiều kiện tương ứng.
Đã thử nghiệm trên trăn 2.7.


1
Không chắc tại sao điều này lại bị hạ thấp ... nó thực sự đã giải quyết được vấn đề mà tôi đang gặp phải.
redspidermkv

0

Bạn có thể liệt kê tất cả các phương thức trong một lớp python bằng cách sử dụng đoạn mã sau

dir(className)

Điều này sẽ trả về một danh sách tất cả các tên của các phương thức trong lớp


-1

Tôi biết đây là một bài viết cũ, nhưng chỉ cần viết chức năng này và sẽ để nó ở đây là trường hợp ai đó tình cờ tìm kiếm một câu trả lời:

def classMethods(the_class,class_only=False,instance_only=False,exclude_internal=True):

    def acceptMethod(tup):
        #internal function that analyzes the tuples returned by getmembers tup[1] is the 
        #actual member object
        is_method = inspect.ismethod(tup[1])
        if is_method:
            bound_to = tup[1].im_self
            internal = tup[1].im_func.func_name[:2] == '__' and tup[1].im_func.func_name[-2:] == '__'
            if internal and exclude_internal:
                include = False
            else:
                include = (bound_to == the_class and not instance_only) or (bound_to == None and not class_only)
        else:
            include = False
        return include
    #uses filter to return results according to internal function and arguments
    return filter(acceptMethod,inspect.getmembers(the_class))

Mã này không làm những gì nó được dự định như đã xuất bản. Đưa class_only hoặc instance_only sẽ dẫn đến danh sách trống.
Oz123

-2

Đây chỉ là một quan sát. "encode" dường như là một phương thức cho các đối tượng chuỗi

str_1 = 'a'
str_1.encode('utf-8')
>>> b'a'

Tuy nhiên, nếu str1 được kiểm tra các phương thức, một danh sách trống được trả về

inspect.getmember(str_1, predicate=inspect.ismethod)
>>> []

Vì vậy, có thể tôi sai, nhưng vấn đề dường như không đơn giản.


1
'a'là một đối tượng, có loại là str. Bạn có thể thấy điều này bằng cách chạy type('a'). inspect.getmember()có một tham số loại, vì vậy bạn cần gọi inspect.getmember(str)để xem những gì bạn mong đợi.
lhasson

-3
class CPerson:
    def __init__(self, age):
        self._age = age

    def run(self):
        pass

    @property
    def age(self): return self._age

    @staticmethod
    def my_static_method(): print("Life is short, you need Python")

    @classmethod
    def say(cls, msg): return msg


test_class = CPerson
# print(dir(test_class))  # list all the fields and methods of your object
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ == 'function' and not name.startswith('__')])
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ != 'function' and not name.startswith('__')])

đầu ra

[('run', <function CPerson.run at 0x0000000002AD3268>)]
[('age', <property object at 0x0000000002368688>), ('my_static_method', <staticmethod object at 0x0000000002ACBD68>), ('say', <classmethod object at 0x0000000002ACF0B8>)]

-4

Nếu bạn muốn liệt kê chỉ các phương thức của lớp python

import numpy as np
print(np.random.__all__)

1
Đó là một mô-đun, không phải là một lớp.
Aran-Fey

@ Aran-Fey Nó được áp dụng cho mọi lớp, tất cả đều tồn tại trong mọi lớp
Rakesh Chaudhari

2
Không, nó không. Nó thậm chí không tồn tại trong tất cả các mô-đun .
Aran-Fey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.