Hi all,
I've been using Python for 3 years, but I've rarely used its OOP
features (I'm a physicist, sorry). Now, after having read a lot about
Python OOP capabilities, I'm trying to get advantage of this (for me)
new paradigm. As a result I've a lot of somewhat philosophical
questions. I will start with one of them.
Suppose I have a bunch of classes that represent slightly (but
conceptually) different object. The instances of each class must behave
in very similar manner, so that I've created a common class ancestor
(let say A) that define a lot of special method (such as __getattr__,
__setattr__, __len__ and so on), and then I've created all my "real"
classes inheriting from it: class A(object):
..... # here define all special and some common methods
class B(A):
..... # this is the first "real" class
class C(A):
..... # and this is the second
and so on. The problem I'm worried about is that an unaware user may
create an instance of "A" supposing that it has any real use, while it
is only a sort of prototype. However, I can't see (from my limited
point of view) any other way to rearrange things and still get a
similar behaviour.
Implementing those special methods directly in class B and then inherit
from it, doesn't seem the right way, since I'd prefer that instances of
B weren't in any relation with the instances of C (i.e. I'd prefer not
to subclass C from B)
Perhaps some OOP techniques (that I miss at the moment) could be of any
help. Any suggestion?
Thanks in advance,
Andrea. 10 1055
On Thu, Dec 01, 2005 at 03:51:05PM -0800, Mr.Rech wrote:
[...] Suppose I have a bunch of classes that represent slightly (but conceptually) different object. The instances of each class must behave in very similar manner, so that I've created a common class ancestor (let say A) that define a lot of special method (such as __getattr__, __setattr__, __len__ and so on), and then I've created all my "real" classes inheriting from it:
class A(object): .... # here define all special and some common methods class B(A): .... # this is the first "real" class class C(A): .... # and this is the second
and so on. The problem I'm worried about is that an unaware user may create an instance of "A" supposing that it has any real use, while it is only a sort of prototype. However, I can't see (from my limited point of view) any other way to rearrange things and still get a similar behaviour. class A(object): ... def __init__(self, foo): ... if self.__class__ is A: ... raise TypeError("A is base class.") ... self.foo = foo ... class B(A):
.... pass
.... class C(A):
.... def __init__(self, foo, bar):
.... A.__init__(self, foo)
.... self.bar = bar
.... a = A(1)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in __init__
TypeError: A is base class. b = B(1) b.foo
1 c = C(1, 2) c.foo, c.bar
(1, 2)
HTH
--Inyeol Lee
"Mr.Rech" <an*************@gmail.com> writes: Suppose I have a bunch of classes that represent slightly (but conceptually) different object. The instances of each class must behave in very similar manner, so that I've created a common class ancestor (let say A) that define a lot of special method (such as __getattr__, __setattr__, __len__ and so on), and then I've created all my "real" classes inheriting from it:
and so on. The problem I'm worried about is that an unaware user may create an instance of "A" supposing that it has any real use, while it is only a sort of prototype. However, I can't see (from my limited point of view) any other way to rearrange things and still get a similar behaviour.
Perhaps some OOP techniques (that I miss at the moment) could be of any help. Any suggestion?
I assume there are methods of B & C that aren't shared, and hence
aren't in A. When the user invokes those, they should get an error
message. That's how this kind of thing is normally dealt with.
If you want things to happen at instantiation time, then you can make
A.__init__ raise an exception. Your B & C __init__ then can't invoke
it. If A.__init__ has a real use, move that into another method that B
& C's __init__ can invoke.
<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Mr.Rech wrote: Suppose I have a bunch of classes that represent slightly (but conceptually) different object. The instances of each class must behave in very similar manner, so that I've created a common class ancestor (let say A) that define a lot of special method (such as __getattr__, __setattr__, __len__ and so on), and then I've created all my "real" classes inheriting from it:
class A(object): ....*****#*here*define*all*special*and*some*common *methods class B(A): ....****#*this*is*the*first*"real"*class class C(A): ....****#*and*this*is*the*second
and so on. The problem I'm worried about is that an unaware user may create an instance of "A" supposing that it has any real use, while it is only a sort of prototype. However, I can't see (from my limited point of view) any other way to rearrange things and still get a similar behaviour.
Implementing those special methods directly in class B and then inherit from it, doesn't seem the right way, since I'd prefer that instances of B weren't in any relation with the instances of C (i.e. I'd prefer not to subclass C from B)
Perhaps some OOP techniques (that I miss at the moment) could be of any help. Any suggestion?
How about
class A(object):
"""Provides common functionality for A-like classes, e. g. B and C.
Do not instantiate.
"""
This is definitely a low-tech approach, but I suppose you don't clutter your
functions with spurious argument type checks, either.
An exception like the one shown by Inyeol Lee is typically raised once
during the development process while my approach bites (only) the
illiterate programmer with a message like a.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'A' object has no attribute 'foo'
which normally can be tracked down almost as quickly -- and which serves him
well anyway :-)
Peter
Inyeol Lee wrote:
(snip) class A(object): ... def __init__(self, foo): ... if self.__class__ is A: ... raise TypeError("A is base class.")
s/TypeError/NotImplementedError/
s/base class/abstract class/
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Thanks for your suggestions. They are very usefull and indeed bypass my
problem. However, I've found a (perhaps) more elegant way to get the
same result using metaclasses. My idea is to define my classes as
follows: class meta_A(type):
..... def __new__(cls, classname, bases, classdict):
# define here all special methods
newdict = { #special methods dict}
classdict.update(newdict) # any suggestion on
automatically build newdict?
return type.__new__(cls, classname, bases, classdict)
class B(object):
__metaclass__ = meta_A
# More methods here
I know metaclasses are a complete different beast, anyway I find this
approach more pythonic. Any comment? Suggestion?
Thanks,
Andrea.
Mr.Rech wrote: Thanks for your suggestions. They are very usefull and indeed bypass my problem. However, I've found a (perhaps) more elegant way to get the same result using metaclasses. My idea is to define my classes as follows:
class meta_A(type): .... def __new__(cls, classname, bases, classdict): # define here all special methods newdict = { #special methods dict} classdict.update(newdict) # any suggestion on automatically build newdict? return type.__new__(cls, classname, bases, classdict)
Are you intentionally defeating inheritance? class B(object):
__metaclass__ = meta_A # More methods here
I know metaclasses are a complete different beast, anyway I find this approach more pythonic. Any comment? Suggestion?
Godawful.
Don't use classes when functions suffice.
Don't use inheritance when duck-typing suffices.
Don't use metaclasses when inheritance suffices.
Corollary: don't use metaclasses to solve problems you have just made up.
In short, the simplest solution is most likely the most pythonic, even when
some odd corner cases are not covered.
Simplicity also has a nice side effect: fewer bugs.
Peter
Mr.Rech wrote: Thanks for your suggestions. They are very usefull and indeed bypass my problem. However, I've found a (perhaps) more elegant way to get the same result using metaclasses.
(snip code) I know metaclasses are a complete different beast, anyway I find this approach more pythonic.
It's not. It's a case of ArbitraryOvercomplexification(tm).
The pythonic way is to use inheritence and make the base class abstract
by raising a NotImplementedError in it's __init__ (cf Inyeol Lee's
answer and my small correction)
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
I see your point. Looking again at my metaclass implementation and
comparing it with your abstract class + inheritance approach it turns
out that the latter is definetively more straightforward, easier to
maintain and all in all more pythonic.
Sorry, but being an OOP newbie put me in the position of
overcomplexifing(tm) things a little bit. I'll be back soon with other
(I hope less silly) questions. ;-p
Thanks for all your suggestions,
Andrea
On Fri, Dec 02, 2005 at 10:43:56AM +0100, bruno at modulix wrote: Inyeol Lee wrote: (snip)
>class A(object): >... def __init__(self, foo): >... if self.__class__ is A: >... raise TypeError("A is base class.")
s/TypeError/NotImplementedError/ s/base class/abstract class/
I prefer TypeError here, NotImplementedError would be OK though.
Here is an example from sets.py in stdlib.
class BaseSet(object):
"""Common base class for mutable and immutable sets."""
__slots__ = ['_data']
# Constructor
def __init__(self):
"""This is an abstract class."""
# Don't call this from a concrete subclass!
if self.__class__ is BaseSet:
raise TypeError, ("BaseSet is an abstract class. "
"Use Set or ImmutableSet.")
Inyeol
Mr.Rech wrote: and so on. The problem I'm worried about is that an unaware user may create an instance of "A" supposing that it has any real use, while it is only a sort of prototype. However, I can't see (from my limited point of view) any other way to rearrange things and still get a similar behaviour.
1) Document your class is not intended for public use.
2) Make your A class "private" of the module that defines it. A simple way is
putting an underscore in front of its name.
3) Make your A class non-functional. I assume B and C have methods that A
doesn't. Then, add those methods to A too, but not implement them:
def foo(self):
"""Foo this and that. Must be implemented in subclasses."""
raise NotImplementedError
--
Giovanni Bajo This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Klaus Neuner |
last post by:
Hello,
code (1) works, code (2) doesn't.
(1)
data = cgi.FieldStorage()
comment = data.getvalue("comment")
user_name = data.getvalue("user_name")
(2)
| |
by: Vidyaranya |
last post by:
I am facing one problem w.r.t DB2,
When i launch my first instance of my client exe.
(written using Delphi 7)
and perform an action on Table A. (one of the row is in Transaction mode)
waits for...
|
by: Ben Finney |
last post by:
Howdy all,
I've recently packaged 'enum' in PyPI. In its description, I make the
claim that it creates "immutable" enumeration objects, and that the
enumeration values are "constant" values.
...
|
by: Ben Finney |
last post by:
Howdy all,
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?
What caveats should be observed in making...
|
by: quortex |
last post by:
Hi all,
I have a native class which has a single instance controlled via the
singleton pattern. I need to call this from both native C++ and from
mixed mode visual studio 2005 c++ CLI.
At...
|
by: jantod |
last post by:
I not only want to compare class *instances* but also the classes
themselves. Something like:
class T(object):
@classmethod
def __cmp__(cls, other):
return cmp(cls.__name__, other.__name__)...
|
by: Pedro Werneck |
last post by:
Hi all
I noticed something strange here while explaining decorators to someone.
Not any real use code, but I think it's worth mentioning.
When I access a class attribute, on a class with a...
|
by: Ben |
last post by:
Hello...
I have a dictionary, where each value is a seperate instance of the
same class:
self.mop_list=record(self.mops)
In my case I know that record_number takes the values 0,3,and 7...
|
by: DolphinDB |
last post by:
Tired of spending countless mintues downsampling your data? Look no further!
In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, we are pleased to welcome back...
|
by: ArrayDB |
last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
|
by: PapaRatzi |
last post by:
Hello,
I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
|
by: Defcon1945 |
last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
|
by: Shællîpôpï 09 |
last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
|
by: af34tf |
last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
|
by: Faith0G |
last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome former...
| |