如何向Python3对象动态添加具体化属性

如何向Python3对象动态添加具体化属性,python,python-3.x,decorator,python-decorators,Python,Python 3.x,Decorator,Python Decorators,我正在尝试做一些高级巫术,但我不完全理解这个问题,这无疑是我解决这个问题有困难的原因 如果我做了一些超级黑客的事情,让孩子(DailyPic)知道它的父母(Site),那么我可以让一切都正常工作,但我不知道如何仅仅从Site动态地做到这一点 我正在尝试动态地向DailyPic添加奇妙的(稍加修改),但是让DailyPic实例在站点的实例上调用一个方法 有点老套,但很管用 class reify(): def __init__(self, wrapped, name=None):

我正在尝试做一些高级巫术,但我不完全理解这个问题,这无疑是我解决这个问题有困难的原因

如果我做了一些超级黑客的事情,让孩子(
DailyPic
)知道它的父母(
Site
),那么我可以让一切都正常工作,但我不知道如何仅仅从
Site
动态地做到这一点

我正在尝试动态地向
DailyPic
添加奇妙的(稍加修改),但是让
DailyPic
实例在
站点的实例上调用一个方法

有点老套,但很管用

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

如果一个高级巫师能插话,那就太棒了

除非您真的、真的需要将其作为属性,否则只需忽略具体化和属性,并在每个实例上设置一个函数,该函数在运行一次时会覆盖自身

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.\u filename=filename
,并在
DailyPic
上有一个返回
self.\u filename()
的属性。这基本上就是你一开始要做的。

你在这里通常想做什么?从网站下载图片?并用计数器命名它们?在您的目标示例中,不清楚
pic1
pic2
从何而来,因此很难说出您想要什么…是的,我删掉了很多额外的代码(比如Site.save确实需要一个url),但我试图完成的并不是重点。我想问的是如何使用适当的实例绑定动态添加
具体化
(可能适用于
属性
)。我认为这是相关的,这听起来很像XY问题,但很难说。我的意思是,访问
文件名
的顺序决定了文件名,这有点奇怪。是的,这是一个非常奇怪的顺序,这就是为什么我要做具体化的把戏