Уведомления

Группа в Telegram: @pythonsu

#1 Май 26, 2014 16:13:00

WoMax
Зарегистрирован: 2014-05-26
Сообщения: 124
Репутация: +  9  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

Привет,

дочитываю книгу М. Лутца “Изучаем Python” и пришла в голову идея создать декоратор класса, который подсчитывает кол-во созданных экземпляров.

Реализовать задачу полностью не удалось, вот что получилось:

def count(aClass):
	aClass.numInstances = 0
	class Wrapper(aClass):
		def __init__(self, *args, **kargs):
			aClass.numInstances += 1
			aClass.__init__(self, *args, **kargs)
	return Wrapper
if __name__ == '__main__':
	@count
	class Spam():
		def __init__(self):
			print('in Super.method')
		def printerS(self):
			print('blablabla')
	@count
	class Sub(Spam): pass
	@count
	class Other(Spam):
		def printer(self):
			print('lalala')
	
	x = Spam()
	y1, y2 = Sub(), Sub()
	z1, z2, z3 = Other(), Other(), Other()
	print(x.numInstances, y1.numInstances, z1.numInstances)
	print(Spam.numInstances, Sub.numInstances, Other.numInstances)

Output дает:
in Super.method
in Super.method
in Super.method
in Super.method
in Super.method
in Super.method
6 2 3
6 2 3

Счетчик класса Spam подсчитывает не только экземпляры класса Spam, но и экземпляры классов, которые наследут класс Spam.

Как можно исправить код, что бы счетчик считал корректно экземпляры, то есть что бы код проверки выводил в конце “1 2 3” вместо “6 2 3”?

Отредактировано WoMax (Май 27, 2014 14:46:22)

Офлайн

#2 Май 26, 2014 16:51:59

MindHatter
Зарегистрирован: 2014-05-09
Сообщения: 20
Репутация: +  3  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

Удали строчку

aClass.__init__(self, *args, **kargs)

в классе Wrapper

Отредактировано MindHatter (Май 26, 2014 17:17:38)

Офлайн

#3 Май 26, 2014 17:26:01

WoMax
Зарегистрирован: 2014-05-26
Сообщения: 124
Репутация: +  9  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

Уже пробовал)

Тогда подклассы Sub, Other не унаследует __init__ от Spam и не будет выводится строка “in Super.method” либо другие аргументы со значениями по умолчанию если таковые будут в __init__ суперклассa Spam. :-/

Отредактировано WoMax (Май 26, 2014 17:28:28)

Офлайн

#4 Май 26, 2014 19:30:39

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

from functools import wraps
def instance_counter(cls):
    @wraps(cls)
    def wrapper(*args, **kwargs):
        wrapper.counter += 1
        return cls(*args, **kwargs)
    wrapper.counter = 0
    return wrapper
@instance_counter
class Foo(object):
    def __init__(self):
        print("Foo init")
print(Foo.counter)
foo = Foo()
foo1 = Foo()
print(Foo.counter)



Офлайн

#5 Май 26, 2014 23:53:45

WoMax
Зарегистрирован: 2014-05-26
Сообщения: 124
Репутация: +  9  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

Спасибо, прочитал что такое “wraps”)

Однако с моим проверочным кодом ругается(((

from functools import wraps
def instance_counter(cls):
    @wraps(cls)
    def wrapper(*args, **kwargs):
        wrapper.counter += 1
        return cls(*args, **kwargs)
    wrapper.counter = 0
    return wrapper
if __name__ == '__main__': # проверочный код
	@instance_counter
	class Spam():
		def __init__(self):
			print('in Super.method')
		def printerS(self):
			print('blablabla')
	@instance_counter
	class Sub(Spam): pass
	@instance_counter
	class Other(Spam):
		def printer(self):
			print('lalala')
	
	x = Spam()
	y1, y2 = Sub(), Sub()
	z1, z2, z3 = Other(), Other(), Other()
	print(Spam.counter , Sub.counter , Other.counter)
	z3.printer()
	z3.printerS()

Output:
C:\Users\Максим>C:\Python33\Modules\countEX3.py
Traceback (most recent call last):
File "C:\Python33\Modules\countEX3.py", line 19 in <module>
class Sub(Spam): pass
TypeError: function() argument 1 must be code not str

Отредактировано WoMax (Май 26, 2014 23:54:24)

Офлайн

#6 Май 27, 2014 00:04:18

WoMax
Зарегистрирован: 2014-05-26
Сообщения: 124
Репутация: +  9  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

Так понимаю, декоратор instance_counter возвращает обернутую функцию вместо обернутого класса, поэтому интерпретатор ругается.

Отредактировано WoMax (Май 27, 2014 14:45:08)

Офлайн

#7 Май 27, 2014 11:19:16

mgk
Зарегистрирован: 2014-05-27
Сообщения: 9
Репутация: +  1  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

def count(aClass):
    aClass.numInstances = 0
    class Wrapper(aClass):
        def __init__(self, *args, **kargs):
            if self.__class__ == Wrapper:
                aClass.numInstances += 1
            aClass.__init__(self, *args, **kargs)
    return Wrapper

Офлайн

#8 Май 27, 2014 11:20:44

mgk
Зарегистрирован: 2014-05-27
Сообщения: 9
Репутация: +  1  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

И забудь в python про табуляции. Замени все табы на четыре пробела.

Офлайн

#9 Май 27, 2014 14:42:49

WoMax
Зарегистрирован: 2014-05-26
Сообщения: 124
Репутация: +  9  -
Профиль   Отправить e-mail  

Декоратор класса для подсчета экземпляров

Найс! Как раз тоже думал, что необходима проверка if, но никак не мог сообразить как именно прописать условие.
Спасибо)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version