Как реализовать простой счетчик без "global"?
Я новичок в питоне.
Везде написано, что использование глобальных переменных в функциях это плохой тон и лучше так код не писать.
Но как иначе реализовать такой функционал я не понимаю.
У меня есть переменная X и я хочу, чтобы каждый раз, когда происходил вызов определенной функции переменная X увеличивалась на единицу.
Для меня самым очевидным решением показалось такое:
count = 0
def counter():
global count
count += 1
def turn():
counter()
turn()
print(count)
Но так как везде пишут про то, что "global" это моветон, хочу понять, как по-другому это реализовать?
Ответы (4 шт):
Как вариант:
class MyClass(object):
count = 0
def counter(self):
self.count += 1
return self.count
myClass = MyClass()
print(myClass.counter())
print(myClass.counter())
print(myClass.counter())
Можно несколько "перевернуть" логику и засунуть переменную в атрибуты функции. Но это вариант не очень-то и лучше использования global.
def counter():
counter.count += 1
counter.count = 0
def turn():
counter()
turn()
print(counter.count)
Простой декоратор-счетчик:
def call_counter(func):
def wrapped(*args, **kwargs):
wrapped.count += 1
return func(*args, **kwargs)
wrapped.count = 0
return wrapped
Сложнее, но так правильнее работать с декораторами - использовать functools.wraps (причина ниже в PS. ):
import functools
def call_counter(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
wrapped.count += 1
return func(*args, **kwargs)
wrapped.count = 0
return wrapped
Использование:
@call_counter
def turn():
pass
turn()
print(turn.count)
# 1
for _ in range(10):
turn()
print(turn.count)
# 11
PS.
Причина в том, что декоратор, возвращая функцию не вернет ее __name__ и __doc__, что может вредить для скриптов, что на это заточены.
Пример:
def call_counter(func):
def wrapped(*args, **kwargs):
wrapped.count += 1
return func(*args, **kwargs)
wrapped.count = 0
return wrapped
def call_counter_v2(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
wrapped.count += 1
return func(*args, **kwargs)
wrapped.count = 0
return wrapped
@call_counter
def turn():
"""Это функция turn!"""
@call_counter_v2
def turn_v2():
"""Это функция turn_v2!"""
print(turn.__name__, turn.__doc__)
# wrapped None
print(turn_v2.__name__, turn_v2.__doc__)
# turn_v2 Это функция turn_v2!
вот этот код будет добавлять по 1, и всего 5 строчек кода:
b = 1
while True:
a = int(input('enter number:'))
p = a + b
print(p)