2013-06-18 1 views
0

Я читал, что при написании функций полезно скопировать аргументы в другие переменные, потому что не всегда ясно, является ли переменная неизменной или нет. [Я не помню, где так не спрашивают]. Я писал функции в соответствии с этим.Путаница относительно изменяемых и неизменных типов данных в Python 2.7

Как я понимаю, создание новой переменной требует некоторых накладных расходов. Он может быть небольшим, но он есть. Так что должно быть сделано? Должен ли я создавать новые переменные или не содержать аргументы?

Я прочитал this и this. У меня есть путаница относительно того, почему float и int являются неизменными, если их можно легко изменить?

EDIT:

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

#When I copied arguments into another variable 
def zeros_in_fact(num): 
    '''Returns the number of zeros at the end of factorial of num''' 
    temp = num 
    if temp < 0: 
     return 0 
    fives = 0 
    while temp: 
     temp /= 5 
     fives += temp 
    return fives 

#When I did not copy arguments into another variable 
def zeros_in_fact(num): 
    '''Returns the number of zeros at the end of factorial of num''' 
    if num < 0: 
     return 0 
    fives = 0 
    while num: 
     num /= 5 
     fives += num 
    return fives 
+0

Вопросы, к которым вы связались (в частности, первый), показывают, что float и int не могут быть изменены. Кроме того, неверная копия аргументов функции не является хорошей практикой. Можете ли вы привести пример кода, который вы пишете? – BrenBarn

+0

Первый ответ на вопрос показывает, как легко изменить параметры int и float. Очевидно, они могут быть изменены иначе, какими будут их использование? –

+0

@Zel Неправильно. Каждое целое число является неизменным объектом. Каждый поплавок является неизменным объектом. Операции с неизменяемыми номерами возвращают новые неизменные числа. Присвоение неизменяемого числа изменяемой переменной (ссылка на объект) мутирует ссылку, чтобы указать на новый неизменяемый номер. И т. Д. Дело в том, что вы никогда не сможете редактировать номер и наблюдать его изменения с помощью двух переменных, указывающих на него, поскольку числа неизменяемы. – Patashu

ответ

2

Я думаю, что лучше всего держать это в простых вопросах.

Вторая ссылка в вашем вопросе - действительно хорошее объяснение; в целом:

Методы принимают параметры, которые, как указано в этом объяснении, передаются «по значению». Параметры в функциях принимают значение переданных переменных.

Для примитивных типов, таких как строки, ints и floats, значение переменной является указателем (стрелки на следующей диаграмме) на пространство в памяти, которое представляет число или строку.

code    | memory 
        | 
an_int = 1   | an_int ----> 1 
        |    ^ 
another_int = 1 | another_int/

Когда вы переназначаете метод, вы меняете место, где стрелка указывает.

an_int = 2   | an_int -------> 2 
        | another_int --> 1 

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

a_list = [1, 2, 3] |    1 2 3 
         | a_list ->|^|^|^| 
         |    0 2 3 
a_list[0] = 0   | a_list ->|^|^|^| 

Теперь вы можете изменить, где стрелки в списке, или объект, точка, но указатель в списке по-прежнему указывает на тот же список, как и прежде. (Вероятно, на диаграмме выше для обоих наборов стрелок должно быть только 2 и 3, но стрелки были бы трудными для рисования.)

Итак, как выглядит фактический код?

a = 5 
def not_change(a): 
    a = 6 
not_change(a) 
print(a) # a is still 5 outside the function 

b = [1, 2, 3] 
def change(b): 
    b[0] = 0 
print(b) # b is now [0, 2, 3] outside the function 

ли вы сделать копию списков и объектов вы дали (Интс и строки не имеет значения), и, таким образом, возвращают новые переменные или изменить те, передаваемые в зависимости от того, что функции, которые вам необходимо предоставить.

0

Если вы перекомпоновка имя затем Изменчивость объекта он содержит не имеет значения. Только если вы выполняете , мутируя операций, вы должны создать копию. (И если вы читаете между строк, это косвенно говорит: «Не мутируйте объекты, переданные вам».)

+0

Что именно означает мутация? Поскольку я понимаю, есть ли строка 'abc', то' abc [0] = 'a'' является мутирующей операцией для строки 'abc'. Я прав? Да, тогда вы можете добавить некоторые мутирующие операции для int и float? Будут ли битовые операторы рассматриваться как мутирующие операторы на int и float? –

+0

'str',' unicode', 'int',' float', 'complex',' tuple' и 'FrozenSet' не имеют мутирующих операций. –

+0

@Zel: Строки также неизменяемы.abc [0] = 'a' не работает. – rajpy

1

То, что вы делаете в своих примерах кода, не содержит заметных накладных расходов, но оно также не выполняет ничего, потому что оно не защитит вас от изменяемых/непреложных проблем.

Способ думать об этом заключается в том, что в Python есть два типа имен: имена и объекты. Когда вы делаете x = y, вы работаете на имя, прикрепляя это имя к объекту y. Когда вы делаете x += y или другие расширенные операторы присваивания, вы также связываете имя (в дополнение к выполнению операции, которую вы используете, + в этом случае). Все, что вы делаете, работает на объектах. Если объекты изменяемы, это может привести к изменению их состояния.

Интс и поплавки не могут быть изменены. Что вы можете сделать, это изменить то, что означает int или float, имя , которое называется. Если вы делаете

x = 3 
x = x + 4 

Вы не меняете инт. Вы меняете имя x, так что теперь присоединен к числу 7 вместо числа 3. С другой стороны, когда вы делаете это:

x = [] 
x.append(2) 

Вы изменяете список, а не просто указав имя в новый объект.

Разница может быть видна при наличии нескольких имен для одного и того же объекта.

>>> x = 2 
>>> y = x 
>>> x = x + 3 # changing the name 
>>> print x 
5 
>>> print y # y is not affected 
2 
>>> x = [] 
>>> y = x 
>>> x.append(2) # changing the object 
>>> print x 
[2] 
>>> print y # y is affected 
[2] 

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

Второй вопрос, на который вы ссылаетесь, дает больше информации о том, как это работает в контексте аргументов функции. Расширенные операторы присваивания (+=, *= и т. Д.) Немного сложнее, поскольку они работают с именами, но могут также мутировать объекты одновременно. Вы можете найти другие вопросы о StackOverflow о том, как это работает.

Смежные вопросы