Почему здесь не работает ключевое слово?

Я знаю, что is используется для сравнения, если два объекта одинаковы, но == используется для равенства. По моему опыту is всегда работал с числами, потому что Python повторно использует числа. Например:

>>>a = 3
>>>a is 3
True

И я привык использовать is всякий раз, когда сравниваю что-то с числом. Но is не работал для этой программы ниже:

from collections import namedtuple
# Code taken directly from [Udacity site][1].
# make a basic Link class
Link = namedtuple('Link', ['id', 'submitter_id', 'submitted_time', 'votes',
                           'title', 'url'])

# list of Links to work with
links = [
    Link(0, 60398, 1334014208.0, 109,
         "C overtakes Java as the No. 1 programming language in the TIOBE index.",
         "http://pixelstech.net/article/index.php?id=1333969280"),
    Link(1, 60254, 1333962645.0, 891,
         "This explains why technical books are all ridiculously thick and overpriced",
         "http://prog21.dadgum.com/65.html"),
    Link(23, 62945, 1333894106.0, 351,
         "Learn Haskell Fast and Hard",
         "http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/"),
    Link(2, 6084, 1333996166.0, 81,
         "Announcing Yesod 1.0- a robust, developer friendly, high performance web framework for Haskell",
         "http://www.yesodweb.com/blog/2012/04/announcing-yesod-1-0"),
    Link(3, 30305, 1333968061.0, 270,
         "TIL about the Lisp Curse",
         "http://www.winestockwebdesign.com/Essays/Lisp_Curse.html"),
    Link(4, 59008, 1334016506.0, 19,
         "The Downfall of Imperative Programming. Functional Programming and the Multicore Revolution",
         "http://fpcomplete.com/the-downfall-of-imperative-programming/"),
    Link(5, 8712, 1333993676.0, 26,
         "Open Source - Twitter Stock Market Game - ",
         "http://www.twitstreet.com/"),
    Link(6, 48626, 1333975127.0, 63,
         "First look: Qt 5 makes JavaScript a first-class citizen for app development",
         "http://arstechnica.com/business/news/2012/04/an-in-depth-look-at-qt-5-making-javascript-a-first-class-citizen-for-native-cross-platform-developme.ars"),
    Link(7, 30172, 1334017294.0, 5,
         "Benchmark of Dictionary Structures", "http://lh3lh3.users.sourceforge.net/udb.shtml"),
    Link(8, 678, 1334014446.0, 7,
         "If It's Not on Prod, It Doesn't Count: The Value of Frequent Releases",
         "http://bits.shutterstock.com/?p=165"),
    Link(9, 29168, 1334006443.0, 18,
         "Language proposal: dave",
         "http://davelang.github.com/"),
    Link(17, 48626, 1334020271.0, 1,
         "LispNYC and EmacsNYC meetup Tuesday Night: Large Scale Development with Elisp ",
         "http://www.meetup.com/LispNYC/events/47373722/"),
    Link(101, 62443, 1334018620.0, 4,
         "research!rsc: Zip Files All The Way Down",
         "http://research.swtch.com/zip"),
    Link(12, 10262, 1334018169.0, 5,
         "The Tyranny of the Diff",
         "http://michaelfeathers.typepad.com/michael_feathers_blog/2012/04/the-tyranny-of-the-diff.html"),
    Link(13, 20831, 1333996529.0, 14,
         "Understanding NIO.2 File Channels in Java 7",
         "http://java.dzone.com/articles/understanding-nio2-file"),
    Link(15, 62443, 1333900877.0, 1244,
         "Why vector icons don't work",
         "http://www.pushing-pixels.org/2011/11/04/about-those-vector-icons.html"),
    Link(14, 30650, 1334013659.0, 3,
         "Python - Getting Data Into Graphite - Code Examples",
         "http://coreygoldberg.blogspot.com/2012/04/python-getting-data-into-graphite-code.html"),
    Link(16, 15330, 1333985877.0, 9,
         "Mozilla: The Web as the Platform and The Kilimanjaro Event",
         "https://groups.google.com/forum/?fromgroups#!topic/mozilla.dev.planning/Y9v46wFeejA"),
    Link(18, 62443, 1333939389.0, 104,
         "github is making me feel stupid(er)",
         "http://www.serpentine.com/blog/2012/04/08/github-is-making-me-feel-stupider/"),
    Link(19, 6937, 1333949857.0, 39,
         "BitC Retrospective: The Issues with Type Classes",
         "http://www.bitc-lang.org/pipermail/bitc-dev/2012-April/003315.html"),
    Link(20, 51067, 1333974585.0, 14,
         "Object Oriented C: Class-like Structures",
         "http://cecilsunkure.blogspot.com/2012/04/object-oriented-c-class-like-structures.html"),
    Link(10, 23944, 1333943632.0, 188,
         "The LOVE game framework version 0.8.0 has been released - with GLSL shader support!",
         "https://love2d.org/forums/viewtopic.php?f=3&t=8750"),
    Link(22, 39191, 1334005674.0, 11,
         "An open letter to language designers: Please kill your sacred cows. (megarant)",
         "http://joshondesign.com/2012/03/09/open-letter-language-designers"),
    Link(21, 3777, 1333996565.0, 2,
         "Developers guide to Garage48 hackatron",
         "http://martingryner.com/developers-guide-to-garage48-hackatron/"),
    Link(24, 48626, 1333934004.0, 17,
         "An R programmer looks at Julia",
         "http://www.r-bloggers.com/an-r-programmer-looks-at-julia/")]


# links is a list of Link objects. Links have a handful of properties. For
# example, a Link's number of votes can be accessed by link.votes if "link" is a
# Link.

# make the function query() return a list of Links submitted by user 62443, by
# submission time ascending

def query():
    print "hello"
    print [link for link in links if link.submitter_id == 62443] # is does not work
    return sorted([link for link in links if link.submitter_id == 62443],key = lambda x: x[2])
query()

Когда я использовал is внутри функции запроса, подобной этой [link for link in links if link.submitter_id is 62443], я получаю пустой список. Но если я использую ==, все работает нормально.

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

РЕДАКТИРОВАТЬ: да. Я допускаю, что этот вопрос повторяется и должен быть закрыт. Но он дублируется с первым сообщением, а не с второй. Я не знал этого вопроса до того, как опубликовал это.

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

Спасибо всем, избавилась от вредной привычки.


person Gnijuohz    schedule 19.12.2013    source источник
comment
Я привык использовать это всякий раз, когда сравниваю что-то с числом. Тогда вы должны ожидать, что ваш код загадочным образом сломается. Python никогда не гарантировал, что числа являются одиночными, а иногда и нет. Преодолейте это и используйте ==, как задумал Гвидо ;-)   -  person Tim Peters    schedule 19.12.2013
comment
stackoverflow.com/ вопросы / 2987958 /   -  person Buddhima Gamlath    schedule 19.12.2013
comment
Как будто перебегает дорогу, не глядя. Вы знаете, что это неправильно, но, похоже, раньше это работало, так что ...   -  person John La Rooy    schedule 19.12.2013
comment
@Gnijuohz: Попробуйте в своем примере с числом вроде 1023 вместо 3, и вы увидите False вместо True.   -  person Matthias    schedule 19.12.2013
comment
@TimPeters Я всегда использовал его для сравнения чисел вроде -1 или 0, которые используются в качестве возвращаемого значения для некоторых функций. Вот почему они всегда работали. Теперь я понимаю!   -  person Gnijuohz    schedule 19.12.2013


Ответы (6)


На ваш вопрос нет ответа, кроме подробностей реализации конкретной версии Python, которую вы используете. Ничего не определено относительно того, подразумевает ли a == b a is b, когда a и b являются числами. Часто это верно, особенно для «маленьких целых чисел», из-за того, что CPython хранит кеш маленьких целочисленных объектов и обычно (не всегда!) Возвращает тот же объект для данного небольшого целочисленного значения. Но в этом нет ничего определенного, гарантированного или даже одного и того же в разных выпусках.

Размышление об адресах памяти может быть в некоторой степени полезным, поскольку именно так id() реализовано в CPython. Но другие реализации используют другие реализации для id(). Например, мне сказали, что id() было большой проблемой для реализации в Jython (Python, реализованный на Java), поскольку Java может свободно перемещать объекты в памяти во время сборки мусора (CPython этого не делает: в CPython объект всегда изначально занимает память выделены для него, пока объект не превратится в мусор).

Единственное предназначенное - и поддерживаемое - использование для is - это проверка того, действительно ли два имени для объектов соответствуют одному и тому же объекту. Например, независимо от типа b, после

a = b

это должно быть так, что

a is b

это True. И это иногда полезно.

_sentinel = object() # create a unique object

def somefunc(optional=_sentinel):
    if optional is _sentinel:  # we know for sure nothing was passed
        ...

Другое основное использование - горстка объектов, гарантированно чтобы быть одиночными. None, True и False являются примерами этого, и действительно идиоматично писать:

if a is None:

вместо:

if a == None:

Первый способ является успешным тогда и только тогда, когда a фактически привязан к одноэлементному объекту None, но второй способ может быть успешным, если a имеет любой тип, такой, что a.__eq__(None) возвращает True.

Не используйте is для чисел. Это безумно ;-)

person Tim Peters    schedule 19.12.2013
comment
Отличный ответ. У меня создалось впечатление, что Python всегда будет повторно использовать объекты для чисел. Теперь я знаю, что это неправильно. - person Gnijuohz; 19.12.2013
comment
Что ж, это было бы очень дорого. Например, после a = 10**10000 и b=10**10000. После вычисления 10**10000 во второй раз Python должен будет перебрать все существующие числа, чтобы понять, что a уже имеет то же значение. Не при нашей жизни ;-) - person Tim Peters; 19.12.2013
comment
Я понимаю вашу точку зрения! Спасибо! - person Gnijuohz; 19.12.2013

Вы правы в том, что is проверяет идентичность, если две переменные являются одним и тем же объектом, и что == используется для проверки равенства, если объекты равны. (Какие равные средства решают участвующие классы).

И вы правы, что использование is для проверки равенства двух чисел часто работает, потому что Python повторно использует числа, поэтому часто, когда они равны, они также идентичны.

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

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

К тому же в Python 3 == 3.0, но 3 is not 3.0. Поэтому вам следует использовать == по этой причине.

person Lennart Regebro    schedule 19.12.2013
comment
Да, я должен использовать ==. Но я использовал это с небольшими числами, и они всегда работали. это стало привычкой. Спасибо! - person Gnijuohz; 19.12.2013

Этот вопрос состоит из двух частей

  1. is не проверяет равенство, он просто проверяет идентичность. Два объекта имеют одинаковую идентичность, если они являются одними и теми же объектами (с одинаковой идентичностью, т.е. id(a) == id(b))

    >>> a = 10
    >>> b = a
    >>> id(a), id(b)
    (30388628, 30388628)
    
  2. Реализованный CPython (может быть для других) определенный диапазон чисел целых чисел в пределах определенного предела, они кэшируются, поэтому, хотя они и являются разными объектами, но имеют одинаковую идентичность

Таким образом

>>> a is 200
True
>>> a = 2000
>>> a is 2000
False
person Abhijit    schedule 19.12.2013
comment
Короче говоря, для больших чисел is не сработает. - person Gnijuohz; 19.12.2013
comment
@Gnijuohz Короче говоря, причина, по которой он иногда работает, - это внутренняя деталь реализации CPython. Ожидается, что это не сработает, и вы не должны полагаться на его работу. - person Lennart Regebro; 19.12.2013
comment
Итак, хотя это разные объекты, но идентичность у них одна - Неправильно. Это тот же объект. В противном случае у них были бы разные личности. - person Lennart Regebro; 19.12.2013
comment
@LennartRegebro хорошо, для небольших чисел CPython повторно использовал один и тот же объект, но для больших чисел это не так. Это утверждение правильно? - person Gnijuohz; 19.12.2013
comment
@Gnijuohz Да. Хотя я думаю, что могут быть случаи, когда они не совпадают, но я не помню, когда это было. Это не имеет значения, поскольку это деталь реализации, о которой вам не нужно заботиться. - person Lennart Regebro; 19.12.2013

Это потому, что is сравнивает идентичности:

>>> a = 10
>>> id(a)
30967348
>>> id(10)
30967348
>>> a is 10
True
>>> a += 1
>>> a
11
>>> id(a)
30967336
>>> id(11)
30967336
>>> a is 11
True
>>> a = 106657.334
>>> id(a)
44817088
>>> id(106657.334)
31000752
>>> a is 106657.334
False
>>> a == 106657.334
True
person Games Brainiac    schedule 19.12.2013

is используется для сравнения идентичности.

In [26]: a = 3

In [27]: a is 3
Out[27]: True

In [28]: id(a)
Out[28]: 140479182211448

In [29]: id(3)
Out[29]: 140479182211448

Распространение того же на приведенный выше пример.

In [32]: for link in links:
    print id(link.submitter_id), id(62443), id(link.submitter_id) == id(62443), link.submitter_id

....:

140479184066728 140479184065152 False 60398
140479184066872 140479184065152 False 60254
140479184065688 140479184065152 False 62945
140479184064984 140479184065152 False 6084
140479184064648 140479184065152 False 30305
140479184063416 140479184065152 False 59008
140479184063608 140479184065152 False 8712
140479184063752 140479184065152 False 48626
140479184064352 140479184065152 False 30172
140479185936456 140479184065152 False 678
140479185966096 140479184065152 False 29168
140479184063752 140479184065152 False 48626
140479185936888 140479184065152 False 62443
140479184052336 140479184065152 False 10262
140479184061232 140479184065152 False 20831
140479185936888 140479184065152 False 62443
140479184057712 140479184065152 False 30650
140479185957880 140479184065152 False 15330
140479185936888 140479184065152 False 62443
140479185959760 140479184065152 False 6937
140479184061528 140479184065152 False 51067
140479184058728 140479184065152 False 23944
140479185944264 140479184065152 False 39191
140479184062568 140479184065152 False 3777
140479184063752 140479184065152 False 48626

Используйте is при проверке личности.

Ссылка: Сравнение строк в Python: is vs. ==

person Kracekumar    schedule 19.12.2013

Оператор is используется для сравнения идентичностей двух объектов Итак, в основном вы сравниваете, имеют ли объекты одинаковую идентичность, а не равны ли они

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

>>>print [(id(link),id(62443)) for link in links if link.submitter_id == 62443]
[(28741560, 21284824), (28860576, 21284824), (28860744, 21284824)]

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


Примечание. После сборки мусора его идентификатор можно использовать повторно. Поэтому использование оператора is на самом деле несколько не рекомендуется

person K DawG    schedule 19.12.2013
comment
почему голос против? Кстати, исправлено, если это каким-либо образом вызывает путаницу @ user2864740 - person K DawG; 19.12.2013
comment
@KDawG Это действительно плохой способ делать что-то, дружище. - person Games Brainiac; 19.12.2013
comment
OP начинает свой вопрос с того, что я знаю, что он используется для сравнения, если два объекта одинаковы, но == для равенства. Значит, он это уже знает. Просто говорю'. - person Lennart Regebro; 19.12.2013
comment
Ваш пример, кажется, доказывает обратное тому, что вы объясняете выше. Короткие строки интернируются (если они соответствуют определенным правилам). - person Tim Pietzcker; 19.12.2013
comment
Примечание. После сборки мусора его идентификатор можно использовать повторно. Так что использование оператора is на самом деле несколько обескураживает - Эх. WAT? Кто тебе это сказал? Это бессмысленно. Смейтесь над ними. - person Lennart Regebro; 19.12.2013
comment
@LennartRegebro ну их идентификаторы действительно доступны для повторного использования, так что это может привести к неожиданным результатам, верно? - person K DawG; 19.12.2013
comment
@KDawG: Нет, может и нет. Объект собирает мусор только тогда, когда у вас больше нет на него ссылок. - person Lennart Regebro; 19.12.2013