On 3 Dec 2005 15:50:25 -0800, "Brendan" <[EMAIL PROTECTED]> wrote:

>There must be an easy way to do this:
>
>For classes that contain very simple data tables, I like to do
>something like this:
>
>class Things(Object):
>    def __init__(self, x, y, z):
>        #assert that x, y, and z have the same length
>
>But I can't figure out a _simple_ way to check the arguments have the
>same length, since len(scalar) throws an exception.  The only ways
>around this I've found so far are
>
>a)  Cast each to a numeric array, and check it's dimension and shape.
>This seems like far too many dependencies for a simple task:
>
>def sLen(x):
>    """determines the number of items in x.
>    Returns 1 if x is a scalar. Returns 0 if x is None
>    """
>    xt = numeric.array(x)
>    if xt == None:
>        return 0
>    elif xt.rank == 0:
>        return 1
>    else:
>        return xt.shape[0]
>
>b) use a separate 'Thing' object, and make the 'Things' initializer
>work only with Thing objects.  This seems like way too much structure
>to me.
>
>c) Don't bother checking the initializer, and wait until the problem
>shows up later.  Maybe this is the 'dynamic' way, but it seems a little
>fragile.
>
>Is there a simpler way to check that either all arguments are scalars,
>or all are lists of the same length?  Is this a poor way to structure
>things?  Your advice is appreciated

I'd go with c) unless you think errors that might result could be too mysterious
to diagnose or some dangerous action could result, but usually the errors won't 
be
very mysterious. If some dangerous action could result, you might well want to
impose a number of constraints, starting with checking input args, but you will
also want thorough unit tests.

Note that an assert statement gets eliminated from the generated code when 
optimization
is requested with a -O command line option, so you might want to write out the 
test and
exception raising explicitely to make sure it remains part of the code, if that 
is
what you want.

You could also define an external function to check that args conform
    def __init__(self, x, y, z)
        argcheck(x, y ,z) # raise exception if non-conforming

where

 >>> scalartype = (int, long, float)
 >>> def argcheck(*args):
 ...     assert len(set([isinstance(x, scalartype) and 'S' or
 ...                     hasattr(x, '__len__') and len(x) for x in args]))==1
 ...
 >>> argcheck(1, 2L, 3.0)
 >>> argcheck([1,2], [3,4], [4,5])
 >>> argcheck([1,2], [3,4], [4,5], 6)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 2, in argcheck
 AssertionError
 >>> argcheck([1,2], [3,4], [4,5,6])
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 2, in argcheck
 AssertionError
 >>> argcheck('abc','def')
 >>> argcheck('abc','def', 3)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 2, in argcheck
 AssertionError

You might want to add a check on the elements of arrays, e.g. to make sure
they are all scalartypes or all complex or whatever (and so as not to
accept str elements ;-).

Note that an assert statement disappears if optimization is called for on the 
python
command line with -O, so you might want to code your own test of the condition 
and
raise an exception explicitly if appropriate.

If the assert is enough, you can of course put it directly in the __init__, 
e.g.,

    def __init__(self, x, y, z)
        assert len(set([isinstance(arg, scalartype) and 'S' or
                        hasattr(arg, '__len__') and len(arg) for arg in 
(x,y,z)]))==1
        ...

BTW, I'm using len(set(list_of_stuff_that_should_all_be_equal))==1 to test that 
they are equal,
since if not, there would be more than one element in the set. So there should 
either be
a bunch of 'S's in the list or a bunch of lengths that are all equal, so a mix 
wouldn't give
one element either. But this is a lot of calling for a simple check that could 
be written to
short-cut lots faster for the specific case or x,y,z args, e.g., (untested)

    ii = isinstance; st = scalartype; ha = hasattr; L = '__len__' # save me 
typing ;-)
    def __init__(self, x, y, z):
        assert ii(x,st) and ii(y,st) and ii(z,st) or ha(x,L) and ha(y,L) and 
ha(z,L) and len(x)==len(y)==len(z)
        ...

If you wanted to check that all the elements of a passed vector x were scalars, 
you could
write (untested)
    assert sum(isinstance(_, scalartype) for _ in x)==len(x)
since True==1 as a subtype of integer.

 >>> sum(isinstance(_, scalartype) for _ in [1, 2.0, 3L])
 3
 >>> sum(isinstance(_, scalartype) for _ in [1, 2.0, 3j])
 2
 >>> sum(isinstance(_, scalartype) for _ in [1, 2.0, []])
 2
compared == len(thething) should work
Of course, your next step in using vectors might give you the check for free,
so no need for redundant checking. It's generally faster to let your args try 
to quack
like the ducks you need, if possible and safe.


Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to