Python: Позволяет методам, не определенным специально, называться ala __getattr__ - PullRequest
5 голосов
/ 08 августа 2010

Я пытаюсь написать класс Python, который может выполнять следующие действия:

c = MyClass()
a = c.A("a name for A") # Calls internally c.create("A", "a name for A")
b = c.B("a name for B") # Calls internally c.create("B", "a name for B")

A и B могут быть чем угодно (ну, они определены в базе данных, но я не хочу явно определять их в моем коде)

Хакерский обходной путь для этого заключается в следующем:

class MyClass():
    def __init__(self):
        self.createItem = ""

    def create(self, itemType, itemName):
        print "Creating item %s with name %s" % (itemType, itemName)

    def create_wrapper(self, name):
        self.create(self.createItem, name)

    def __getattr__(self, attrName):
        self.createItem = attrName
        return self.create_wrapper

Это будет работать, когда пользователь вызывает что-то вроде:

a = c.A("nameA")
b = c.B("nameB")

Тем не менее, он может упасть в ситуациях, когда указатели функций сохраняются без вызова:

aFunc = c.A
bFunc = c.B
aFunc("nameA") # Is actually calling c.create("B", "nameA"),
               # as c.B was the last __getattr__() call
bFunc("nameB")

Какие-нибудь предложения для чего-то, что я пропускаю здесь?

Спасибо

Редактировать: Кажется, я только что понял это, но у Филиппа гораздо более элегантное решение ...

Мое решение было:

class MyClassCreator():
    def __init__(self, origClass, itemType):
        self.origClass = origClass
        self.itemType = itemType

    def create_wrapper(self, name):
        return self.origClass.create(self.itemType, name)

class MyClass():
    def __init__(self):
        self.createItem = ""

    def create(self, itemType, itemName):
        print "Creating item %s with name %s" % (itemType, itemName)

    def __getattr__(self, attrName):
        return MyClassCreator(self, attrName).create_wrapper

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

def __getattr__(self, attrName):
    def find_entity_wrapper(*args, **kwargs):
        return self.find_entity(attrName, *args, **kwargs)

    return find_entity_wrapper

Ответы [ 2 ]

8 голосов
/ 08 августа 2010

Иметь __getattr__ возвращать локальную функцию-обертку:

class MyClass(object):
    def create(self, itemType, itemName):
        print "Creating item %s with name %s" % (itemType, itemName)

    def __getattr__(self, attrName):
        def create_wrapper(name):
            self.create(attrName, name)
        return create_wrapper

Существуют и другие способы создания функции-оболочки. Самым простым в этом случае является использование functools.partial:

import functools

class MyClass(object):
    def create(self, itemType, itemName, *args, **kwargs):
        print "Creating item %s with name %s, args %r and kwargs %r" % (itemType, itemName, args, kwargs)

    def __getattr__(self, attrName):
        return functools.partial(self.create, attrName)

c = MyClass()
bFunc = c.B
bFunc("nameB", 1, 2, foo=3)

Это автоматически передаст все оставшиеся аргументы в упакованную функцию.

6 голосов
/ 08 августа 2010

Вы можете получить то, что хотите, упрощая:

class MyClass():

    def create(self, itemType, itemName):
        print "Creating item %s with name %s" % (itemType, itemName)

    def __getattr__(self, attrName):
        return lambda x: self.create(attrName, x)

c = MyClass()
a = c.A("nameA")
b = c.B("nameB")


af = c.A
bf = c.B
af("nameA")
bf("nameB")

отпечатки:

Creating item A with name nameA
Creating item B with name nameB
Creating item A with name nameA
Creating item B with name nameB
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...