def mylen(x):
if isinstance(x,int) or isinstance(x,float): return 1
return len(x)
But, this shouldn't be necessary.
--
View this message in context: http://www.nabble.com/len%28%29-should-always-return-something-tp24639361p24639361.html
Sent from the Python - python-list mailing list archive at Nabble.com.
Can you show some example of where that is actually making a piece of
code more elegant?
Diez
The problem is that redefining len()/length/size that way would
violate several principles of Python's design (The "Zen" of Python -
http://www.python.org/dev/peps/pep-0020/).
Specifically:
- Explicit is better than implicit.
- Special cases aren't special enough to break the rules.
- Errors should never pass silently.
- In the face of ambiguity, refuse the temptation to guess.
If you'd explain the situation that prompts you to find this
redefinition necessary, I'm sure someone can suggest a better
approach.
Cheers,
Chris
--
http://blog.rebertia.com
> Some aspects of the Python design are remarkably clever, while others
> leave me perplexed. Here's an example of the latter: Why does len() give
> an error when applied to an int or float? len() should always return
> something; in particular, when applied to a scalar, it should return a
> value of 1. Of course, I can define my own function like this:
>
> def mylen(x):
> if isinstance(x,int) or isinstance(x,float): return 1
> return len(x)
>
> But, this shouldn't be necessary.
Python should not blur the distinction between vectors an scalars like that.
Instead of trying to be clever you should pass a vector with a single item
and send mylen() to /dev/null.
On a general note, I think one of Python's strengths is that it consistently
/avoids/ this kind of cleverness.
A prominent example is the handling of "1" + 1.
Peter
If len(7) returned a value of 1, then wouldn't one expect 7[0]
to be valid? It isn't, so you'd then have to redefine all
types so that they are sequences that can be indexed. Sounds
like a big mess to me...
[Are there types for which len() returns a value that can't be
indexed?]
--
Grant Edwards grante Yow! It's the RINSE CYCLE!!
at They've ALL IGNORED the
visi.com RINSE CYCLE!!
> On 2009-07-24, Dr. Phillip M. Feldman <pfel...@verizon.net> wrote:
>>
>> Some aspects of the Python design are remarkably clever, while
>> others leave me perplexed. Here's an example of the latter:
>> Why does len() give an error when applied to an int or float?
>> len() should always return something; in particular, when
>> applied to a scalar, it should return a value of 1.
>
> If len(7) returned a value of 1, then wouldn't one expect 7[0]
> to be valid? It isn't, so you'd then have to redefine all
> types so that they are sequences that can be indexed. Sounds
> like a big mess to me...
>
> [Are there types for which len() returns a value that can't be
> indexed?]
>
Dictionaries.
Which doesn't make your point less valid. In fact I'd go so
far as to argue that what len() gives you is the number of
items in a container, so len(7) should return 0.
--
Rhodri James *-* Wildebeest Herder to the Masses
Nah. 7 contains three bits, so len(7) should *clearly* return 3.
Mark
and len("7") must return 8, by the same token... but wait!
>>> len("7")
1
>>>
my python installation must me outdated ;-)
bye
But it contains a minimum of 32 bits! And why are you treating ones as
special over zeros? I thought the times of BitRacism were finally over...
Diez
>RJ> On Fri, 24 Jul 2009 14:57:02 +0100, Grant Edwards <invalid@invalid> wrote:
>>> On 2009-07-24, Dr. Phillip M. Feldman <pfel...@verizon.net> wrote:
>>>>
>>>> Some aspects of the Python design are remarkably clever, while
>>>> others leave me perplexed. Here's an example of the latter:
>>>> Why does len() give an error when applied to an int or float?
>>>> len() should always return something; in particular, when
>>>> applied to a scalar, it should return a value of 1.
>>>
>>> If len(7) returned a value of 1, then wouldn't one expect 7[0]
>>> to be valid? It isn't, so you'd then have to redefine all
>>> types so that they are sequences that can be indexed. Sounds
>>> like a big mess to me...
>>>
>>> [Are there types for which len() returns a value that can't be
>>> indexed?]
>>>
>RJ> Dictionaries.
>RJ> Which doesn't make your point less valid. In fact I'd go so
>RJ> far as to argue that what len() gives you is the number of
>RJ> items in a container, so len(7) should return 0.
But len(7) could as well be defined as 3, 1, 32, or 64 (depending on the
implementation). Therefore it doesn't make much sense.
--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: pi...@vanoostrum.org
Quite.
On Fri, Jul 24, 2009 at 8:58 AM, Phillip M. Feldman<pfel...@verizon.net> wrote:
> I've read the "Zen of Python", but most of these aphorisms are vague and
> could be understood differently by different readers. In particular, I
> don't understand the statement that "explicit is better than implicit".
> Some examples of this would be helpful.
>
> I've been converting Matlab codes to Python. In Matlab, a scalar is just a
> one-by-one matrix and has a length of 1. This convention seems no less
> arbitrary to me than Python's convention that the concept of length is not
> applicable to ints and floats. My workaround was to write the following
> function:
>
> def is_scalar(x):
> """Return True if x is an instance of int, float, or complex.
> Otherwise, return False. Note: If x is a length-1 list or array
> containing an int, float, or complex value, False is returned."""
> if isinstance(x,int) or isinstance(x,float) or isinstance(x,complex):
> return True
> return False
>
> The application is the following: In various types of scientific
> applications, one operates on a list of measurements. If there is only a
> single measurement, it is reasonable to allow the calling program to pass a
> scalar without wrapping it up into a list or array.
You could use Python's extended call syntax when defining your function:
def average(*args):
return sum(args) / len(args)
average(7) #==> 7
average(2,3,4,5,6) #==> 4
average(*[2,3,4,5,6]) #==> 4
average([2,3,4,5,6]) #==> error
> I've been converting Matlab codes to Python. In Matlab, a scalar is
> just a one-by-one matrix and has a length of 1. This convention seems
> no less arbitrary to me than Python's convention that the concept of
> length is not applicable to ints and floats.
Multiplication of a vector/matrix by a scalar always defined and
commutative. Multiplication of a vector/matrix by a 1x1 matrix is not
always even defined. So not having scalars in a matrix package strikes
me as a bit odd.
> My workaround was to write
> the following function:
>
> def is_scalar(x):
> """Return True if x is an instance of int, float, or complex.
> Otherwise, return False. Note: If x is a length-1 list or array
> containing an int, float, or complex value, False is returned."""
> if isinstance(x,int) or isinstance(x,float) or isinstance(x,complex):
Better: if isinstance(x, (int, float, complex)):
but you forgot decimals and fractions and any other possible number modules.
In 3.1,
>>> from numbers import Number
>>> from decimal import Decimal
>>> from fractions import Fraction
>>> for x in 1, 1.0, (1+0j), Decimal(1), Fraction(1,1):
isinstance(x, Number)
True
True
True
True
True
and the same for any other module that registers a class as a Number
> return True
> return False
>
> The application is the following: In various types of scientific
> applications, one operates on a list of measurements. If there is only
> a single measurement, it is reasonable to allow the calling program to
> pass a scalar without wrapping it up into a list or array.
If you want to do that, start with
def f(x):
try: len(x)
except TypeError: x = x,
or in 3.1 use Number test above.
Terry Jan Reedy
>> Nah. 7 contains three bits, so len(7) should *clearly* return 3.
>
> and len("7") must return 8, by the same token... but wait!
>
> >>> len("7")
> 1
> >>>
> >>>
> my python installation must me outdated ;-)
No no no, you're obviously using an awesome version of Python that can
compress single-character strings to a single bit!
--
Steven
> Better: if isinstance(x, (int, float, complex)):
I never noticed this before, but it seems odd that the second argument to
isinstance() should be a tuple. Using the normal arguments made about
tuples vs. lists, it seems like a list would be the right data structure
here. I suppose a set would be even more right, but (I'm pretty sure)
isinstance() predates sets.
I'm curious why a tuple was chosen.
Compressing strings to a single bit is easy. It's the uncompressing that's
tricky.
> On Thu, Jul 23, 2009 at 11:35 PM, Dr. Phillip M.
> Feldman<pfel...@verizon.net> wrote:
>>
>> Some aspects of the Python design are remarkably clever, while others
>> leave me perplexed. Here's an example of the latter: Why does len()
>> give an error when applied to an int or float? len() should always
>> return something; in particular, when applied to a scalar, it should
>> return a value of 1. Of course, I can define my own function like this:
>>
>> def mylen(x):
>> if isinstance(x,int) or isinstance(x,float): return 1 return len(x)
>>
>> But, this shouldn't be necessary.
>
> The problem is that redefining len()/length/size that way would violate
> several principles of Python's design (The "Zen" of Python -
> http://www.python.org/dev/peps/pep-0020/).
>
> Specifically:
> - Explicit is better than implicit.
> - Special cases aren't special enough to break the rules.
> - Errors should never pass silently.
> - In the face of ambiguity, refuse the temptation to guess.
Chris, I'm curious why you think that these Zen are relevant to the OP's
complaint.
Re explicit vs implicit, len(42) is just as explicit as len([42, 23]).
Arguably (I wouldn't argue this, but some people might) ints aren't
"special enough" to break the rule that len(obj) should always return
something.
(I don't actually agree, but some people might be able to produce a
coherent argument why len() should apply equally to all objects.)
Re errors passing silently, the OP doesn't believe that len(42) should be
an error, so that's not relevant.
And there's nothing ambiguous about len(42).
I agree with the current Python behaviour, but I don't think there's
anything in the Zen to support it. As far as I know, there is no
programming language which treats scalars like ints as if they were
vectors of length 1, which makes Python's choice to make ints unlengthed
a no-brainer.
--
Steven
> In article <mailman.3674.1248461...@python.org>,
> Terry Reedy <tjr...@udel.edu> wrote:
>
>> Better: if isinstance(x, (int, float, complex)):
>
> I never noticed this before, but it seems odd that the second argument
> to isinstance() should be a tuple. Using the normal arguments made
> about tuples vs. lists, it seems like a list would be the right data
> structure here.
What would be the point of using a list? You're never going to sort it,
or append items to it, or otherwise mutate it. You build it, pass it to a
function which doesn't modify it in any fashion, then it gets garbage
collected.
> I suppose a set would be even more right, but (I'm
> pretty sure) isinstance() predates sets.
Yes.
[steve@sylar ~]$ python1.5
Python 1.5.2 (#1, Apr 1 2009, 22:55:54) [GCC 4.1.2 20070925 (Red Hat
4.1.2-27)] on linux2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> isinstance
<built-in function isinstance>
>>> set
Traceback (innermost last):
File "<stdin>", line 1, in ?
NameError: set
> I'm curious why a tuple was chosen.
Tuples are smaller and faster to build than lists -- they're the most
lightweight sequence type in Python. You don't need all the extra
functionality of lists, so why go to the time and effort of building a
list?
--
Steven
To explain in more detail:
> Re explicit vs implicit, len(42) is just as explicit as len([42, 23]).
If you want a collection (something that has length), then one should
explicitly create one, not implicitly have a singleton value act like
it's a pseudo-collection.
I admit I'm somewhat conflating this principle with the anti-ambiguity
principle, but the two are related, imho.
> Arguably (I wouldn't argue this, but some people might) ints aren't
> "special enough" to break the rule that len(obj) should always return
> something.
Except that's not the current rule. The current rule is that it's
defined only for collections.
One would instead have to argue why ints are special enough to have
len() defined despite not being collections.
I think the point made by Grant Edwards is instructive. len(x) = 1
typically implies list(x)[0] and similar should be valid. Altering the
behavior would invalidate that theorem and cause quite a bit of code
upheaval, all just to save the OP from typing one pair of []s.
> (I don't actually agree, but some people might be able to produce a
> coherent argument why len() should apply equally to all objects.)
Well, yes, this /whole/ "argument" is entirely academic; the behavior
is extremely unlikely to change, we're just trying to give ex post
facto rationales for pedagogical purposes. :)
> Re errors passing silently, the OP doesn't believe that len(42) should be
> an error, so that's not relevant.
True, it would not directly silence an error, but defining len() on
scalars would tend towards obscuring errors in code that incorrectly
treats scalars as collections.
> And there's nothing ambiguous about len(42).
Really? What is its value then? I think arguments of varying quality
can be made for:
1 - as the OP and those from array programming languages would suggest
2 - the number of decimal digits in 42, if one was feeling Perlish
6 - the minimum number of bits necessary to represent 42 in binary
32 (or 64, depending on your CPU) - the number of bits necessary to
represent an int (obviously breaks down a bit with arbitrary-magnitude
ints)
undefined - i.e. it causes an error, the current behavior; asking for
the length of a non-collection is "nonsensical" or "absurd"
> I agree with the current Python behaviour, but I don't think there's
> anything in the Zen to support it. As far as I know, there is no
The problem and strength of the Zen is that it's all about how you
interpret it. :-)
First one to correctly decompress the value 0 into an ASCII character
wins the title of the world's most capable hacker :p
Marcus
--
Kindest regards.
Mark Lawrence.
Marcus
Bah...uncompressing the value 0 into *an* ASCII character is
easy. Uncompressing it into the *original* ASCII character from
which it was compressed (with the aforementioned compression
method) becomes a bit trickier ;-)
-tkc
Deja vu: http://www.hackles.org/cgi-bin/archives.pl?request=310
- Chris
--
http://blog.rebertia.com
I ignore the 'normal arguments' and it seems that Guido or the designer
of isinstance did so here too. Fortunately. Practicality beats
'purity', especially misguided purity.
> What would be the point of using a list? You're never going to sort it,
> or append items to it, or otherwise mutate it. You build it, pass it to a
> function which doesn't modify it in any fashion, then it gets garbage
> collected.
>
>
>> I suppose a set would be even more right, but (I'm
>> pretty sure) isinstance() predates sets.
>
> Yes.
>
> [steve@sylar ~]$ python1.5
> Python 1.5.2 (#1, Apr 1 2009, 22:55:54) [GCC 4.1.2 20070925 (Red Hat
> 4.1.2-27)] on linux2
> Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>>> isinstance
> <built-in function isinstance>
>>>> set
> Traceback (innermost last):
> File "<stdin>", line 1, in ?
> NameError: set
>
>
>
>> I'm curious why a tuple was chosen.
>
> Tuples are smaller and faster to build than lists -- they're the most
> lightweight sequence type in Python. You don't need all the extra
> functionality of lists, so why go to the time and effort of building a
> list?
In fact, constant tuples can be and now are compiled as constants:
>>> dis(compile('(1,2,3)','','eval'))
1 0 LOAD_CONST 3 ((1, 2, 3))
3 RETURN_VALUE
>>> dis(compile('[1,2,3]','','eval'))
1 0 LOAD_CONST 0 (1)
3 LOAD_CONST 1 (2)
6 LOAD_CONST 2 (3)
9 BUILD_LIST 3
12 RETURN_VALUE
Internally, even a frozenset is more complicated than a tuple since it
still needs a hash table, which is overkill for something that will be
linearly scanned exactly once.
tjr
> I think the point made by Grant Edwards is instructive. len(x) = 1
> typically implies list(x)[0] and similar should be valid.
At least, one should be able to iterate with x and get len(x) items.
See below.
>> And there's nothing ambiguous about len(42).
>
> Really? What is its value then? I think arguments of varying quality
> can be made for:
> 1 - as the OP and those from array programming languages would suggest
> 2 - the number of decimal digits in 42, if one was feeling Perlish
> 6 - the minimum number of bits necessary to represent 42 in binary
> 32 (or 64, depending on your CPU) - the number of bits necessary to
> represent an int (obviously breaks down a bit with arbitrary-magnitude
> ints)
> undefined - i.e. it causes an error, the current behavior; asking for
> the length of a non-collection is "nonsensical" or "absurd"
In set theory, one can define counts recursively as follows
0 = {} (set, not dict)
n+1 = n | {n}
so len(n) = n, and in particular, len(42) = 42.
On the same basis, it has been proposed (and rejected) that iter(n) ==
range(n), do that we could write 'for i in 10' for instance. Guido
thought this too esoteric.
Terry Jan Reedy
There's a very good reason[*]. The second argument to isinstance() is a
classinfo where a classinfo is a type or a tuple of classinfo.
That means you can have an arbitrarily complex set of nested tuples e.g.
(int, (float, complex)), but the immutable nature of tuples means the
implementation of isinstance can walk the tuple tree without ever having to
worry about infinite loops.
If classinfo could be a list of types then someone somewhere would feed it
a recursive list and then complain that the interpreter crashed.
Exception specifications are tuples for the same reason.
[*] For some definition of 'very good'. Would Python be significantly
impaired if you couldn't combine classinfos into a tree structure? Probably
not.
So you want len() to treat 123 as though it could potentially be a list
containing a single element?
In that case there could be an ambiguity here:
print len([10,20,30])
Should it print 3 (the elements in [10,20,30]), or 1 (treating [10,20,30] as
a potential list containing the single element [10,20,30])?
--
bartc
is certainly very compact, and does what I want. Thanks!
--
View this message in context: http://www.nabble.com/len%28%29-should-always-return-something-tp24639361p24654347.html
Sent from the Python - python-list mailing list archive at Nabble.com.
Actually, Matlab does:
>> length(5)
ans =
1
>>
--
View this message in context: http://www.nabble.com/len%28%29-should-always-return-something-tp24639361p24654358.html
def dumbfunc(xs):
for x in xs:
print x
This function works fine if xs is a list of floats, but not if it is single
float. It can be made to work as follows:
def dumbfunc(xs):
if isinstance(xs,(int,float,complex)): xs= [xs]
for x in xs:
print x
Having to put such extra logic into practically every function is one of the
annoying things about Python.
Phillip
Diez B. Roggisch-2 wrote:
>
> Dr. Phillip M. Feldman schrieb:
>> Some aspects of the Python design are remarkably clever, while others
>> leave
>> me perplexed. Here's an example of the latter: Why does len() give an
>> error
>> when applied to an int or float? len() should always return something; in
>> particular, when applied to a scalar, it should return a value of 1. Of
>> course, I can define my own function like this:
>>
>> def mylen(x):
>> if isinstance(x,int) or isinstance(x,float): return 1
>> return len(x)
>>
>> But, this shouldn't be necessary.
>
> Can you show some example of where that is actually making a piece of
> code more elegant?
>
> Diez
> --
> http://mail.python.org/mailman/listinfo/python-list
You can easily fix that using decorators:
(disclaimer: untested, except mentally)
#bit of setup; pays off later
def list_or_single(func):
def wrapper(arg):
try: iter(arg)
except TypeError: arg = [arg]
return func(arg)
return wrapper
#now just prefix functions with @list_or_single
@list_or_single
def dumbfunc(xs):
for x in xs:
print x
Using the extended call syntax as I explained earlier is another option.
You can call the big mess "Matlab".
Carl Banks
I don't have this problem - when I have a list of one element, that's
what I use - a list with one element. I think things would get much
simpler if you do such a conversion right at the Matlab-Python
interface, rather than changing all kind of things in Python so that
its types are more matlab-like. Just like you shouldn't program Python
by simply translating Java or C into Python idiom, you also shouldn't
program Python by trying to mimic Matlab. Each language has its own
strengths and weaknesses, and moving things over too much in a
simplistic fashion will usually mean that you get the weaknesses of
both and the strengths of neither.
--
André Engels, andre...@gmail.com
> Here's a simple-minded example:
>
> def dumbfunc(xs):
> for x in xs:
> print x
>
> This function works fine if xs is a list of floats, but not if it is
> single float. It can be made to work as follows:
>
> def dumbfunc(xs):
> if isinstance(xs,(int,float,complex)):
> xs= [xs]
> for x in xs:
> print x
>
> Having to put such extra logic into practically every function is one of
> the annoying things about Python.
But it's not "practically every function". It's hardly any function at
all -- in my code, I don't think I've ever wanted this behavior. I would
consider it an error for function(42) and function([42]) to behave the
same way. One is a scalar, and the other is a vector -- they're different
things, it's poor programming practice to treat them identically.
(If Matlab does this, so much the worse for Matlab, in my opinion.)
However, if you want this behaviour, it's easy enough to get it with a
decorator:
from functools import wraps
def matlab(func):
"""Decorate func so that it behaves like Matlab, that is,
it considers a single scalar argument to be the same as a
vector of length one."""
@wraps(func)
def inner(arg, **kwargs):
# If arg is already a vector, don't touch it.
try:
# If this succeeds, it's a vector of some type.
iter(arg)
except TypeError:
# It's a scalar.
arg = [arg]
# Now call the decorated function (the original).
return func(arg, **kwargs)
return inner
With this decorator in hand, you can now easily get the behaviour you
want with a single extra line per function:
>>> @matlab
... def mean(numbers):
... return sum(numbers)/len(numbers)
...
>>> mean([4.5])
4.5
>>> mean(4.5)
4.5
>>> mean([4.5, 3.6])
4.0499999999999998
Decorators are extremely powerful constructs, and well worth learning. As
an example, here's a similar decorator that will accept multiple
arguments, like the built-in functions min() and max():
def one_or_many(func):
"""Decorate func so that it behaves like the built-ins
min() and max()."""
@wraps(func)
def inner(*args, **kwargs):
# If we're given a single argument, and it's a vector,
# use it as args.
if len(args) == 1:
try:
iter(args[0])
except TypeError:
pass
else:
# No exception was raised, so it's a vector.
args = args[0]
# Now call the decorated function (the original).
return func(args, **kwargs)
return inner
And then use it:
>>> @one_or_many
... def minmax(numbers):
... """Return the minimum and maximum element of numbers,
... making a single pass."""
... # the following will fail if given no arguments
... smallest = biggest = numbers[0]
... for x in numbers[1:]:
... if x < smallest:
... smallest = x
... elif x > biggest:
... biggest = x
... return (smallest, biggest)
...
>>>
>>> minmax([2, 4, 6, 8, 1, 3, 5, 7])
(1, 8)
>>> minmax(2, 4, 6, 8, 1, 3, 5, 7)
(1, 8)
--
Steven
> On Jul 24, 3:11 pm, "Rhodri James" <rho...@wildebst.demon.co.uk>
>
> wrote:
> > Which doesn't make your point less valid. In fact I'd go so
> > far as to argue that what len() gives you is the number of
> > items in a container, so len(7) should return 0.
>
> Nah. 7 contains three bits, so len(7) should *clearly* return 3.
Almost right - however the first seven that you typed was a string
seven and not an int - so the hex is 37 and that takes at least
six bits...
:-)
Now if only someone can figure out a reason why it should
return seven, then it would be perfect!
- Hendrik
I knew that you were coming from Matlab as soon as I saw the subject
line.
I use both Matlab and Python very often, and I understand the design
decisions behind both (insofar as Matlab can be considered a
"design").
The thing to keep in mind about Python is that it's a general purpose
language, not just for mathematical computation, and there are some
things in Python that are a bit suboptimal for math calculations.
This is one of them: when the types of objects you are dealing with
most often are numbers, then there's not much chance for ambiguity
when treating a scalar as a 1x1 matrix.
However, when doing general purpose programming, you often use lots of
types besides numbers, some of which are containers themselves. This
creates the possibility of ambiguity and inconsistent behavior. Let's
consider your example function.
def dumbfunc(xs):
for x in xs:
print x
You can use it on an list, like this, and there is no ambiguity:
dumbfunc([1,2,3])
Now suppose Python allowed numbers to be treated as degenerate
sequences of length 1. Then you could pass a number, and it would
work as you expect:
dumbfunc(1)
However, because Python is general purpose, you might also want to
pass other types around, such as strings. Say you wanted to print a
list of string, you would do this, and it would work as expected:
dumbfunc(["abc","def","ghi"])
Now, the problem. In the numbers example, you were able to treat a
single number as a degenerate list, and by our supposition, it
worked. By analogy, you would expect to be able to do the same with a
list of strings, like this:
dumbfunc("abc")
Whoops: doesn't work. Instead of printing one string "abc" it prints
three strings, "a", "b", and "c".
By allowing scalar numbers to act as degenerate lists, you've
introduced a very bad inconsistency into the language, you've made it
difficult to learn the language by analogy.
For a general purpose language there is really no second-guessing this
design decision. It would be unequivocally bad to have atomic types
act like sequences. The reason it isn't so bad in Matlab is that you
can rely on the elements of an array to be scalar.
Matlab, for its part, does contain some types (cell arrays and
structures) that can contain non-scalars for cases when you want to do
that. However, you will notice that no scalar will ever be treated as
a degenerate cell array or structure. Even a poorly designed, ad hoc
language like Matlab won't try to treat scalar numbers as cell arrays,
because ambiguity like I described above will appear. Nope, it takes
an abomination like Perl to do that.
As for how I would recommend you translate the Matlab function that
rely on this: you need to decide whether that scalar number you are
passing in is REALLY a scalar, or a degenerate vector. If it's the
latter, just get over it and pass in a single-item list. I have done
these kinds of conversions myself before, and that's the way to do
it. Trying to be cute and writing functions that can work with both
types will lead to trouble and inconsistency, especially if you are a
Python newbie. Just pass in a list if your function expects a list.
Carl Banks
And where comes "len(xs)" into play here? What you want is iteration
over scalars.
I do think that if you frequently have to write code like that, you are
writing errorneous code.
But might that as it is, a simple
def iterable(i):
if isinstance(i, (int, float, complex)):
return [i]
return i
is all you need. So you can write
for x in iterable(xs):
wherever you expect values to be either scalar or iterable.
Diez
>S> Chris, I'm curious why you think that these Zen are relevant to the OP's
>S> complaint.
>S> Re explicit vs implicit, len(42) is just as explicit as len([42, 23]).
>S> Arguably (I wouldn't argue this, but some people might) ints aren't
>S> "special enough" to break the rule that len(obj) should always return
>S> something.
>S> (I don't actually agree, but some people might be able to produce a
>S> coherent argument why len() should apply equally to all objects.)
>S> Re errors passing silently, the OP doesn't believe that len(42) should be
>S> an error, so that's not relevant.
>S> And there's nothing ambiguous about len(42).
len(42) should be 7.5 million.
--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: pi...@vanoostrum.org
> Compressing strings to a single bit is easy. It's the uncompressing that's
> tricky.
Not really - all you have to do is to apply the EXACT same sequence
of operations that compressed it, in reverse.
The unfortunate part is that this information is in almost all cases
larger than the original, uncompressed string, so that it kind of defeats
the object of compression.
So yes - tricky!
:-)
- Hendrik
> First one to correctly decompress the value 0 into an ASCII character
> wins the title of the world's most capable hacker :p
that is easy.
the xor of 0 and 1 is 1, which is ASCII soh, if I remember right.
soh is start of header.
Burroughs poll select, anyone?
- Hendrik
Marcus
>>S> And there's nothing ambiguous about len(42).
>
> len(42) should be 7.5 million.
And "I don't understand your reasoning".upper() should be "Millennium
Hand and Shrimp!".
Every function would be ambiguous if we treat it as returning an
arbitrary result. But we don't -- semantics do matter. We expect that
string.upper() should return the string converted to uppercase, and
that's not ambiguous because we already know what uppercase means. Even
if somebody didn't know what uppercase meant, they would expect that it
had a meaning, and it was just a matter of learning what it meant: for
example, one might take string.upper() as any of:
* convert every letter a..z to A..Z
* convert the first letter of each word to A..Z
* throw away the argument and return the literal "upper"
* count how many characters are in A..Z
and so forth.
These are some of the infinite number of *possible* meanings to
string.upper(), but only one of them is the *actual* meaning. The method
isn't ambiguous, because the language designers have chosen one meaning,
and having learned what that meaning is, it's the *only* meaning you can
legitimately use. If you (generic you) are uncertain what that meaning
is, that's uncertainty, not ambiguity.
Similarly, we might be uncertain about the meaning of len(42) --
reasonable values it might return are 0, 1, 2, the number of bits in 42,
and possibly even 7.5 million as you suggest. But that's our ignorance,
due to the fact that we haven't yet agreed on a meaning to len(42), and
not ambiguity: having made up our mind what len(42) should mean, it could
only mean one thing.
However, mixed string/integer addition is a good example of ambiguity. We
can add strings:
"1" + "2" => "12"
and we can add integers:
1 + 2 => 3
but it is ambiguous as to what "1" + 2 should return. Guido might have
made Python behave like Perl, and define addition of a string and an int,
but there would still be ambiguity in the expression, because we can't
tell if the coder intended "1"+"2" and forgot to quote the two, or
intended 1+2 and forgot to convert the string "1" to an int.
Ambiguity essentially boils down to being unable to reasonably predict
the expectation of the coder. I say "reasonably", because if you allow
unreasonable situations, everything is "ambiguous":
I typed:
x = 42 + y
but maybe I intended to import the math module, therefore the + operator
is ambiguous. Reasonable? No, because we're allowed to assume the coder
is rational, and mistakes are small.
--
Steven
>SD> Ambiguity essentially boils down to being unable to reasonably predict
>SD> the expectation of the coder. I say "reasonably", because if you allow
>SD> unreasonable situations, everything is "ambiguous":
That's for me the reason that len(42) is ambiguous. The OP apparently
had 1 as expectation, whereas my first thought was the minimal number of
bits to represent the number and 7.5 million came later :=). The number
of bits I certainly find reasonable, and I would find the number of
decimal digits equally reasonable. More so than 1, actually. 1 as the
length of an int doesn't give any information.
That does it.
I will be kinder to you in future.
Anybody who quotes foul old Ron cannot be all bad.
- Hendrik
>
> Here's a simple-minded example:
>
> def dumbfunc(xs):
> for x in xs:
> print x
>
> This function works fine if xs is a list of floats, but not if it is
> single
> float. It can be made to work as follows:
>
> def dumbfunc(xs):
> if isinstance(xs,(int,float,complex)): xs= [xs]
> for x in xs:
> print x
>
> Having to put such extra logic into practically every function is one of
> the
> annoying things about Python.
If you persist in treating <language 1> as if it was <language 2>, then
your code will always be ugly, and often buggy. Unless we're talking
natural languages, in which case Yoda-like you will sound.
Fundamentally, your problem is your assertion that it is reasonable to
allow users to treat a single object as if it were wrapped in a list.
In Python, it is not reasonable, for the reasons that you are spending
so much time complaining about.
--
Rhodri James *-* Wildebeest Herder to the Masses
I have spent the last ten years writing scientific code in Python (i.e. that
which otherwise might be written in Matlab), and I can guarantee you that you do
not need to put such extra logic in practically every function. Even when
naively translating code from Matlab, it's not often necessary.
By the way, are you familiar with numpy? If you are converting code from Matlab,
you will almost certainly need it. We have a number of functions that make these
kinds of operations easy when they are in fact necessary. For example, we have
isscalar() and atleast_1d().
def dumbfunc(xs):
xs = numpy.atleast_1d(xs)
for x in xs:
print x
--
Robert Kern
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
He explained in another post that iteration is another feature along the same
lines that he would want for scalars.
I also think that "Explicit is better than implicit." says that there
should be no return value in this case, as any return value would be
implicit.
Marcus
There's actually good reason to do this in heavily matrix-oriented
specialized languages; there are numerous applications where scalars and
1x1 matrices are mathematically equivalent.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Gods are born and die, but the atom endures.
-- Alexander Chase
The pertinent issue here being that Python, as a language, is neither
matrix-oriented nor special-purpose. :)
Yes. And I was responding to the comment that such a feature of a
language would a priori be poor design. It _isn't_ poor design for
special purpose languages. Python isn't one of them, but Matlab _is_.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
More fodder for the new lost generation
-- Nik Kershaw
I was agreeing with your point actually. That was what I was trying to
convey in my post. Apparently I wasn't as successful in that regard as
I'd hoped.
- Chris
--
http://blog.rebertia.com
For my two eurocents, I'd expect such an operator to be called "sizeof" and
when applied to a collection, to also return the number of bits it uses. I
don't think a 'len' function has meaning when applied to something else than a
collection, really...
> I also think that "Explicit is better than implicit." says that there
> should be no return value in this case, as any return value would be
> implicit.
Agreed.
Cheers,
Emm
> Steven D'Aprano wrote:
>> But it's not "practically every function". It's hardly any function at
>> all -- in my code, I don't think I've ever wanted this behavior. I
>> would consider it an error for function(42) and function([42]) to
>> behave the same way. One is a scalar, and the other is a vector --
>> they're different things, it's poor programming practice to treat them
>> identically.
>>
>> (If Matlab does this, so much the worse for Matlab, in my opinion.)
>
> There's actually good reason to do this in heavily matrix-oriented
> specialized languages; there are numerous applications where scalars and
> 1x1 matrices are mathematically equivalent.
I'm curious what those applications are, because regular multiplication
behaves differently depending on whether you have a 1x1 matrix or a
scalar:
[[2]]*[[1, 2, 3], [2, 3, 4]] is not defined
2*[[1, 2, 3], [2, 3, 4]] = [[2, 4, 6], [2, 6, 8]]
I'm curious as to what these applications are, and what they're actually
doing. Kronecker multiplication perhaps? Do you have some examples of
those applications?
--
Steven
The most obvious example would be the matrix algebra equivalent of the
calculation of the dot product, the equivalent of a dot product in
normal vector algebra. If you have two 3-vectors (say), u = (u_1, u_2,
u_3) and v = (v_1, v_2, v_3), then the dot product is the sum of the
pairwise products of these terms, u dot v = sum_i u_i v_i = u_1 v_1 +
u_2 v_2 + u_3 v_3.
Nothing revolutionary there. The matrix way of writing this wouldn't
obviously work, since multiplying two nx1 or (1xn) matrixes by each
other is invalid. But you _can_ multiply a nx1 matrix by an 1xn matrix,
and you get the equivalent of the dot product:
u v^T = ( u dot v ),
where the right hand side of the equation is formally a 1x1 matrix
(intended to be indicated by the parentheses), but you can see how it is
useful to think of it as just a scalar, because it's really just a
matrix version of the same thing as a dot product.
This stretches out to other kinds of applications, where, say, in tensor
calculus, you can think of a contravariant vector as being transformed
into a covariant vector by the application of the matrix tensor, which
is written as lowering an index. The components of the contravariant
vector can be thought of as a column vector, while the components of a
covariant vector can be represented with a row vector. The application
of the metric tensor to a contravariant vector turns it into a row
vector, and then contracting over the two vectors gives you the inner
product as above. The applications and contractions can all be
visualized as matrix multiplications. (Contrary to a popularization,
tensors _aren't_ generalizations of matrices, but their components can be.)
It's a bunch of other examples like that where you end up with a 1x1
matrix that really represents a scalar, and since that was intended
there really isn't a lot of efficacy to treat it as a separate entity.
Especially if you're dealing with a special-purpose language where
everything is really a form of an generalized array representation of
something _anyway_.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Scars are like memories. We do not have them removed.
-- Chmeee
>
> "As far as I know, there is no programming language which treats scalars
> like ints as if they were
> vectors of length 1"
>
> Actually, Matlab does:
>
>>> length(5)
> ans =
> 1
>>>
Oddly enough, so does Perl:
$ print length(44)
2
(that's in the Zoidberg shell)
j
No, that's not really treating scalars as vectors of length 1.
Were it doing so, length(44) would be 1 rather than 2. What
Perl does is treat everything as a string.
--
Grant Edwards grante Yow! I was making donuts
at and now I'm on a bus!
visi.com
Wow, you could substitute "Matlab" for "Python" in your post and it'd still be
just as good. :-)