【问题标题】:Enumerate instance methods in Python在 Python 中枚举实例方法
【发布时间】:2019-12-26 15:28:03
【问题描述】:

我想列举一个类中的一些实例方法。 operate函数需要使用foo1,foo2,..作为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,..

我不知道如何定义枚举类。

【问题讨论】:

  • 你的意思是你需要一种方法来找到“一些实例方法”吗?你如何区分你想列举的和不想列举的?
  • 与您遇到的错误相关:How to use class name in class scope?
  • @giannisl9 未绑定的方法和函数没有区别。与未绑定方法不同,绑定方法可以在不知道其实例的情况下使用。
  • Python 3 只知道函数类型和方法类型。就实例而言,前者是未绑定的,后者是绑定的。

标签: python python-3.x enums


【解决方案1】:

@giannisl9 提出的解决方案存在漏洞,虽然乍一看似乎可行,但仔细检查发现Enum 已损坏:

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'

在@Epic Programmer 的回答的基础上——因为最初的问题仅陈述为定义Enum 以运行实例方法的要求——给定应用程序,在__init__ 或其他方法中组织过程就足够了:

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")

但是,据我理解这个问题,Enum 应该在类内部是完全有道理的,因为从本体上讲,它涉及编码/缩写一组适合于类的所有实例的状态。这很有意义!

__init__ 中将其声明为self 实例常量没有多大意义。相反,它应该用作一个符号类常量,允许对可能与实例相关的所有内容进行编码。

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

或者这大概就是您正在寻找的东西:

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)

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    前提是Foo类中所有不以_开头的方法都是你要使用的方法,遍历Foo类的内容,获取匹配的方法的属性即可:

    class Machine:
        def operate(self):
            for attribute in dir(self.Foo):
                if attribute[0] != "_":
                    getattr(self.Foo, attribute)()
    

    【讨论】:

    • 感谢您的回答,但我认为它没有回答我关于如何定义枚举类的问题。
    【解决方案3】:

    按照How to use class name in class scope? 以及对我的情况最有意义的是,在 init 方法中定义枚举似乎是可行的方法。

    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
    

    【讨论】:

    • 问题是:这破坏了Enum。困难在于将其定义为内部类,因为您必须自省外部类以引用外部方法。大多数食谱建议使用更简单的解决方案,因为结果会相同(更好)。这可以做到吗?可能,但很难证明时间的合理性,下一个来的人将很难理解您的代码。如果它很紧迫,docs/api 将暗示一个简单的解决方案。相反,我们建议避免这种情况。 PEP 395 对所涉及的陷阱和复杂性进行了有趣的概述......
    猜你喜欢
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 2015-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多