Christoph Groth a écrit :
Bruno Desthuilliers <bruno.42.desthuilli...@websiteburo.invalid> writes:
It seems to me that in this way I might get problems when I pass an
instance of Derived_from_my_type to bar, as it will become an
instance of My_type.
The instance you pass to bar won't "become" anything else. You create
a new My_type instance from the Derived_from_my_type one's values, and
rebinding the _local_ name 'arg' only affects the local namespace.
I understand that it won't become an instance of My_type globally. But
it will become locally and this breaks polymorphism.
Then don't do it !-)
(See code example
I provide at the end)
In C++
Forget about C++ - Python is a different beast !-)
Still, it is useful and interesting to compare languages.
Indeed. But you have to understand enough of a language to compare it
with another one. The old "I can write C in any language" syndrom...
(which I know better than python) I would make bar accept a const
reference to My_type. Then I could use it directly with instances of
My_type, Derived_from_my_type and other types which can be converted
into My_type.
If you only worry about being able to use any "My_type like" object -
that is, any object implementing a given subset of My_type's
interface, then just document your expectations in the function's
docstring and use whatever object is passed in as if it was a My_type
instance. Period. As long as you document what your function expects,
it's the caller's responsaibility to make sure it provides something
compatible. If he don't, well he'll get a nice traceback.
This is not what I am worrying about. I will try to be more explicit.
Ok.
I would like to have a class for a "special matrix". This is an
ordinary 2n by 2n matrix which can be thought of as consisting of four n
by n sized blocks.
Right.
At this moment, I just use normal numpy arrays (or anything which
behaves like them). But I have very good reasons to actually have a
class for these special matrices. Still, I would like to be able to
call functions which work with "special matrices" with plain numpy
arrays as arguments. In that case, the arguments which are plain
matrices should be converted to "special" ones such that the main part
of the function can assume to always work with "special matrices".
Ok. So you want to build a "special matrice" like object from the numpy
array.
The code attached in the end (which is a complete runnable script)
should illustrate what I mean.
This example works as I want except that when bar is called with a an
argument of type Derived, it behaves as Base.
Ok.
Also, I am not sure
whether there is a nicer way to achieve the following functionality for
Base.__init__:
If other is of type Base already, just "pass it on". Otherwise,
construct an instance of Base from it.
You can't do this in the initializer, you have to use either a factory
function or the proper constructor (or an alternate constructor).
****************************************************************
import numpy as np
class Base:
If you're using Python 2.x, make this:
class Base(object):
def __init__(self, other):
if isinstance(other, type(self)):
self = other
'self' is a local name. Rebinding a local name only impact the local
namespace.
return
n = other.shape[0]
assert n == other.shape[1]
assert n % 2 == 0
n //= 2
self.a = other[0 : n, 0 : n]
self.b = other[n : 2*n, 0 : n]
self.c = other[0 : n, n : 2*n]
self.d = other[n : 2*n, n : 2*n]
Question : is there any case where you may want to instanciate this
class with explicit values for a, b, c and d ?
Anyway: the simplest solution here is to replace the call to your Base
class with a call to a factory function. I'd probably go for something
like (Q&D untested code and other usual warnings) :
class Base(object):
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
@classmethod
def from_array(cls, arr):
""" alternate constructor from a numpy array """
n = arr.shape[0]
assert n == arr.shape[1]
assert n % 2 == 0
n //= 2
return cls(
arr[0 : n, 0 : n],
arr[n : 2*n, 0 : n],
arr[0 : n, n : 2*n],
arr[n : 2*n, n : 2*n]
)
def hello(self):
print 'hello from Base'
class Derived(Base):
def hello(self):
print 'hello from Derived'
def coerce(obj, cls=Base):
if isinstance(obj, cls):
return obj
else:
return cls.from_array(obj)
def bar(arg):
arg = coerce(arg)
# Do something useful with arg.{a..d}
arg.hello()
# This works.
a = np.identity(4)
bar(a)
# And this also.
a = Base.from_array(np.identity(4))
bar(a)
# And now this should work too
a = Derived.from_array(np.identity(4))
bar(a)
Does it solve your problem ?-)
Note that if using a plain function hurts your feelings - or just isn't
practical for any other reason - you can also make it another
classmethod of Base, ie :
class Base(object):
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
@classmethod
def from_array(cls, arr):
""" alternate constructor from a numpy array """
n = arr.shape[0]
assert n == arr.shape[1]
assert n % 2 == 0
n //= 2
return cls(
arr[0 : n, 0 : n],
arr[n : 2*n, 0 : n],
arr[0 : n, n : 2*n],
arr[n : 2*n, n : 2*n]
)
@classmethod
def coerce(cls, obj):
if isinstance(obj, cls):
return obj
else:
return cls.from_array(obj)
def bar(arg):
arg = Base.coerce(arg)
# Do something useful with arg.{a..d}
arg.hello()
HTH
--
http://mail.python.org/mailman/listinfo/python-list