Znajdowanie metod w obiekcie Python


427

Biorąc pod uwagę dowolny obiekt Pythona, czy istnieje prosty sposób na uzyskanie listy wszystkich metod, które ten obiekt ma?

Lub,

jeśli nie jest to możliwe, czy istnieje co najmniej łatwy sposób sprawdzenia, czy ma określoną metodę inną niż zwykłe sprawdzenie, czy wystąpił błąd podczas wywoływania metody?


Odpowiedzi:


521

W przypadku wielu obiektów możesz użyć tego kodu, zastępując „obiekt” obiektem, który Cię interesuje:

object_methods = [method_name for method_name in dir(object)
                  if callable(getattr(object, method_name))]

Odkryłem to na stronie diveintopython.net (teraz zarchiwizowane). Mam nadzieję, że powinno to dostarczyć dalszych szczegółów!

Jeśli otrzymasz AttributeError, możesz użyć tego zamiast :

getattr(nie toleruje abstrakcyjnych wirtualnych podklas w stylu python3.6. Ten kod działa tak samo jak powyżej i ignoruje wyjątki.

import pandas as pd 
df = pd.DataFrame([[10, 20, 30], [100, 200, 300]],  
                  columns=['foo', 'bar', 'baz']) 
def get_methods(object, spacing=20): 
  methodList = [] 
  for method_name in dir(object): 
    try: 
        if callable(getattr(object, method_name)): 
            methodList.append(str(method_name)) 
    except: 
        methodList.append(str(method_name)) 
  processFunc = (lambda s: ' '.join(s.split())) or (lambda s: s) 
  for method in methodList: 
    try: 
        print(str(method.ljust(spacing)) + ' ' + 
              processFunc(str(getattr(object, method).__doc__)[0:90])) 
    except: 
        print(method.ljust(spacing) + ' ' + ' getattr() failed') 


get_methods(df['foo']) 

3
Jest to lista, która zwraca listę metod, w których metoda jest pozycją na liście zwróconą przez dir (obiekt), a każda metoda jest dodawana do listy tylko wtedy, gdy getattr (obiekt, metoda) zwraca wywołanie.
Mnebuerquo,

1
Jak dokładnie tego używasz? Aby powiedzieć, wydrukuj listę metod.
bagno

12
@marsh Aby wydrukować metod: print [method for method in dir(object) if callable(getattr(object, method))].
Orienteerix

1
Dostaję, AttributeError: module 'pandas.core.common' has no attribute 'AbstractMethodError'kiedy próbuję to uruchomić. Zobacz szczegóły na stackoverflow.com/q/54713287/9677043 .
Karl Baker

1
nie działa dla obiektu ramki danych pand w pythonie 3.6.
Stefan Karlsson

226

Możesz użyć wbudowanej dir()funkcji, aby uzyskać listę wszystkich atrybutów modułu. Wypróbuj to w wierszu polecenia, aby zobaczyć, jak to działa.

>>> import moduleName
>>> dir(moduleName)

Możesz także użyć tej hasattr(module_name, "attr_name")funkcji, aby dowiedzieć się, czy moduł ma określony atrybut.

Aby uzyskać więcej informacji, zobacz Przewodnik po introspekcji w języku Python .


hasattrpomógł mojemu przypadkowi użycia sprawdzić, czy obiekt Pythona ma określoną zmienną składową lub metodę.
Akshay,

Nie jestem pewien, dlaczego to rozwiązanie nie jest wystarczająco dobrze oceniane. To jest zwięzłe i dokładne.
Prasad Raghavendra

93

Najprostszą metodą jest użycie dir(objectname). Wyświetli wszystkie metody dostępne dla tego obiektu. Fajna sztuczka.


2
Wyświetla również atrybuty obiektu, więc jeśli chcesz konkretnie znaleźć metody, to nie zadziała.
eric,

Tak. Zgoda. Ale nie znam żadnej innej techniki, aby uzyskać tylko listę metod. Być może najlepszym pomysłem jest uzyskanie listy zarówno atrybutów, jak i metod, a następnie użycie <hasattr (object, "method_name"> w celu dalszego odfiltrowania?
Pawan Kumar

1
@neuronet, próbuję uruchomić zaakceptowaną odpowiedź, ale otrzymuję AttributeError: module 'pandas.core.common' has no attribute 'AbstractMethodError'. Jakieś pomysły? Zobacz deets na stackoverflow.com/q/54713287/9677043 . +1 do @Pawan Kumar b / c odpowiedź działa, a dla @ljs za obietnicę przefiltrowanej listy tylko metod.
Karl Baker

30

Aby sprawdzić, czy ma określoną metodę:

hasattr(object,"method")

14
ponieważ OP szuka metody, a nie tylko i atrybutu, myślę, że chcesz pójść o krok dalej:if hasattr(obj,method) and callable(getattr(obj,method)):
Bruno Bronosky

28

Wierzę, że to, czego chcesz, to coś takiego:

lista atrybutów z obiektu

Moim skromnym zdaniem wbudowana funkcja dir()może wykonać tę pracę za Ciebie. Pobrane z help(dir)danych wyjściowych powłoki Python Shell:

reż (...)

dir([object]) -> list of strings

Jeśli zostanie wywołany bez argumentu, zwróci nazwy w bieżącym zakresie.

W przeciwnym razie zwróć alfabetyczną listę nazw zawierających (niektóre) atrybuty danego obiektu i atrybuty, które można z niego uzyskać.

Jeśli obiekt dostarcza metodę o nazwie __dir__, zostanie użyta; w przeciwnym razie używana jest domyślna logika dir (), która zwraca:

  • dla obiektu modułu: atrybuty modułu.
  • dla obiektu klasy: jego atrybuty i rekurencyjnie atrybuty jego podstaw.
  • dla dowolnego innego obiektu: jego atrybutów, atrybutów jego klasy i rekurencyjnie atrybutów klas podstawowych jego klasy.

Na przykład:

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> a = "I am a string"
>>>
>>> type(a)
<class 'str'>
>>>
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__',
'__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__',
'__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'_formatter_field_name_split', '_formatter_parser', 'capitalize',
'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find',
'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace',
'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition',
'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip',
'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title',
'translate', 'upper', 'zfill']

Sprawdzając twój problem, postanowiłem zademonstrować swój tok myślenia, z lepszym formatowaniem danych wyjściowych dir().

dir_attributes.py (Python 2.7.6)

#!/usr/bin/python
""" Demonstrates the usage of dir(), with better output. """

__author__ = "ivanleoncz"

obj = "I am a string."
count = 0

print "\nObject Data: %s" % obj
print "Object Type: %s\n" % type(obj)

for method in dir(obj):
    # the comma at the end of the print, makes it printing 
    # in the same line, 4 times (count)
    print "| {0: <20}".format(method),
    count += 1
    if count == 4:
        count = 0
        print

dir_attributes.py (Python 3.4.3)

#!/usr/bin/python3
""" Demonstrates the usage of dir(), with better output. """

__author__ = "ivanleoncz"

obj = "I am a string."
count = 0

print("\nObject Data: ", obj)
print("Object Type: ", type(obj),"\n")

for method in dir(obj):
    # the end=" " at the end of the print statement, 
    # makes it printing in the same line, 4 times (count)
    print("|    {:20}".format(method), end=" ")
    count += 1
    if count == 4:
        count = 0
        print("")

Mam nadzieję, że przyczyniłem się :).


1
Przyczynił się? Twoja odpowiedź zadziałała dla mnie w Pythonie 2.7.12, więc do diabła, tak!
gsamaras

23

Oprócz bardziej bezpośrednich odpowiedzi, byłbym niedoceniony, gdybym nie wspomniał o iPython . Naciśnij „tab”, aby zobaczyć dostępne metody z autouzupełnianiem.

A gdy znajdziesz metodę, spróbuj:

help(object.method) 

aby zobaczyć pydoki, podpis metody itp.

Ahh ... REPL .


12

Jeśli potrzebujesz metod , powinieneś użyć inspect.ismethod .

W przypadku nazw metod:

import inspect
method_names = [attr for attr in dir(self) if inspect.ismethod(getattr(self, attr))]

Dla samych metod:

import inspect
methods = [member for member in [getattr(self, attr) for attr in dir(self)] if inspect.ismethod(member)]

Czasami inspect.isroutinemoże być również przydatny (dla wbudowanych rozszerzeń C, Cython bez „wiążącej” dyrektywy kompilatora).


Czy nie powinieneś używać inspect.getmemberszamiast dirrozumieć listę?
Boris

Tak, wydaje się lepiej!
paulmelnikow

11

Otwórz powłokę bash (ctrl + alt + T na Ubuntu). Uruchom w nim powłokę python3. Utwórz obiekt do obserwacji metod. Po prostu dodaj kropkę i naciśnij dwukrotnie „tab”, a zobaczysz coś takiego:

 user@note:~$ python3
 Python 3.4.3 (default, Nov 17 2016, 01:08:31) 
 [GCC 4.8.4] on linux
 Type "help", "copyright", "credits" or "license" for more information.
 >>> import readline
 >>> readline.parse_and_bind("tab: complete")
 >>> s = "Any object. Now it's a string"
 >>> s. # here tab should be pressed twice
 s.__add__(           s.__rmod__(          s.istitle(
 s.__class__(         s.__rmul__(          s.isupper(
 s.__contains__(      s.__setattr__(       s.join(
 s.__delattr__(       s.__sizeof__(        s.ljust(
 s.__dir__(           s.__str__(           s.lower(
 s.__doc__            s.__subclasshook__(  s.lstrip(
 s.__eq__(            s.capitalize(        s.maketrans(
 s.__format__(        s.casefold(          s.partition(
 s.__ge__(            s.center(            s.replace(
 s.__getattribute__(  s.count(             s.rfind(
 s.__getitem__(       s.encode(            s.rindex(
 s.__getnewargs__(    s.endswith(          s.rjust(
 s.__gt__(            s.expandtabs(        s.rpartition(
 s.__hash__(          s.find(              s.rsplit(
 s.__init__(          s.format(            s.rstrip(
 s.__iter__(          s.format_map(        s.split(
 s.__le__(            s.index(             s.splitlines(
 s.__len__(           s.isalnum(           s.startswith(
 s.__lt__(            s.isalpha(           s.strip(
 s.__mod__(           s.isdecimal(         s.swapcase(
 s.__mul__(           s.isdigit(           s.title(
 s.__ne__(            s.isidentifier(      s.translate(
 s.__new__(           s.islower(           s.upper(
 s.__reduce__(        s.isnumeric(         s.zfill(
 s.__reduce_ex__(     s.isprintable(       
 s.__repr__(          s.isspace(           

1
Podczas gdy mówimy o takich obejściach, dodam, że możesz także uruchomić ipython, zacząć pisać obiekt i nacisnąć, taba on również zadziała. Nie są wymagane ustawienia readline
Max Coplan

1
@MaxCoplan Dodałem obejście w kodzie dla przypadków, w których uzupełnianie tabulatorami nie jest domyślnie włączone
Valery Ramusik

8

Problem ze wszystkimi wskazanymi tutaj metodami polega na tym, że NIE MOŻESZ być pewien, że metoda nie istnieje.

W Pythonie można przechwytywać kropki wywołujące __getattr__i __getattribute__, dzięki czemu możliwe jest utworzenie metody „w czasie wykonywania”

Przykład:

class MoreMethod(object):
    def some_method(self, x):
        return x
    def __getattr__(self, *args):
        return lambda x: x*2

Jeśli go wykonasz, możesz wywołać metodę nieistniejącą w słowniku obiektowym ...

>>> o = MoreMethod()
>>> o.some_method(5)
5
>>> dir(o)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'some_method']
>>> o.i_dont_care_of_the_name(5)
10

I dlatego używasz Łatwiejszego do wybaczenia niż paradygmatów zgody w Pythonie.


6

Najprostszym sposobem uzyskania listy metod dowolnego obiektu jest użycie help()polecenia.

%help(object)

Spowoduje to wyświetlenie wszystkich dostępnych / ważnych metod związanych z tym obiektem.

Na przykład:

help(str)

Co robi %pierwszy przykład? To nie działa w moim Pythonie 2.7.
Scorchio,

@ Scorchio Użyłem „%” jako zachęty zamiast „>>>” dla pythona. Możesz zdjąć% przed uruchomieniem polecenia.
Paritosh Vyas,

3
import moduleName
for x in dir(moduleName):
print(x)

To powinno działać :)


1

Można utworzyć getAttrsfunkcję, która zwróci nazwy właściwości obiektu, które można wywoływać

def getAttrs(object):
  return filter(lambda m: callable(getattr(object, m)), dir(object))

print getAttrs('Foo bar'.split(' '))

To by wróciło

['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
 '__delslice__', '__eq__', '__format__', '__ge__', '__getattribute__', 
 '__getitem__', '__getslice__', '__gt__', '__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']

1

Nie ma niezawodnego sposobu wylistowania wszystkich metod obiektu. dir(object)jest zwykle przydatny, ale w niektórych przypadkach może nie zawierać wszystkich metod. Zgodnie z dir()dokumentacją : „Za pomocą argumentu spróbuj zwrócić listę prawidłowych atrybutów dla tego obiektu”.

Sprawdzanie, czy istnieje metoda, można wykonać, callable(getattr(object, method))jak już tam wspomniano.


1

Weź listę jako obiekt

obj = []

list(filter(lambda x:callable(getattr(obj,x)),obj.__dir__()))

Dostajesz:

['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__delitem__',
 '__dir__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__gt__',
 '__iadd__',
 '__imul__',
 '__init__',
 '__init_subclass__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__reversed__',
 '__rmul__',
 '__setattr__',
 '__setitem__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'append',
 'clear',
 'copy',
 'count',
 'extend',
 'index',
 'insert',
 'pop',
 'remove',
 'reverse',
 'sort']

0

... czy istnieje co najmniej łatwy sposób sprawdzenia, czy ma określoną metodę inną niż po prostu sprawdzenie, czy błąd występuje podczas wywoływania metody

Chociaż „ Łatwiej prosić o wybaczenie niż o pozwolenie ” jest z pewnością pytonicznym sposobem, czego szukasz może:

d={'foo':'bar', 'spam':'eggs'}
if 'get' in dir(d):
    d.get('foo')
# OUT: 'bar'

0

Aby wyszukać określoną metodę w całym module

for method in dir(module) :
  if "keyword_of_methode" in method :
   print(method, end="\n")

-1

Jeśli na przykład używasz powłoki plus, możesz użyć tego:

>> MyObject??

w ten sposób z „??” zaraz po twoim obiekcie pokażą ci wszystkie atrybuty / metody klasy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.