2

The dir() function return a list of the methods but:

The resulting list is sorted alphabetically

I want to know which ones are but not sorted alphabetically. I use the name to help to understand what does this method. I use name like game_start, game_battle, game_map. I could change the name to start, battle, map but if I want to use the same submit method for all this other methods in a tkinter app. So I need the name of the methods to eval in the order of declaration.

Is there any other workaround?

example:

class hi(object):
    def __init__(self):
        self.name="LLopis"
    def question(self):
        print("Question?")
    def answer(self):
        print("Answer")

The result of dir(hi) is:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'answer', 'question']

I want a function that return instead (or whatever is the internal order of the private methods, but by order of finding):

['__init__', 'question', 'answer']

Edit: I do not care about attributes like hi.name, therefore although this question is related it is not an exact duplicate.

Community
  • 1
  • 1
llrs
  • 3,308
  • 35
  • 68
  • The 'internal' order is a *dictionary*, so **not ordered**. – Martijn Pieters Aug 10 '14 at 18:41
  • 3
    Why is being sorted alphabetically a problem? Do you want the order in which they occurred in source code? If so, what are you trying to achieve that way? –  Aug 10 '14 at 18:43
  • I want to use the methods I define in the order I write them inside the class, but I don't want to define a list with the wanted order or change the methods' name. – llrs Aug 10 '14 at 18:49
  • What version of Python are you using? – Jon Clements Aug 10 '14 at 18:49
  • I am using python 3.3 – llrs Aug 10 '14 at 18:49
  • I've closed as a certain dupe target... but if anyone can find a better target as I know this has been asked various times (in some form or another) – Jon Clements Aug 10 '14 at 18:52
  • @Jon I just want methods so I think it is not a duplicate of attributes declaration sorting – llrs Aug 10 '14 at 18:53
  • 1
    "I don't want to define a list with the wanted order or change the methods' name." I cannot think of a scenario where this would be a major issue. – TheSoundDefense Aug 10 '14 at 18:54
  • @Llopis okay... I've re-opened but I *know* this has been asked before... (agree though that probably wasn't the best target - apologies) – Jon Clements Aug 10 '14 at 18:56
  • @TheSoundDefense It is an exercise, it is not a real scenario, but I do not want to change the method from game_* to game_a*, game_b*. Jon I would be glad to know where or how, if you remember or find it let me know please. – llrs Aug 10 '14 at 18:58
  • Start with the example from the docs https://docs.python.org/3/reference/datamodel.html#customizing-class-creation - then filter out callables either using `inspect.ismethod` or `callable` – Jon Clements Aug 10 '14 at 19:16

3 Answers3

3

When executing a program, the interpreter (CPython) does not preserve the order in which a class's methods got declared, so there's no way to find that out at runtime other than by looking at the source code.

P.S. But see a remark by @Jon Clements in the comments below.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 2
    Not exactly true - if the OP is using Python 3.x, `__prepare__` with a metaclass can be used to return a custom dictionary (such as an `OrderedDict`) - there are hack-arounds in 2.x also available – Jon Clements Aug 10 '14 at 18:48
  • @JonClements: Fair enough. I'll add a remark pointing to this comment of yours. :-) – NPE Aug 10 '14 at 18:49
  • @JonClements: BTW, feel free to write up a better answer. I'd be happy to upvote that and delete mine as it's clearly half-baked. – NPE Aug 10 '14 at 18:50
1

Specifically to CPython, you can utilize the fistrlineno property:

fns = []
for p in dir(hi):
    a = getattr(hi, p)
    if hasattr(a, '__code__'):
        fns.append((a.__code__.co_firstlineno, p))


print([x[1] for x in sorted(fns)])  # ['__init__', 'question', 'answer']
georg
  • 211,518
  • 52
  • 313
  • 390
  • Thanks but I still don't understand the co_firstlineno property. I found that is the first line (https://docs.python.org/2/library/inspect.html) of a definition, but in the python-dev there is some discussion about it in 2010: https://mail.python.org/pipermail/python-dev/2010-August/102735.html. Do you have a clear idea of how to use it? – llrs Aug 11 '14 at 12:20
  • 1
    From my understanding, that thread is about decorated functions and returning exact line numbers. For your problem, only relative position is important, so what exactly does `firstlineno` return doesn't matter much. – georg Aug 11 '14 at 12:26
0

Compile the source code (accessed with inspect) yourself to an abstract syntax tree (AST) and then list the method names:

import ast, inspect
codeobj = compile(inspect.getsource(hi), "<string>", "exec", flags=ast.PyCF_ONLY_AST)
methods = [_.name for _ in codeobj.body[0].body]
print(methods) # ['__init__', 'question', 'answer']

This only works if you save the code to a file, not in the IDLE, but I assume that you are doing this anyway.

example run on my computer

pascalhein
  • 5,700
  • 4
  • 31
  • 44