Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

comment est implementée telle methode de tel objet

+3 votes

Pour connaitre les méthodes d'un objet on peut faire :

[method for method in dir(monobjettropcool) if callable(getattr(monobjettropcool, method))]

Comment faire pour avoir le détail de l'implementation d'une methode ?

Y a t il une particularité dans le cas de méthodes magiques ?

Dans le cas d'un heritage avec un type de base comme list ou dict par exemple, comment faire si il s'agit d'une methode built in ?

types.BuiltinMethodType

*The type of built-in functions like len() or sys.exit(), and methods of built-in classes. (Here, the term “built-in” means “written in C”.)*
demandé 6-Nov-2016 par buffalo974 (2,956 points)
edité 7-Nov-2016 par buffalo974

1 Réponse

+3 votes
 
Meilleure réponse

Le détail d'implémentation n'est, à ma connaissance, pas accessible depuis l'interpréteur. Cette réponse SO est très explicative.
Cela dit, il est possible de savoir où la trouver :

def f(): pass
print('{}: {} at line {}'.format(f, f.__code__.co_filename, f.__code__.co_firstlineno))

Généralement, accéder aux sources pendant l'exécution n'est pas vraiment utile. La fonction help est probablement beaucoup plus utile que les lignes de codes qui renseignent sur le comment, et non le pourquoi.

Enfin, si cela est nécessaire, le paquet dis permet de déssassembler le code. C'est très rigolo à expérimenter, et cela permet d'avoir accès au bytecode python:

print(dis.dis(f.__code__))

Concernant les builtins, l'accès programmatique au code source est encore moins pertinent, d'autant plus qu'il dépends beaucoup de l'interpréteur, bien plus que la lib standard écrite en Python. Pour CPython, on trouve par exemple l'implémentation des dictionnaires dans dictobject.c.


Voilà un snippet fait rapidement à la main et probablement pas très canonique qui permet d'afficher les sources d'un objet python.

def lines_since_obj_source(obj) -> iter:
    fn, ln = obj.__code__.co_filename, obj.__code__.co_firstlineno
    with open(fn) as fd:
        for idx, line in enumerate(fd, start=1):
            if idx >= ln:
                yield line

def block_lines(lines:iter) -> iter:
    level_of = lambda line: line.find(line.lstrip())  # nb of heading spaces
    lines = iter(lines)
    first_line = next(lines)
    base_level = level_of(first_line)
    yield first_line[base_level:]
    for line in lines:
        if line.strip() and level_of(line) <= base_level:
            break
        yield line[base_level:]

def source(obj, joiner='') -> str:
    try:
        return joiner.join(block_lines(lines_since_obj_source(obj)))
    except AttributeError:  # obj have no __code__ attr: probably a C module
        return None

Et voilà deux exemples d'utilisation:

import random

def f():
    pass
    pass
    pass

for obj in (f, random.randrange, random.random):
    print("Source of object {} is:".format(obj))
    print(source(obj) or "No available source. Probably a builtin, a module or a class.")

Selon le type d'objet, il faudrait un code différent. Les modules et les classes ne sont pas accessibles de la même façon. Pour les premières, il faudrait passer par l'attribut __file__, et les seconde par l'attribut __module__ suivis d'une recherche de la définition de la classe.

répondu 7-Nov-2016 par lucas (2,340 points)
sélectionné 8-Nov-2016 par buffalo974
...