Как динамически добавить свойство reify к объекту Python3 - PullRequest
0 голосов
/ 22 декабря 2018

Я пытаюсь сделать что-то продвинутое волшебство, и я не до конца понимаю проблему, которая не вызывает сомнений, почему у меня возникают проблемы при ее решении.

Если я делаю что-то супер хакерское и позволяю ребенку(DailyPic) знаю о его родителе (Site), тогда я могу заставить все работать, но я не могу понять, как динамически сделать это только из Site.

Я пытаюсьдинамически добавьте фантастический reify (слегка измененный) к DailyPic, но у экземпляра DailyPic вызовите метод для экземпляра Site.

hacky, но он работает

class reify():
    def __init__(self, wrapped, name=None):
        self.wrapped = wrapped

        if name is None:
            from functools import update_wrapper
            update_wrapper(self, wrapped)
        else:
            self.wrapped.__name__ = name

    def __get__(self, inst, objtype=None):
        if inst is None:
            return self
        val = self.wrapped(inst)
        setattr(inst, self.wrapped.__name__, val)
        return val

class Site:
    def __init__(self):
        self.counter = 0

    def mk_filename(self, pic):
        self.counter += 1
        return f"{self.__class__.__name__}-{self.counter}.{pic.ext()}"

    def save(self):
        pic = DailyPic()

        from functools import partial
        pic._mk_filename = partial(self.mk_filename, pic)

        return pic


class DailyPic:
    def ext(self):
        return 'gif' # simplified for example

    @reify
    def filename(self):
        return self._mk_filename() # YUCK!!!

# works but ugly...

class Site1(Site): pass
class Site2(Site): pass

pic1 = Site1().save()
pic2 = Site2().save()

print(pic1.filename) # Site1-1
print(pic2.filename) # Site2-1

Я пытаюсь добраться до чего-то подобного:

class Site:
    def save(self):
        pic = DailyPic()
        DailyPic.filename = reify(
            functools.partial(lambda pic: self.mk_filename(pic)),
            'filename'
        )
        return pic

# sorta works...

print(pic1.filename) # Site2-1 , should be Site1-1
print(pic2.filename) # Site2-2 , should be Site2-1

Если бы продвинутый волшебник мог звонить в это, это было бы фантастически!

1 Ответ

0 голосов
/ 23 декабря 2018

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

class Site:
    def save(self):
        pic = DailyPic()

        def filename(pic_self):
            val = self.mk_filename(pic_self)
            pic_self.filename = lambda _: val
            return val

        pic.filename = filename
        return pic

, тогда это просто:

print(pic1.filename())

если вы действительно хотите, чтобы это было свойство, вы всегда можете установить pic._filename = filename и иметь свойство на DailyPic, которое возвращает self._filename().это то, что вы делали для начала.

...