Лямбда-функция для классов в Python?

Должен быть простой способ сделать это, но каким-то образом я могу обернуть голову вокруг этого. Лучший способ описать то, что я хочу, - это лямбда-функция для класса. У меня есть библиотека, которая ожидает в качестве аргумента необоснованную версию класса для работы. Затем он создает экземпляр самого класса для работы. Проблема в том, что я хотел бы иметь возможность динамически создавать версии класса, передавать их в библиотеку, но я не могу понять, как это сделать, поскольку библиотека ожидает неопознанную версию. Код ниже описывает проблему:

class Double:
    def run(self,x):
        return x*2

class Triple:
    def run(self,x):
        return x*3

class Multiply:
    def __init__(self,mult):
        self.mult = mult
    def run(self,x):
        return x*self.mult

class Library:
    def __init__(self,c):
        self.c = c()
    def Op(self,val):
        return self.c.run(val)

op1 = Double
op2 = Triple
#op3 = Multiply(5)

lib1 = Library(op1)
lib2 = Library(op2)
#lib3 = Library(op3)

print lib1.Op(2)
print lib2.Op(2)
#print lib3.Op(2)

Я не могу использовать универсальный класс Multiply, потому что я должен сначала создать его экземпляр, что нарушает библиотеку «AttributeError: экземпляр Multiply не имеет метода вызова ». Без изменения класса библиотеки, как я могу это сделать?

11.12.2008 18:27:21
6 ОТВЕТОВ
РЕШЕНИЕ

Там нет необходимости лямбда вообще. Лямбда - это всего лишь синтетический сахар для определения функции и одновременного ее использования. Как любой лямбда-вызов можно заменить явным определением, мы можем решить вашу проблему, создав реальный класс, который соответствует вашим потребностям, и вернем его.

class Double:
        def run(self,x):
            return x*2

class Triple:
    def run(self,x):
        return x*3

def createMultiplier(n):
    class Multiply:
        def run(self,x):
            return x*n
    return Multiply

class Library:
    def __init__(self,c):
        self.c = c()
    def Op(self,val):
        return self.c.run(val)

op1 = Double
op2 = Triple
op3 = createMultiplier(5)

lib1 = Library(op1)
lib2 = Library(op2)
lib3 = Library(op3)

print lib1.Op(2)
print lib2.Op(2)
print lib3.Op(2)
8
11.12.2008 18:53:30
Преимущество использования общего конвертера, конечно, состоит в том, что он в принципе принимает любую функцию с одним аргументом, освобождая дальнейшие реализации от необходимости явно определять свои классы
Greg Case 11.12.2008 19:35:18
Мне нравится функция createMultiplier (). Элегантный.
Deestan 12.12.2008 09:38:37
Я знаю, что это старый пост, но здесь стоит кое-что отметить. createMultiplier (4)! = createMultiplier (4). Это потому, что класс создается дважды в двух разных местах памяти. Если у Multiply нет метакласса, который переопределяет поведение по умолчанию для сравнения классов, вы должны создать простой словарь для кэширования созданных объектов класса. Дикт будет иметь ключ n, а значения будут классы. Но это может быть неэффективно при использовании памяти, если группа классов создана, но не используется. Самый простой способ - прикрепить атрибут класса к Multiply. Например, Multiply.x = 5.
Oliver Zheng 22.11.2009 19:32:11

Это своего рода обман, но вы могли бы дать вашему классу Multiply __call__метод, который возвращает сам себя:

class Multiply:
    def __init__(self,mult):
        self.mult = mult
    def __call__(self):
        return self
    def run(self,x):
        return x*self.mult

Таким образом, когда библиотека вызывает c()ее, она действительно вызывает c.__call__()нужный объект.

1
11.12.2008 18:39:04
def mult(x):
    def f():
        return Multiply(x)
    return f


op3 = mult(5)
lib3 = Library(op3)
print lib3.Op(2)
1
11.12.2008 18:42:25

Действительно ли библиотека указывает, что она хочет "неинициализированную версию" (т.е. ссылку на класс)?

Мне кажется, что библиотека действительно хочет фабрику объектов. В этом случае допустимо ввести:

lib3 = Library(lambda: Multiply(5))

Чтобы понять, как работает лямбда, рассмотрите следующее:

Multiply5 = lambda: Multiply(5)
assert Multiply5().run(3) == Multiply(5).run(3)
11
11.12.2008 18:44:54

Если я правильно понимаю ваше проблемное пространство, у вас есть общий интерфейс, который принимает 1 аргумент, который вызывается с использованием Libraryкласса. К сожалению, вместо вызова функции Libraryпредполагается, что функция заключена в класс с runметодом.

Вы, конечно, можете создавать эти классы программно. Классы могут быть возвращены методами, и благодаря концепции замыканий вы сможете обернуть любую функцию в классе, которая соответствует вашим потребностям. Что-то вроде:

def make_op(f):
  class MyOp(object):
    def run(self, x):
      return f(x)
  return MyOp

op1 = make_op(lambda x: return x*2)
op2 = make_op(lambda x: return x*3)

def multiply_op(y):
    return make_op(lambda x: return x*y)

op3 = multiply_op(3)

lib1 = Library(op1)
lib2 = Library(op2)
lib3 = Library(op3)

print( lib1.Op(2) )
print( lib2.Op(2) )
print( lib3.Op(2) )

Тем не менее, изменение библиотеки для получения функции и последующее предоставление функций, вероятно, является более надежным способом сделать это.

1
11.12.2008 18:50:19

Так typeкак класс по умолчанию для объекта класса Python, и вызов класса создает новый экземпляр этого класса, вызов typeс правильными аргументами приведет к новому классу.

my_class = type("my_class", (object,), {"an_attribute": 1})

my_classтеперь относится к новому классу с именем «my_class», который является подклассом object, с атрибутом «an_attribute», значение которого равно 1. Поскольку методы также являются просто атрибутами класса, указывающими на объект функции, вы можете добавить их в словарь атрибутов:

{"an_attribute": 1, "a_method": lambda self: print("Hello")}

Вот как это работает. Я не рекомендую делать это таким образом, если вам абсолютно не нужно. В 99% случаев вы этого не делаете. Обратитесь к ответу @Parker Coates, чтобы узнать, как достичь цели.

0
3.12.2018 18:14:22