Re: None in string => TypeError?

2014-06-09 Thread Chris Angelico
On Tue, Jun 10, 2014 at 3:58 AM, Ian Kelly  wrote:
> On Mon, Jun 9, 2014 at 11:40 AM, Chris Angelico  wrote:
>> Also, this is the first time I've seen None as a constant other than
>> the first. Usually co_consts[0] is None, but this time co_consts[4] is
>> None.
>
> Functions always seem to have None as the first constant, but modules
> and classes are other examples that don't.
>
 co = compile("class MyClass: pass", '', 'exec')
 co.co_consts
> (, 'MyClass', None)
 co.co_consts[0].co_consts
> ('MyClass', None)

Huh. Learn something every day!

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Ian Kelly
On Mon, Jun 9, 2014 at 11:40 AM, Chris Angelico  wrote:
> Also, this is the first time I've seen None as a constant other than
> the first. Usually co_consts[0] is None, but this time co_consts[4] is
> None.

Functions always seem to have None as the first constant, but modules
and classes are other examples that don't.

>>> co = compile("class MyClass: pass", '', 'exec')
>>> co.co_consts
(, 'MyClass', None)
>>> co.co_consts[0].co_consts
('MyClass', None)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Chris Angelico
On Tue, Jun 10, 2014 at 3:22 AM, Ian Kelly  wrote:
> On Mon, Jun 9, 2014 at 10:59 AM, Chris Angelico  wrote:
>> On Tue, Jun 10, 2014 at 2:53 AM, Roy Smith  wrote:
>>> In retrospect, I suspect:
>>>
>>>   hourly_data = [(t if status in set('CSRP') else None) for (t,
>>> status) in hours]
>>>
>>> is a little cleaner.
>>
>> I'd go with this. It's clearer that a status of 'SR' should result in
>> False, not True. (Presumably that can never happen, but it's easier to
>> read.) I'd be inclined to use set literal syntax, even though it's a
>> bit longer - again to make it clear that these are four separate
>> strings that you're checking against.
>
> Depending on how much work this has to do, I might also consider
> moving the set construction outside the list comprehension since it
> doesn't need to be repeated on every iteration.

Set literal notation will accomplish that, too, for what it's worth.

>>> def x():
hourly_data = [(t if status in {'C','S','R','P'} else None) for (t,
status) in hours]

>>> dis.dis(x)
  2   0 LOAD_CONST   1 ( at
0x012BE660, file "", line 2>)
  3 LOAD_CONST   2 ('x..')
  6 MAKE_FUNCTION0
  9 LOAD_GLOBAL  0 (hours)
 12 GET_ITER
 13 CALL_FUNCTION1 (1 positional, 0 keyword pair)
 16 STORE_FAST   0 (hourly_data)
 19 LOAD_CONST   0 (None)
 22 RETURN_VALUE
>>> dis.dis(x.__code__.co_consts[1])
  2   0 BUILD_LIST   0
  3 LOAD_FAST0 (.0)
>>6 FOR_ITER36 (to 45)
  9 UNPACK_SEQUENCE  2
 12 STORE_FAST   1 (t)
 15 STORE_FAST   2 (status)
 18 LOAD_FAST2 (status)
 21 LOAD_CONST   5 (frozenset({'R', 'S', 'C', 'P'}))
 24 COMPARE_OP   6 (in)
 27 POP_JUMP_IF_FALSE   36
 30 LOAD_FAST1 (t)
 33 JUMP_FORWARD 3 (to 39)
>>   36 LOAD_CONST   4 (None)
>>   39 LIST_APPEND  2
 42 JUMP_ABSOLUTE6
>>   45 RETURN_VALUE
>>> isinstance(x.__code__.co_consts[1].co_consts[5],set)
False

Interestingly, the literal appears to be a frozenset rather than a
regular set. The compiler must have figured out that it can never be
changed, and optimized.

Also, this is the first time I've seen None as a constant other than
the first. Usually co_consts[0] is None, but this time co_consts[4] is
None.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Ian Kelly
On Mon, Jun 9, 2014 at 10:59 AM, Chris Angelico  wrote:
> On Tue, Jun 10, 2014 at 2:53 AM, Roy Smith  wrote:
>> In retrospect, I suspect:
>>
>>   hourly_data = [(t if status in set('CSRP') else None) for (t,
>> status) in hours]
>>
>> is a little cleaner.
>
> I'd go with this. It's clearer that a status of 'SR' should result in
> False, not True. (Presumably that can never happen, but it's easier to
> read.) I'd be inclined to use set literal syntax, even though it's a
> bit longer - again to make it clear that these are four separate
> strings that you're checking against.

Depending on how much work this has to do, I might also consider
moving the set construction outside the list comprehension since it
doesn't need to be repeated on every iteration.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Chris Angelico
On Tue, Jun 10, 2014 at 2:53 AM, Roy Smith  wrote:
> In retrospect, I suspect:
>
>   hourly_data = [(t if status in set('CSRP') else None) for (t,
> status) in hours]
>
> is a little cleaner.

I'd go with this. It's clearer that a status of 'SR' should result in
False, not True. (Presumably that can never happen, but it's easier to
read.) I'd be inclined to use set literal syntax, even though it's a
bit longer - again to make it clear that these are four separate
strings that you're checking against.

Alternatively, you could go "if status or '0' in 'CSRP", which would
work, but be quite cryptic. (It would also mean that '' is not deemed
to be in the string, same as the set() transformation does.)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Roy Smith
On Jun 9, 2014, at 11:57 AM, Paul Sokolovsky wrote:

> This is very Pythonic, Python is strictly typed language. There's no
> way None could possibly be "inside" a string, so if you're trying to
> look for it there, you're doing something wrong, and told so.

Well, the code we've got is:

   hourly_data = [(t if status in 'CSRP' else None) for (t, status) in 
hours]

where status can be None.  I don't think I'm doing anything wrong.  I wrote 
exactly what I mean :-)  We've changed it to:

  hourly_data = [(t if (status and status in 'CSRP') else None) for (t, 
status) in hours]

but that's pretty ugly.  In retrospect, I suspect:

  hourly_data = [(t if status in set('CSRP') else None) for (t, status) 
in hours]

is a little cleaner.


---
Roy Smith
r...@panix.com

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Chris Angelico
On Tue, Jun 10, 2014 at 2:14 AM, Steven D'Aprano
 wrote:
>> This is very Pythonic, Python is strictly typed language. There's no way
>> None could possibly be "inside" a string,
>
> Then `None in some_string` could immediately return False, instead of
> raising an exception.

Note, by the way, that CPython does have some optimizations that
immediately return False. If you ask if a 16-bit string is in an 8-bit
string, eg "\u1234" in "asdf", it knows instantly that it cannot
possibly be, and it just returns false. The "None in string" check is
different, and deliberately so.

I do prefer the thrown error. Some things make absolutely no sense,
and even if it's technically valid to say "No, the integer 61 is not
in the string 'asdf'", it's likely to be helpful to someone who thinks
that characters and integers are equivalent. You'll get an exception
immediately, instead of trying to figure out why it's returning False.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Steven D'Aprano
On Mon, 09 Jun 2014 18:57:28 +0300, Paul Sokolovsky wrote:

> Hello,
> 
> On Mon, 9 Jun 2014 08:34:42 -0700 (PDT) Roy Smith  wrote:
> 
>> We noticed recently that:
>> 
>> >>> None in 'foo'
>> 
>> raises (at least in Python 2.7)
>> 
>> TypeError: 'in ' requires string as left operand, not NoneType
>> 
>> This is surprising.  The description of the 'in' operatator is, 'True
>> if an item of s is equal to x, else False'.  From that, I would 
assume
>> it behaves as if it were written:
>> 
>> for item in iterable:
>> if item == x:
>> return True
>> else:
>> return False
>> 
>> why the extra type check for str.__contains__()?  That seems very
>> unpythonic.  Duck typing, and all that. --
> 
> This is very Pythonic, Python is strictly typed language. There's no way
> None could possibly be "inside" a string, 

Then `None in some_string` could immediately return False, instead of 
raising an exception.


> so if you're trying to look
> for it there, you're doing something wrong, and told so.

This, I think, is the important factor. `x in somestring` is almost 
always an error if x is not a string. If you want to accept None as well:

x is not None and x in somestring 

does the job nicely.


-- 
Steven D'Aprano
http://import-that.dreamwidth.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Shiyao Ma
2014-06-09 23:34 GMT+08:00 Roy Smith :

> We noticed recently that:
>
> >>> None in 'foo'
>
> raises (at least in Python 2.7)
>
> TypeError: 'in ' requires string as left operand, not NoneType
>
> This is surprising.  The description of the 'in' operatator is, 'True if
> an item of s is equal to x, else False '.  From that, I would assume it
> behaves as if it were written:
>
> for item in iterable:
> if item == x:
> return True
> else:
> return False
>
> why the extra type check for str.__contains__()?  That seems very
> unpythonic.  Duck typing, and all that.
>

It's a little bit inconsistent.  But it's clearly documented here:
https://docs.python.org/3/reference/expressions.html#in

Which, according to its own logic, the string is not  a *container* type.
It's just some chars, and that totally makes sense for to restrict the type
of x in "str" to be convertible to type str. On the other hand, containers
like list, and tuple, they are heterogeneous by default in Python, so a
item by item comparison is needed.



-- 

吾輩は猫である。ホームーページはhttp://introo.me。
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Steven D'Aprano
On Mon, 09 Jun 2014 08:34:42 -0700, Roy Smith wrote:

> We noticed recently that:
> 
 None in 'foo'
> 
> raises (at least in Python 2.7)

That goes back to at least Python 1.5, when member tests only accepted a 
single character, not a substring:


>>> None in "abc"
Traceback (innermost last):
  File "", line 1, in ?
TypeError: string member test needs char left operand


It's a matter of taste whether predicate functions should always return a 
bool, or sometimes raise an exception. Would you be surprised that this 
raises TypeError?

"my string".startswith(None)


A predicate function could swallow any exception, e.g. be the logical 
equivalent of:

try:
return True if the condition holds, else return False
except:
return False  # or True as needed


but that is, I think, an anti-pattern, as it tends to hide errors rather 
than be useful. Most of the time, doing `[] in "xyz"` is an error, so 
returning False is not a useful thing to do.

I think that Python has been moving away from the "swallow exceptions" 
model in favour of letting errors propagate. E.g. hasattr used to swallow 
a lot more exceptions than it does now, and order comparisons (less than, 
greater than etc.) of dissimilar types used to return a version-dependent 
arbitrary but consistent result (e.g. all ints compared less than all 
strings), but in Python 3 that is now an error.



-- 
Steven D'Aprano
http://import-that.dreamwidth.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread MRAB

On 2014-06-09 16:34, Roy Smith wrote:

We noticed recently that:


None in 'foo'


raises (at least in Python 2.7)

TypeError: 'in ' requires string as left operand, not NoneType

This is surprising.  The description of the 'in' operatator is, 'True if an 
item of s is equal to x, else False '.  From that, I would assume it behaves as 
if it were written:

for item in iterable:
 if item == x:
 return True
else:
 return False

why the extra type check for str.__contains__()?  That seems very unpythonic.  
Duck typing, and all that.


When working with strings, it's not entirely the same. For example:

>>> 'oo' in 'foo'
True

If you iterated over the string, it would return False.

--
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Paul Sokolovsky
Hello,

On Mon, 9 Jun 2014 08:34:42 -0700 (PDT)
Roy Smith  wrote:

> We noticed recently that:
> 
> >>> None in 'foo'
> 
> raises (at least in Python 2.7)
> 
> TypeError: 'in ' requires string as left operand, not NoneType
> 
> This is surprising.  The description of the 'in' operatator is, 'True
> if an item of s is equal to x, else False '.  From that, I
> would assume it behaves as if it were written:
> 
> for item in iterable:
> if item == x:
> return True
> else:
> return False
> 
> why the extra type check for str.__contains__()?  That seems very
> unpythonic.  Duck typing, and all that. -- 

This is very Pythonic, Python is strictly typed language. There's no
way None could possibly be "inside" a string, so if you're trying to
look for it there, you're doing something wrong, and told so.

Also, it's not "extra check", it's "extra checks less", just consider
that "in" operator just checks types of its arguments for sanity once
at the start, and then just looks for a substring within string. You
suggest that it should check for each element type in a loop, which is
great waste, as once again, nothing but a string can be inside another
string.


-- 
Best regards,
 Paul  mailto:pmis...@gmail.com
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Ian Kelly
On Mon, Jun 9, 2014 at 9:34 AM, Roy Smith  wrote:
> We noticed recently that:
>
 None in 'foo'
>
> raises (at least in Python 2.7)
>
> TypeError: 'in ' requires string as left operand, not NoneType
>
> This is surprising.  The description of the 'in' operatator is, 'True if an 
> item of s is equal to x, else False '.  From that, I would assume it behaves 
> as if it were written:
>
> for item in iterable:
> if item == x:
> return True
> else:
> return False
>
> why the extra type check for str.__contains__()?  That seems very unpythonic. 
>  Duck typing, and all that.

I guess for the same reason that you get a TypeError if you test
whether the number 4 is in a string: it can't ever be, so it's a
nonsensical comparison.  It could return False, but the comparison is
more likely to be symptomatic of a bug in the code than intentional,
so it makes some noise instead.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: None in string => TypeError?

2014-06-09 Thread Ryan Hiebert
On Mon, Jun 9, 2014 at 10:34 AM, Roy Smith  wrote:

> We noticed recently that:
>
> >>> None in 'foo'
>
> raises (at least in Python 2.7)
>
> TypeError: 'in ' requires string as left operand, not NoneType
>
> This is surprising.
>
> It's the same in 3.4, and I agree that it's surprising, at least to me
​. I don't know the story or implementation behind it, so I'll leave that
to others.​
-- 
https://mail.python.org/mailman/listinfo/python-list