2013-12-19 3 views
5

Я знаю, что 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, но я также попробовал его на своей локальной машине. Тот же результат. Итак, я думаю, что в настоящее время цифры являются разными объектами, но почему? Есть ли необходимость в этом?

EDIT: Да. Я признаю, что этот вопрос повторяется и должен быть закрыт. Но он дублируется с first post не the second. Я не знал этого вопроса, прежде чем публиковать это.

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

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

+10

«Я привык использовать, когда я что-то сравниваю с числом». Тогда вы должны ожидать, что ваш код сломается таинственным образом. Python никогда не гарантировал, что числа являются одиночными, а иногда и нет. Подойдите к нему и используйте '==', как предполагал Гвидо ;-) –

+0

http://stackoverflow.com/questions/2987958/how-is-the-is-keyword-implemented-in-python – bgamlath

+4

Как бегать по дороге без Ищу. Вы знаете, что это неправильно, но, похоже, он работал в прошлом, поэтому ... –

ответ

9

Там нет ответа на ваш вопрос не копаясь в деталях реализации конкретной версии 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 в действительности, связанного с singleton None объект, но второй способ может быть успешным, если a имеет любой тип, такой, что a.__eq__(None) возвращает True.

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

+0

Отличный ответ. У меня создалось впечатление, что Python всегда будет использовать объекты для чисел. Теперь я знаю, что это неправильно. – Gnijuohz

+0

Ну, это было бы очень дорого. Например, после 'a = 10 ** 10000' и' b = 10 ** 10000'. После вычисления '10 ** 10000' во второй раз Python должен будет выполнить поиск по всем имеющимся числам, чтобы понять, что' a' уже имеет такое же значение. Не в нашей жизни ;-) –

+0

Я вижу вашу мысль! Благодаря! – Gnijuohz

0

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

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

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

Хотя только потому, что два объекта подобны там тождества не может быть такой же


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

+0

почему нисходящий? BTW исправлено, если оно вызывает путаницу любыми способами. @ User2864740 –

+0

@KDawG Это плохой способ сделать что-то сопряженное. –

+0

OP начинает свой вопрос с «Я знаю, что это используется для сравнения, если два объекта одинаковы, но == для равенства». Значит, он уже это знает. Просто говорю'. –

0

Это потому, что 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 
0

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

Продолжение на примере выше.

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 при проверке идентичности.

Ref: String comparison in Python: is vs. ==

5

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

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

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

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

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

+0

Да, я должен использовать '=='. Но я использовал с небольшими числами, и они всегда работали. это стало привычкой. Благодаря! – Gnijuohz

1

Есть две части к этому вопросу

  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 
+0

Так что вкратце для больших чисел 'is' не будет работать. – Gnijuohz

+1

@Gnijuohz Итак, причина, по которой она работает, иногда является внутренней детальностью реализации CPython. Он не должен работать, и вы не должны полагаться на его работу. –

+0

«Итак, хотя они разные объекты, но у них одинаковая идентичность» - «Неправильно». Это тот же объект. В противном случае они имели бы разные идентичности. –

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