Het detecteren van de gebonden methode in klassen (niet exemplaren) in Python 3

Gegeven een klasse C met een functie of methode f , gebruik ik inspect.ismethod (obj.f) (waarbij obj is een instantie van C ) om te achterhalen of f methode is gebonden of niet. Is er een manier om hetzelfde op klasniveau te doen (zonder een object te maken)?

inspect.ismethod werkt niet als volgt:

class C(object):

    @staticmethod
    def st(x):
        pass

    def me(self):
        pass

obj = C()

resulteert hierin (in Python 3):

>>> inspect.ismethod(C.st) 
False
>>> inspect.ismethod(C.me)
False
>>> inspect.ismethod(obj.st) 
False
>>> inspect.ismethod(obj.me)
True

Ik denk dat ik moet controleren of de functie/methode lid is van een klasse en niet statisch, maar ik was niet in staat om het gemakkelijk te doen. Ik denk dat het kan worden gedaan met behulp van classify_class_attrs zoals hier getoond Hoe zou u bepaalt waar elke eigenschap en methode van een Python-klasse is gedefinieerd? maar ik hoopte dat er nog een meer directe manier was.

2

3 antwoord

Er zijn geen ongebonden methoden in Python 3, dus je kunt ze ook niet detecteren. Het enige dat je hebt zijn reguliere functies. Hooguit kunt u zien of ze een gekwalificeerde naam met een punt , wat aangeeft dat ze genest zijn , en hun eerste argumentnaam is zelf :

if '.' in method.__qualname__ and inspect.getargspec(method).args[0] == 'self':
    # regular method. *Probably*

Dit mislukt natuurlijk volledig voor statische methoden en geneste functies die toevallig zelf bevatten als eerste argument, evenals reguliere methoden die self niet als eerste argument gebruiken ( vliegen in het zicht van conventie).

Voor statische methoden en klassemethoden moet u in plaats daarvan naar het klassenwoordenboek gaan:

>>> isinstance(vars(C)['st'], staticmethod)
True

Dat komt omdat C .__ dict __ ['st'] de eigenlijke instantie staticmethod is, vóór binden aan de klas .

2
toegevoegd

Zou u inspect.isroutine (...) kunnen gebruiken? Uitgevoerd met uw class C krijg ik:

>>> inspect.isroutine(C.st)
True
>>> inspect.isroutine(C.me)
True
>>> inspect.isroutine(obj.st)
True
>>> inspect.isroutine(obj.me)
True

Als u de resultaten van inspect.isroutine (...) combineert met de resultaten van inspect.ismethod (...) , kunt u bepalen wat u moet weten.

Edit: dm03514's answer suggests you might also try inspect.isfunction():

>>> inspect.isfunction(obj.me)
False
>>> inspect.isfunction(obj.st)
True
>>> inspect.isfunction(C.st)
True
>>> inspect.isfunction(C.me)
False

Hoewel, zoals Hernan heeft opgemerkt, de resultaten van inspect.isfunction (...) veranderen in python 3.

0
toegevoegd

Omdat inspect.ismethod True retourneert voor zowel gebonden als ongebonden methoden in Python 2.7 (dat wil zeggen, is verbroken), gebruik ik:

def is_bound_method(obj):
    return hasattr(obj, '__self__') and obj.__self__ is not None

Het werkt ook voor methoden van klassen geïmplementeerd in C, bijvoorbeeld int:

>>> a = 1
>>> is_bound_method(a.__add__)
True
>>> is_bound_method(int.__add__)
False

Maar is niet erg handig in dat geval omdat inspect.getargspec niet werkt voor functies geïmplementeerd in C.

is_bound_method werkt ongewijzigd in Python 3, maar in Python 3 maakt inspection.ismethod op de juiste manier onderscheid tussen ingebonden en ongebonden methoden, dus het is niet nodig.

0
toegevoegd
Dit is alleen handig voor Python twee , terwijl de vraag specifiek betrekking heeft op Python drie , waar er geen ongebonden methoden zijn.
toegevoegd de auteur Martijn Pieters, de bron