объект Python бассейн с метаклассы


class Pool(type):
    pool = dict()
    def __new__(clas, *a, **k):
        def __del__(self):
            Pool.pool[self.__class__] = Pool.pool.get(self.__class__, []) + [self]
        a[-1]['__del__'] = __del__
        return type.__new__(clas, *a, **k)

    def __call__(clas, *a, **k):
        if Pool.pool.get(clas):
            print('Pool.pool is not empty: return an already allocated instance')
            r = Pool.pool[clas][0]
            Pool.pool[clas] = Pool.pool[clas][1:]
            return r
        else:
            print('Pool.pool is empty, allocate new instance')
            return type.__call__(clas, *a, **k)

class Foo(metaclass=Pool):
    def __init__(self):
        print('Foo > .', self)
    def foo(self):
        print('Foo > foo:', self)

f1 = Foo()
f1.foo()

print('## now deleting f1')
del f1

print('## now create f2')
f2 = Foo()
f2.foo()

print('## now create f3')
f3 = Foo()
f3.foo()

что вы думаете об этот кусок кода?



1240
6
задан 3 марта 2011 в 02:03 Источник Поделиться
Комментарии
2 ответа

class Pool(type):

Класс defaultdict автоматически создаст моем списке, когда я получить доступ к нему

    pool = collection.defaultdict(list)

Руководство по стилю Python предлагает использовать class_ форме, а затем клас
Также не понятно, почему вы захватываете входящие аргументы как переменные.
Это метакласс он будет иметь стабильные параметры

    def __new__(class_, name, bases, classdict):
def __del__(self):

Поскольку сейчас бассейн автоматически создает список, мы можем только добавить к ней
Бассейн.бассейн[собственной личности.класс].добавить(самовыдвижение)

Избавившись от переменных аргументов и делает это гораздо яснее.

        classdict['__del__'] = __del__
return type.__new__(class_, name, bases, classdict)

args и kwargs часто используются в качестве имен для переменных параметров. Я рекомендую использовать их, чтобы сделать код понятнее

    def __call__(class_, *args, **kwargs):

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

        instances = Pool.pool[class_]
if instances:

Существует тонкая и опасная проблема здесь. Когда вы создаете новый экземпляр, вы проходите по вашим параметрам.
Однако, если экземпляр уже создан, ты вернешься, что не замечает того, что эти параметры не делают.
Это означает, что вы можете получить объект, который был создан с помощью различных параметров, то вы только что прошли.
Я не сделал ничего, чтобы это исправить здесь

            print('Pool.pool is not empty: return an already allocated instance')
return instances.pop()
else:
print('Pool.pool is empty, allocate new instance')
return type.__call__(class_, *args, **kwargs)

Ваш метод-это установка __дель__ метод на объекты, так что вы можете обнаружить, если они не используются, и поддержания их в свой список для следующего человека, который спросит за них. в __дель__ метод вызывается, когда объект должен быть удален. Предотвратить удаление хранить ссылку на объект в свой список. Это допускается, но в документации по языку Python указывает на то, что это не рекомендуется.

__дель__ имеет ряд подводных камней. Если исключение возникает во время работы в __дель__ метод будет проигнорирован. Кроме того, он будет стремиться вызвать объекты в циклах ссылки, чтобы не быть взыскана. Если ваш код когда-нибудь работать на языка Jython/установить IronPython, то вы не можете быть уверены в том, что __Дель__ будет своевременно. По этим причинам я вообще избегаю использования __дель__.

Используется метакласс поэтому тот факт, что данный объект объединили скрыто от пользователя. Я не думаю, что это хорошая идея. Я думаю, что это намного лучше explict о чем-то вроде компенсации. Вы также теряют гибкость делать это таким образом. Нельзя создавать несколько пулов и т. д.

Интерфейс, который я мог бы изготовить для этого будет:

pool = Pool(Foo, 1, 2, alpha = 5) # the pool gets the arguments that will be used to construct Foo
with pool.get() as f1:
# as long as I'm in the with block, I have f1, it'll be returned when I exit the block
f1.foo()
with pool.get() as f2:
f2.foo()
with pool.get() as f3:
f3.foo()

f4 = pool.get()
f4.foo()
pool.repool(f4)

3
ответ дан 4 марта 2011 в 03:03 Источник Поделиться

Имя ваши аргументы. Если вы знаете достаточно о том, что вы прошли, чтобы принять пункт 1 из списка позиционный аргумент, вы знаете достаточно, чтобы дать ему имя.

2
ответ дан 3 марта 2011 в 06:03 Источник Поделиться