ฉันจะรับรายการวิธีการในคลาส Python ได้อย่างไร


330

1
แหล่งที่มา ..... แหล่งที่มา ...
# # RickyA

4
@ JonCrowell นั่นไม่ใช่วิธีการทำงานของ Force
Ken Williams

สำหรับ Cython โดยใช้คำสั่งของคอมไพเลอร์binding: stackoverflow.com/a/46041480/1959808
Ioannis Filippidis

4
ใน python3: [f for f in dir(ClassName) if not f.startswith('_')]หรือdir(ClassName)เพื่อทุกอย่าง
Seraf

@Seraf กรุณาอย่าโพสต์คำตอบในความคิดเห็น โพสต์คำตอบแทน
wjandrea

คำตอบ:


332

ตัวอย่าง (รายการวิธีการของoptparse.OptionParserชั้นเรียน):

>>> 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)
...

ขอให้สังเกตว่าgetmembersส่งคืนรายการของ 2-tuples รายการแรกคือชื่อของสมาชิกรายการที่สองคือค่า

คุณสามารถส่งตัวอย่างไปที่getmembers:

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

4
ที่สมบูรณ์แบบ, ส่วนคำกริยาเป็นกุญแจสำคัญมิฉะนั้นคุณจะได้รับสิ่งเดียวกันเป็นDictกับข้อมูล meta พิเศษ ขอบคุณ
Purrell

2
สิ่งนี้จะสร้างรายการวิธีการทั้งหมดในชั้นเรียน (รวมถึงวิธีที่สืบทอดมาจากคลาสอื่น ๆ ) หรือจะแสดงเฉพาะวิธีการที่กำหนดไว้อย่างชัดเจนในชั้นเรียนนั้นหรือไม่
Anderson Green

10
inspect.isroutineอาจเป็นภาคแสดงที่เหมาะสมกว่า; inspect.ismethodไม่สามารถใช้ได้กับวิธีการของวัตถุทั้งหมด
Gavin S. Yancey

1
สิ่งนี้ใช้ได้เฉพาะเมื่อใช้อินสแตนซ์ของคลาส (เช่นเดียวกับตัวอย่าง) เป็นพฤติกรรมที่คาดหวังหรือไม่
Christian Reall-Fluharty

2
ใน python 3.7 อย่างน้อยก็ใช้ไม่ได้คุณต้องยกตัวอย่างคลาส
kederrac

222

มีdir(theobject)วิธีการที่จะแสดงรายการเขตข้อมูลและวิธีการทั้งหมดของวัตถุของคุณ (เป็น tuple) และโมดูลตรวจสอบ (เป็น codeape เขียน) เพื่อแสดงรายการเขตข้อมูลและวิธีการที่มีเอกสารของพวกเขา (ใน "" ")

เนื่องจากอาจมีการเรียกทุกอย่าง (แม้แต่ฟิลด์) ใน Python ฉันไม่แน่ใจว่ามีฟังก์ชันในตัวเพื่อแสดงรายการวิธีการเท่านั้น คุณอาจต้องการลองว่าวัตถุที่คุณได้รับdirนั้นสามารถเรียกได้หรือไม่


3
dir (object) เป็นคำตอบที่ง่ายที่สุดที่ฉันเคยใช้
lstodd

@skjerns มันต้องใช้ 5 สัญลักษณ์ในการพิมพ์ :)
Dr_Zaszuś

117

Python 3.x ตอบกลับโดยไม่มีไลบรารีภายนอก

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

ผลลัพธ์ที่ไม่รวม dunder:

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

38

สมมติว่าคุณต้องการทราบวิธีการทั้งหมดที่เกี่ยวข้องกับรายการคลาสเพียงพิมพ์ต่อไปนี้

 print (dir(list))

ด้านบนจะให้วิธีการทั้งหมดของรายการคลาส


2
อันนี้เป็นทางออกที่ดีที่สุด
Zeeshan Ahmad

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

32

__dict__ลองทรัพย์สิน


16
ฉันคิดว่าคุณหมายถึงDict แต่นั่นแสดงรายการคุณลักษณะของอินสแตนซ์ไม่ใช่วิธีการ
me_and

1
…ที่ไม่ได้ผลสำหรับฉันเช่นกัน เมื่อพิจารณาถึงไวยากรณ์ของ Markdown แล้วฉันคิดว่าฉันหมายถึง __dict__
me_and

3
@me_and คุณอาจทำ "ตัวเอง .__ dict__" __dict__หรือมากกว่าโดยทั่วไปเรียกรุ่นอินสแตนซ์ อย่างไรก็ตามการเรียนมี__dict__มากเกินไปและควรจะแสดงวิธีการเรียน :)
Seaux

21

คุณยังสามารถนำเข้า FunctionType จากประเภทและทดสอบด้วย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']

นี้ทำงานได้ดีสำหรับฉัน. ฉันเพิ่มand not x.startswith('_')ในตอนท้ายของรายการความเข้าใจสำหรับการใช้งานของฉันที่จะไม่สนใจ__init__วิธีการส่วนตัวและ
Christopher Pearson

2
คุณสามารถได้รับการกำจัดimportของFunctionTypeโดยใช้แลมบ์ดาใบปลิวกับtype():type(lambda:0)
Tersosauros

isinstanceจะดีกว่าtype(y) == FunctionTypeที่นี่
Gloweye

13

โปรดทราบว่าคุณต้องพิจารณาว่าคุณต้องการวิธีการจากคลาสฐานที่สืบทอด (แต่ไม่แทนที่) รวมอยู่ในผลลัพธ์ กระบวนการdir()และinspect.getmembers()การดำเนินงานมีวิธีการเรียนพื้นฐาน แต่การใช้__dict__คุณลักษณะไม่ได้


3

สิ่งนี้ยังใช้งานได้:

mymodule.py

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

ในไฟล์อื่น

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

เอาท์พุท:

['foo', 'bar']

จาก python docs:

inspect.isroutine (วัตถุ)

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

ดังนั้น

print find_defining_class(car, 'speedometer') 

คิดว่า Python หน้า 210


3
การเยื้องของ 5? คำหลักเป็นตัวพิมพ์ใหญ่หรือไม่ การเว้นวรรคแบบไม่ใช่ pep8
Florrie

1
ไม่เพียงครั้งเดียวที่รหัสการประชุม nazis มาถึงแล้ว!
rbennell

1
คำถามนี้จะตอบคำถามได้อย่างไร
Aran-Fey

2

มีวิธีนี้:

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

เมื่อต้องจัดการกับอินสแตนซ์ของชั้นเรียนบางทีอาจเป็นการดีกว่าที่จะส่งคืนรายการด้วยการอ้างอิงเมธอดแทนที่จะเป็นแค่ชื่อ¹ ถ้านั่นคือเป้าหมายของคุณเช่นเดียวกับ

  1. ใช้หมายเลข import
  2. ไม่รวมวิธีการส่วนตัว (เช่น__init__) จากรายการ

มันอาจจะใช้งานได้ โดยสรุปสำหรับชั้นเรียนเช่น

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

เราสามารถตรวจสอบการดึงอินสแตนซ์ด้วย

>>> 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 ...>>]

ดังนั้นคุณสามารถเรียกมันได้ทันที:

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

¹กรณีการใช้งาน:

ผมใช้วิธีนี้สำหรับการทดสอบหน่วย มีคลาสที่วิธีการทั้งหมดใช้รูปแบบของกระบวนการเดียวกันซึ่งนำไปสู่การทดสอบที่ยาวนานซึ่งแต่ละวิธีนั้นแตกต่างจากวิธีอื่น DRYเป็นความฝันที่แสนไกล

คิดว่าฉันควรมีการทดสอบเดียวสำหรับวิธีการทั้งหมดดังนั้นฉันทำซ้ำข้างต้น

แม้ว่าฉันจะรู้ตัวว่าฉันควรจะ refactor โค้ดเองเพื่อให้เป็นไปตามมาตรฐาน DRY ต่อไป ... สิ่งนี้อาจจะยังคงทำหน้าที่เป็นจิตวิญญาณของการทำไนติงกี้แบบสุ่มในอนาคต


2

ฉันเพียงแค่เก็บไว้ที่นั่นเพราะคำตอบที่จัดอันดับชั้นนำไม่ชัดเจน

นี่คือการทดสอบอย่างง่ายที่ไม่มีคลาสปกติตาม 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) )

และนี่คือผลลัพธ์ที่ได้

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>]

ดังนั้นสิ่งที่เรามี:

  • dir ให้ข้อมูลไม่สมบูรณ์
  • inspect.getmembers ให้ข้อมูลไม่สมบูรณ์และให้รหัสภายในที่ไม่สามารถเข้าถึงได้ getattr()
  • __dict__.keys()ให้ผลลัพธ์ที่สมบูรณ์และเชื่อถือได้

ทำไมคะแนนโหวตผิดพลาด และฉันผิดตรงไหน และคนอื่นที่ตอบผิดมีคะแนนโหวตต่ำมาก ๆ


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

ให้รายการเหมือนกันเป็น

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

ทำ.


0

หากวิธีการของคุณเป็นวิธีที่ "ปกติ" และไม่ได้statimethod, classmethodฯลฯ
นอกจากนี้เล็ก ๆ น้อย ๆ สับฉันมาด้วย -

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

สิ่งนี้สามารถขยายไปยังวิธีการประเภทอื่น ๆ โดยการเปลี่ยน "ฟังก์ชั่น" ในifสภาพที่สอดคล้องกัน
ทดสอบกับ python 2.7


1
ไม่แน่ใจว่าทำไมสิ่งนี้จึงถูกลดระดับลง ... มันแก้ปัญหาที่ฉันมีได้จริง ๆ
redspidermkv

0

คุณสามารถแสดงรายการวิธีการทั้งหมดในคลาสหลามโดยใช้รหัสต่อไปนี้

dir(className)

นี่จะส่งคืนรายการชื่อทั้งหมดของเมธอดในคลาส


-1

ฉันรู้ว่านี่เป็นโพสต์เก่า แต่เพิ่งเขียนฟังก์ชั่นนี้และจะทิ้งไว้ที่นี่เป็นกรณีที่มีคนสะดุดมองหาคำตอบ:

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))

รหัสนี้ไม่ได้ทำตามที่ตั้งใจไว้ การให้ class_only หรือ instance_only ส่งผลให้รายการว่าง
Oz123

-2

นี่เป็นเพียงการสังเกต "เข้ารหัส" น่าจะเป็นวิธีการสำหรับวัตถุสตริง

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

อย่างไรก็ตามหากมีการตรวจสอบ str1 สำหรับวิธีการรายการที่ว่างเปล่าจะถูกส่งกลับ

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

ดังนั้นบางทีฉันผิด แต่ปัญหาดูเหมือนจะไม่ง่าย


1
'a'strเป็นวัตถุที่มีประเภทคือ type('a')คุณสามารถดูนี้โดยการเรียกใช้ inspect.getmember()รับพารามิเตอร์ประเภทดังนั้นคุณต้องโทรinspect.getmember(str)เพื่อดูสิ่งที่คุณคาดหวัง
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('__')])

เอาท์พุต

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

-4

หากคุณต้องการแสดงรายการวิธีการของคลาสหลามเท่านั้น

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

1
นั่นเป็นโมดูลไม่ใช่คลาส
Aran-Fey

@ Aran-Fey มันถูกนำไปใช้สำหรับทุกชั้นเรียนทั้งหมดที่มีอยู่ในทุกชั้นเรียน
Rakesh Chaudhari

2
ไม่เลย มันไม่ได้อยู่ในทุกโมดูล
Aran-Fey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.