2

I would like to enumerate some instance methods inside a class. The operate function needs to use foo1, foo2,.. as Foo.FOO1, Foo.FOO2,.. .

class Machine:
    def __init__(self):
        self.operate()

    def foo1(self):
        pass
    def foo2(self):
        pass
    ..

    class Foo(Enum):
        FOO1 = Machine.foo1 # Machine is not defined
        FOO2 = Machine.foo2 # Machine is not defined
        ..
    
    def operate(self):
        # use self.Foo.FOO1, self.Foo.FOO2,..

I do not know how to define the enum class.

giannisl9
  • 151
  • 2
  • 11
  • 2
    Do you mean you need a way to *find* "some instance methods"? How do you distinguish between ones you want to enumerate and ones you don't? – Scott Hunter Dec 26 '19 at 15:33
  • this one may helps you https://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python?rq=1 – Basavaraju US Dec 26 '19 at 15:35
  • @ScottHunter, this will be decided in the enum class Foo. Not all of the methods are part of the enum. – giannisl9 Dec 26 '19 at 15:44
  • Do you want the enum to refer to the unbound methods (Machine.foo1) or the bound methods of an instance (self.foo1)? – MisterMiyagi Dec 26 '19 at 15:59
  • 1
    Related to the error you're getting: [How to use class name in class scope?](https://stackoverflow.com/q/19622550/4518341) – wjandrea Dec 26 '19 at 16:05
  • @MisterMiyagi, I think there is no distinction between bound and unbound methods in Python 3.x. I would say that the enum enumerates methods that need to be able to alter the state of the instance. – giannisl9 Dec 26 '19 at 16:09
  • 1
    @giannisl9 There is no distinction between unbound methods and functions. Unlike an unbound method, a bound method can be used without knowing its instance. – MisterMiyagi Dec 26 '19 at 16:12
  • @wjandrea, so maybe define the enum inside __init__? – giannisl9 Dec 26 '19 at 16:13
  • @MisterMiyagi, I thought that what used to be called a bound method is now just a method that is wrapped by another function that provides the instance variable. – giannisl9 Dec 26 '19 at 16:22
  • 1
    Python 3 only knows function type and method type. The former is unbound, the latter is bound, with respect to instances. – MisterMiyagi Dec 26 '19 at 16:57

3 Answers3

2

The solution proposed by @giannisl9 is bugged, although it apparently works at first sight, a closer inspection reveals the Enum is broken:

from enum import Enum


class Machine:

    def __init__(self):
        class Foo(Enum):
            FOO1 = self.foo1
        self.foo = Foo
        self.operate()

    def foo1(self):
        pass

    def operate(self):
        # breaks Enum contract, breaks syntax, breaks functionality...
        self.foo.FOO1()  # Enum member is NOT available! Method of class Machine bound in its place.
        print(type(self.foo))  # {type}<class'enum.EnumMeta'> - Enum 'Foo'
        print(type(self.foo.FOO1))  # {type} <class 'method'> - should be Enum member
        print(type(self.foo.FOO1.name))  # {AttributeError}'function'object has no attribute 'name'
        print(type(self.foo.FOO1.value))  # {AttributeError}'function'object has no attribute 'value'

Building on the answer by @Epic Programmer -since the original question only stated as requirement defining an Enum to run instance methods- given the application, organizing procedures in the __init__ or other methods, could suffice:

from inspect import ismethod
from inspect import isbuiltin


class Machine(object):

    def operate(self):
        for method in self.__dir__():
            if ismethod(getattr(self, method)) \
                    and not isbuiltin(getattr(self, method)) \
                    and '__' not in method \
                    and 'operate' != method:  # delete this to see a recursion
                self.__getattribute__(method)()  # after much filtering runs the method

    def __init__(self):

        self.operate()

    def foo1(self):
        print("drinks at bar1")

However, as I understand the question, it makes perfect sense the Enum should be internal to the class, since ontologically it pertains to encode/abbreviate a set of states proper to all instances of the class. That makes lots of sense!

It doesn't make much sense declaring it inside the __init__ as a self instance constant. Instead, it should be used as a symbolic class constant allowing to encode everything that in common may pertain to the instances.

from enum import Enum


class Machine:

    class Foo(Enum):  
        # you could comma separate any combination for a given state
        FOO1 = "foo1"   
        FOO2 = "foo2"

    def __init__(self, arg_foo):

        self.foo = arg_foo
        self.operate()
        self.all_operations()

    def foo1(self):
        print('drinks at bar1')

    def foo2(self):
        print('drinks at bar2')

    def all_operations(self):
        for one_member in Machine.Foo:
            self.__getattribute__(one_member.value)()

    def operate(self):
        self.__getattribute__(str(self.foo.value))()


go_bar1 = Machine(Machine.Foo.FOO1)
go_bar2 = Machine(Machine.Foo.FOO2)
go_bar1.all_operations()  # bar crawl

Or perhaps this is, approximately, what you're looking for:

from enum import Enum


class Machine:

    def __init__(self, receive: Enum):

        for one in receive.value:
            if one is not None:
                one(self)  # Zen of Python

    def foo1(self):
        print('drinks at bar1')

    def foo2(self):
        print('drinks at bar2')


class Runner(Enum):
    FOO1 = getattr(Machine, 'foo1'), getattr(Machine, 'foo2')
    FOO2 = getattr(Machine, 'foo2'), None


first = Machine(Runner.FOO1)
second = Machine(Runner.FOO2)

I hope this helps.

bad_coder
  • 11,289
  • 20
  • 44
  • 72
1

Provided all methods in the Foo class that do not start with _ are methods you want to use, just iterate over the contents of the Foo class and get the attributes of the methods that match:

class Machine:
    def operate(self):
        for attribute in dir(self.Foo):
            if attribute[0] != "_":
                getattr(self.Foo, attribute)()
Epic Programmer
  • 383
  • 3
  • 12
  • Thank you for your answer but I think that it does not answer my question which is about how to define the enum class. – giannisl9 Dec 26 '19 at 16:26
0

Following How to use class name in class scope? and what made the most sense for my case, defining the enum inside the init method seems the way to go.

class Machine:
    def __init__(self):
        class Foo(Enum):
            FOO1 = self.foo1
            FOO2 = self.foo2
            ..
        self.Foo = Foo 
        self.operate()

    def foo1(self):
        pass

    def foo2(self):
        pass
    ..

    def operate(self):
        #self.Foo.FOO1(), self.Foo.FOO2(),.. availabe
        #self.Foo holds the enumeration
giannisl9
  • 151
  • 2
  • 11
  • The problem is: this breaks the `Enum`. The difficulty is defining it as an inner class, because you'd have to introspect the outer class, to reference outer methods. Most recipes advise going for easier solutions, because the result will be the same(better). Can this be done? Probably, but hardly justifying the time, and who came next would be left in a hard place trying to understand your code. Were it pressing, the docs/api would hint a straightforward solution. Instead we are advised to avoid this. PEP 395 gives an interesting overview of the pitfalls and intricacies involved... – bad_coder Dec 29 '19 at 03:15