2013-12-21 1 views
0

т. Е. У нас есть глобальная декларация, но не локальная.Как сделать переменную (действительно) локальной процедурой или функцией

«Обычно» аргументы являются локальными, я думаю, или они, конечно, ведут себя так. Однако, если аргумент, скажем, применяется список и метод, который изменяет список, могут возникнуть некоторые неожиданные (для меня) результаты.

У меня есть 2 вопроса: что такое правильный способ гарантировать, что переменная действительно является локальной? я завелся, используя следующую команду, которая работает, но вряд ли это может быть правильный способ сделать это:

def AexclB(a,b): 
    z = a+[] # yuk 
    for k in range(0, len(b)): 
     try: z.remove(b[k]) 
     except: continue 
    return z 

ОТСУТСТВУЕТ + [], «а» в вызывающей рамки модифицируется, что не требуется , (Вопрос здесь используется метод списка,

Дополнительный вопрос не в том, почему там нет «местная» декларация?

Наконец, пытаясь прикрепить это вниз, я сделал различные функции мыши Mickey, которые все вели себя, как и ожидалось, кроме последнего:

def fun4(a): 
    z = a 
    z = z.append(["!!"]) 
    return z 

a = ["hello"] 
print "a=",a 
print "fun4(a)=",fun4(a) 
print "a=",a 

который произвел следующие действия на консоли:

a= ['hello'] 
fun4(a)= None 
a= ['hello', ['!!']] 
... 
>>> 

'None' ре sult не ожидалось (мной).

Python 2.7 btw в случае, что имеет значение.

PS: Я пробовал искать здесь и в другом месте, но не смог найти что-либо соответствующее точно - есть много о том, чтобы сделать переменные глобальными, к сожалению.

+2

'z.append ([ "!!"])' 'возвращает None', потому что это способ на месте, и вы переназначение, что 'z' и возвращает его. – Volatility

+1

Я думаю, что ваша корневая проблема заключается в том, что вы предполагаете, что переменные Python работают как, скажем, переменные C++. Они этого не делают. _Values_ имеют типы, ячейки памяти и т. Д. Переменные - это просто имена этих значений. Вы можете назначить много имен - локальных или глобальных или иначе - для значения, и значение не имеет значения. – abarnert

+1

Речь идет не о переменных. * Variables * 'a' и' b' являются локальными для вашей функции. То, что не является локальным, является * объектом *, переданным как аргумент 'a' вашей функции. Списки и другие объекты в Python не привязаны к одной переменной; так как многие переменные, как вы хотите, могут ссылаться на один и тот же объект. В отличие от, скажем, C++, Python не будет автоматически делать копию каждый раз, когда вы что-то пропускаете. – user2357112

ответ

0

Если вам нужно работать с списком или другим объектом в действительно локальном контексте, вам нужно явно сделать копию или ее глубокую копию.

from copy import copy 
def fn(x): 
    y = copy(x) 
+0

Является ли это «правильным» способом заставить локальная копия? A против [:] или + [] и т. Д. И т. Д.? Это кажется самым простым, кроме импорта. – RFlack

+0

Мне лично это нравится для ясности и того факта, что если тип x изменяется, скажем, из списка на другой объект, он по-прежнему работает, другие методы полагаются на вас, отслеживая, какой тип является входящим try 'y = x [ :] 'с' dict' или по типу, который вам нужен, как в 'y = list (x)' отбрасывает значения с помощью 'dict' как' x' –

4

Это не то, что z не является локальной переменной в функции. Скорее, когда у вас есть линия z = a, вы делаете z ссылаются на тот же список в памяти, что и a. Если вы хотите, чтобы z являлась копией a, вам необходимо написать z = a[:] или z = list(a).

Смотрите эту ссылку для некоторых иллюстраций и немного больше объяснений http://henry.precheur.org/python/copy_list

+0

Хороший ответ; это единственный, кто пытается устранить основную причину путаницы OP (и делает это, даже не пытаясь объяснить все, что означают переменные в Python, я не мог даже начать отвечать на этот вопрос без этого объяснения, но вы, надеюсь, потянули это от). – abarnert

1

Python не будет копировать объекты, если явно не попросите его. Целые числа и строки не изменяются, поэтому каждая операция над ними возвращает новый экземпляр типа. Списки, словари и, в основном, каждый другой объект в Python являются mutable, поэтому операции, подобные list.append, происходят на месте (и поэтому возвращают None).

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

z = a[:] 
1

Что вы теряете, что все присвоение переменной в питона по ссылке (или указателем, если вы хотите). Передача аргументов функции буквально присваивает значения от вызывающего к аргументам функции по ссылке.Если вы копаетесь в ссылке и меняете что-то внутри это, вызывающий увидит это изменение.

Если вы хотите, чтобы вызывающие абоненты не изменили свои значения, вы можете чаще пытаться использовать неизменяемые значения (tuple, frozenset, str, int, bool, NoneType) или не забудьте взять копии своих данных, прежде чем мутировать его на месте.

Таким образом, обзор вашей проблемы не касается. Мутируемость есть.

Это ясно сейчас?


До сих пор не уверен, Что самый «правильный» способ заставить копию, есть различные предложения здесь.

Он отличается по типу данных, но обычно <type>(obj) будет делать трюк. Например, list([1, 2]) и dict({1:2}) возвращают (неглубокие!) Копии своего аргумента.

Если, однако, у вас есть дерево изменяемых объектов, а также вы не знаете, априори, какой уровень дерева вы могли бы изменить, вам нужно copy модуль. Тем не менее, мне нужно было всего лишь несколько раз (за 8 лет работы на полный рабочий день), и большинство из них в конечном итоге вызывают ошибки. Если вам это нужно, это, по-моему, запах кода.

Сложность сохранения копий изменяемых объектов является причиной того, что по-прежнему существует тенденция использования неизменяемых объектов по умолчанию. На языке clojure все типы данных по умолчанию неизменяемы, а изменчивость рассматривается как особые случаи, которые должны быть сведены к минимуму.

+0

Clear-er. Его «наверняка ...» бит, который меня бросает ... Я взмахнул, почему, если я вообще не использовал z, но действовал непосредственно на «а», вызывающее «значение» менялось. Следовательно, уловка с «z». Тем не менее, не уверен, что «правильный» способ заставить копию, здесь есть различные предложения. – RFlack

1

Существует большой ответ, который будет охватывать большую часть вашего вопроса в here, который объясняет изменчивые и неизменные типы и то, как они хранятся в памяти и как они ссылаются. Первая часть ответа для вас. (Перед Как мы это обойти? заголовок)

В следующей строке

z = z.append(["!!"]) 

Списки являются изменяемыми объектами, поэтому при вызове append, он будет обновлять объект ссылки, он не создаст новый и вернуть его. Если метод или функция ничего не перенастраивают, значит, он возвращает None.

Выше ссылка также дает непреложный экзамен, чтобы вы могли видеть реальную разницу.

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

a = [1,2,3] 
b = a[:] 

Дополнительные опции вы можете проверить here