увеличивать значение вне функции для каждого использования в python

У меня есть функция, которую я хочу использовать несколько раз, при каждом использовании я хочу, чтобы переменная вне функции увеличивалась. По строчкам -

def funtion1(mylists,x):
    row=1
    for elm in mylists:
        ws.write(row,x,elm)
        row+=1
    x += 1

col=0
function1(mylist1,col)
function1(mylist2,col)
function1(mylist3,col)

так далее

Я думал, что col будет увеличиваться при каждом использовании, но он остается равным 0. Должен ли я возвращать значение из функции?


person PTrem2    schedule 06.12.2017    source источник
comment
При передаче неизменяемых типов данных, таких как целые числа, они следуют той же семантике, что и передача по значению. то есть x является локальным для функции, и его изменение не влияет на значение col. Если бы это был изменяемый объект, и вы изменили значение члена внутри функции, вы бы увидели ожидаемое поведение.   -  person    schedule 06.12.2017
comment
вы можете определить переменную как глобальную или вернуть значение   -  person Ora    schedule 06.12.2017
comment
хороший ресурс   -  person RSHAP    schedule 06.12.2017


Ответы (3)


Вы увеличиваете временную переменную x в пространстве имен функций, поэтому col не изменяется. Если вы хотите изменить col, вы можете:

  • используйте class с classmethod и атрибутом класса
  • используйте декоратор, как в ответе Пола Панцера
  • вернуть значение x и изменить его на col
  • используйте оператор global.

Если вы не знакомы с пространством имен, проверьте эту ссылку

Сначала используйте class с classmethod и классом атрибут:

class functions:
    col = 0

    @classmethod
    def function1(cls, mylists):
        row=1
        for elm in mylists:
            ws.write(row, cls.col,elm)
            row+=1
        cls.col += 1

functions.function1(mylist1)
functions.function1(mylist2)
functions.function1(mylist3)

Это был бы мой предпочтительный вариант, поскольку пространства имен не загрязняются, а код чище, чем при возврате значения.

Теперь возвращаем значение:

def funtion1(mylists,x):
    row=1
    for elm in whichlist:
        ws.write(row,x,elm)
        row=row+1
    return x + 1

col = 0
col = function1(mylist1,col)
col = function1(mylist2,col)
col = function1(mylist3,col)

Или с global:

def function1(mylists):
    global col
    row=1
    for elm in mylists:
        ws.write(row,col,elm)
        row+=1
    col += 1

col=0
function1(mylist1)
function1(mylist2)
function1(mylist3)
person Jacques Gaudin    schedule 06.12.2017
comment
Хороший подход, но вы также можете вернуть x + 1 вместо x+=1 return x в две строки. - person Shailyn Ortiz; 06.12.2017
comment
@ShailynOrtiz Спасибо, изменено соответствующим образом. - person Jacques Gaudin; 06.12.2017
comment
спасибо, клянусь, я пробовал это .. Я думал, что это не останется локальной переменной, если вы используете переменную вне функции - person PTrem2; 06.12.2017
comment
@ PTerm2 Я добавил еще одну опцию с помощью метода класса. Я думаю, что это лучший способ добиться того, чего вы хотите. - person Jacques Gaudin; 06.12.2017

Вы можете создать атрибут функции для хранения счетчика. Вот декоратор, который делает это:

import functools as ft

def I_can_count(f):
    @ft.wraps(f)
    def wrapper(*args, **kwds):
        wrapper.times_called += 1
        return f(*args, **kwds)
    wrapper.times_called = 0
    return wrapper

@I_can_count
def f(x):
    print x

print(f.times_called)
f(100)
print(f.times_called)
f(100)
print(f.times_called)

# 0
# 100
# 1
# 100
# 2

Обратите внимание, что у декоратора здесь двоякая цель: (1) он добавляет удобства; но что более важно (2) он защищает пространство имен, в котором находится функция или, скорее, ее оболочка. Без этого может произойти следующая авария:

def f(x)
    f.times_called += 1
    print(x)
f.times_called = 0

f(100)
# 100
f.times_called
# 1
g = f
del f
g(100)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
#   File "<stdin>", line 2, in f
# NameError: name 'f' is not defined
person Paul Panzer    schedule 06.12.2017
comment
Мне нравится это решение. Из любопытства, какое преимущество он имеет перед инкапсуляцией классов? - person Jacques Gaudin; 06.12.2017
comment
@JacquesGaudin Я бы не стал настаивать на том, что это лучше. Это немного короче; Я бы предположил, что немного легче (могу ошибаться). OTOH подход класса имеет тенденцию быть немного более читабельным, особенно когда есть дополнительные параметры (например, начальное значение для счетчика). Суть декораторов, конечно же, в том, что их можно использовать повторно — просто добавьте одну строку перед определением любой функции, и ваша функция получит новые возможности. В вашем решении класса вы должны повторно ввести приращение для каждой новой функции или, если подкласс, по крайней мере, вызовите super. Наконец, декораторы можно создавать с помощью классов. - person Paul Panzer; 06.12.2017

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

как добавил наш друг Жак Годен: https://stackoverflow.com/a/47680265/7579116

другой, менее причудливый и не рекомендуемый, но то, о чем вы просили, это объявить x глобальным

x = 0
def funtion1(mylists,x):
    global x
    row=1
    for elm in whichlist:
        ws.write(row,x,elm)
        row=row+1
    x += 1

function1(mylist1,col)
function1(mylist2,col)
function1(mylist3,col)
person Shailyn Ortiz    schedule 06.12.2017