使用值列表为类动态创建方法

2024-07-04 07:38:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个值列表,希望用于正在进行的生成器对象实现

例如:

val_list = ["abc", "def", "ghi"]

我想做的是在类中动态创建方法,允许在实例中调用和检索这些方法

我对使用setattr(…)执行此操作有点熟悉,但下一步我要做的是能够在方法内部执行一些处理。在下面的例子中,如果我要用我不断增长的列表来做这件事,它将是一大堆做同样事情的代码。它现在起作用了,但我希望这个列表和类一样是动态的

比如说

def abc(self, value):
     self.processing1 = value + "workworkwork"
     return self

def def(self, value):
     self.processing1 = value + "workworkwork"
     return self

def ghi(self, value):
     self.processing1 = value + "workworkwork"
     return self

Tags: 对象实例方法self列表returnvaluedef
2条回答

如果不先包装对象,则无法对其调用不存在的方法,例如:

# A legacy class
class dummy:
    def foo(self):
        return "I'm a dummy!"

obj = dummy()
obj.a("1")    # You can't

您可以先使用包装器类来完成,这里只是一个如何完成的想法:

# Creates a object you can append methods to
def buildable(cls):
    class fake:
        # This method will receive the class of the object to build
        def __init__(self, cls):
            self.cls = cls
        
        # This will simulate a constructor of the underlying class
        # Return the fake class so we can call methods on it
        def __call__(self, *args, **kwargs):
            self.obj = self.cls(*args, **kwargs)
            return self
        
        # Will be called whenever a property (existing or non-existing)
        # is called on a instance of the fake class
        def __getattr__(self, attr):
            # If the underlying object has the called attribute,
            # just return this attribute
            if hasattr(self.obj, attr):
                return getattr(self.obj, attr)
            
            # Call the respective function on globals with the provided 
            # arguments and return the fake class so we can add more methods
            def wrapper(*args, **kwargs):
                globals()[attr](self.obj, *args, **kwargs)
                return self
                
            return wrapper
            
    return fake(cls)

那么,这是如何工作的呢

  1. 装饰您的传统课程:
@buildable
class dummy:
    def foo(self):
        return "I'm a dummy!"
  1. 创建将修改dummy的生成方法:
def a(self, some):
    self.a = some + 'a'
    
def b(self, some):
    self.b = some + 'b'
    
def c(self, some):
    self.c = some + 'c'
  1. 修改它:
obj = dummy()
obj.a("1").b("2").c("3")
  1. 查看全新属性(以及旧属性!):
print(obj.a)      # 1a
print(obj.b)      # 2b
print(obj.c)      # 3c
print(obj.foo())  # I'm a dummy!

请注意,这有一些重要的缺点,例如:

  • dummy上调用不存在的属性不会引发AttributeError:
print(obj.nini)  # <function buildable.<locals>.fake.__getattr__.<locals>.wrapper at 0x7f4794e663a0>
  • 不能对多个对象执行此操作:
obj1 = dummy()
obj1.a("1").b("2")

print(obj1.a)  # 1a
print(obj1.b)  # 2b

obj2 = dummy()
obj2.c("3")

print(obj2.c)  # 3c

print(obj1.a)  # <function buildable.<locals>.fake.__getattr__.<locals>.wrapper at 0x7f524ae16280>
print(obj1.b)  # <function buildable.<locals>.fake.__getattr__.<locals>.wrapper at 0x7f524ae16280>
  • obj的类型将不是dummy
print(type(obj))      # <class '__main__.buildable.<locals>.fake'>
print(type(obj.obj))  # <class '__main__.dummy'>
  • 不能使用与现有方法相同的名称调用生成方法:
def foo(bar):
    self.foo = 'foo' + bar
    
obj.foo("bar")
print(obj.foo())
# raises TypeError: foo() takes 1 positional argument but 2 were
list = buildable(list)
obj = list()
obj.a("4").b("5").c("6")
# raises AttributeError: 'list' object has no attribute 'a'

我以前没有尝试过这个,但是我想知道使用lambdas是否可以

self.my_methods = {}

val_list = []

def new_method(self,method_name):
   self.my_methods[method_name] = "lambda: self.general_method(some_value)"

def general_method(self, value):
   print(value)

老实说,我相信这不会像写的那样奏效,但如果你可能感兴趣的话,希望你能看到思路。因为我无法想象整体概念,所以有点难

但由于方法名称似乎很重要,我不确定该怎么办。也许这是一个XY类型的问题?被困在如何而不是结果上

我认为必须有一种方法来实现这一目标:

[Class definition]
...

def method(self,secret_method_name,arg1):
   # do something based on method name if necessary
   # do something based on args

相关问题 更多 >

    热门问题