473,322 Members | 1,690 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

Bug or Feature?

I was playing around with defining new types and have seen the
following behaviour:

Python 2.3.1
============
class Int(int):pass .... a = Int(7)
b = Int(8)
c = a + b
type(c) <type 'int'>

Basicly: Int is not closed under it's defined operations. :-(
by contrast:
class myset(Set):pass .... a = myset([1,2])
b = myset([2,3])
c = a & b
type(c)

<class '__main__.myset'>

subclasses of Set are closed under the set operations. :-)

Should I consider this as a bug or something I have to live with?

Example, why this can be problematic:
Consider, I want to define an integer subtype that holds integers modulo N.

The straight forward way would be:

class mod7(int):
def __new__(cls,value):
return int.__new__(cls,value%7)

Since addition, substraction, etc. doesn't work as expected, one must
redefine all relevant operators.
This is not what I'd consider object oriented behaviour.

Stephan

P.S.: for the mind police out there: Other than that, Python is great.

Jul 18 '05 #1
14 1705
Stephan Diehl <st***********@gmx.net> wrote in message news:<bp*************@news.t-online.com>...
I was playing around with defining new types and have seen the
following behaviour:

Python 2.3.1
============
class Int(int):pass ... a = Int(7)
b = Int(8)
c = a + b
type(c) <type 'int'>

Basicly: Int is not closed under it's defined operations. :-(


You want my "innermethods" module. Originally I wrote it as a recipe
for the cookbook, but then I forgot to post it ;)

"""
A method of a class ``C`` is said to be an ``inner method`` of ``C``
if it returns an instance of ``C``. For instance, the ``.replace``
method of the string class is an inner method of ``str``, since
invoked by a string, it returns a string:
s='s'
r=s.replace('s','r')
print r,type(r) r <type 'str'>

In general, the property of being an inner method is not preserved
by inheritance. For instance, if I define a subclass of the string class,
class Str(str): .... pass

then ``Str`` has still a ``.replace`` method (inherited from ``str``),
but it is not an inner method of ``Str``:
s=Str('s')
r=s.replace('s','r')
print r,type(r) # the type of r is 'str', not 'Str'! r <type 'str'>

In many circumstances, this is not a problem. However, sometimes
it is important to keep the inner methods safe under inheritance.
If we are writing the methods from scratch, this can be done
by returning ``self.__class__(returnvalue)`` instead of the
simple ``returnvalue``. However, if the methods have been written
by others and we are simply inhering them, we need a more sophisticated
solution.

This module provides a ``protect_inner_methods`` metaclass-like function
which guarantees that the inner methods of the class invoking it are
safe under inheritance. As an exemplication and a commodoty, the
module also provides a ``Str`` class with protected versions of
all the inner methods of the builtin ``str`` class. The only
exception are ``__str__`` and ``__repr__``: it is better than
they stay unprotected, so the string representation of subclasses
of ``str`` is a simple plain string, not an enhanced one. In
this way ``str(x)`` continues to convert ``x`` instances in ``str``
instances. If ``Str`` instances are wanted, use ``Str()``!

Here is an example, showing that ``Str.replace`` is an inner method
of ``Str``:
from innermethods import Str
s=Str('s')
r=s.replace('s','r') # .replace invoked from an instance of 'Str'
print r,type(r) # returns an instance of 'Str', i.e. it is inner method r <class 'innermethods.Str'>

Let me show that the inner methods of ``Str`` are protected under
inheritance, i.e. they continues to be inner methods of the
subclasses:
class MyStr(Str): .... pass
s=MyStr('s')
r=s.replace('s','r') # .replace invoked from an instance of 'Str'
print r,type(r) # returns an instance of 'Str', i.e. it is inner method

r <class 'MyStr'>

"""

def protect_inner__method(cls,methname):
"""Given a class and an inner method name, returns a wrapped
version of the inner method. Raise an error if the method is not
defined in any ancestors of the class. In the case of duplicated
names, the first method in the MRO is taken."""
def _(self,*args,**kw):
supermethod=getattr(super(cls,self),methname)
return self.__class__(supermethod(*args,**kw))
return _

def protect_inner_methods(name,bases,dic):
"""Metaclass-like function. Returns a new class with inner methods
protected under inheritance. The calling class must provide a
``__innermethods__`` attribute containing the list of the
method names to be protected, otherwise nothing will be done."""
cls=type(name,bases,dic) # generate the new class
innermethods=dic.get('__innermethods__',[])
# look for the list of methods to wrap and wrap them all
for methname in innermethods:
setattr(cls,methname,protect_inner__method(cls,met hname))
return cls

class Str(str):
"""A string class with wrapped inner methods."""
__metaclass__=protect_inner_methods
__innermethods__="""__add__ __mod__ __mul__ __rmod__ __rmul__ capitalize
center expandtabs join ljust lower lstrip replace rjust rstrip strip
swapcase title translate upper zfill""".split()
def __radd__(self,other): # inner method
"""Guarantees ``'a'+Str('b')`` returns a ``Str`` instance.
Also ``s='s'; s+=Str('b')`` makes ``s`` a ``Str`` instance."""
return self.__class__(other.__add__(self))
Jul 18 '05 #2
Michele Simionato wrote:
Stephan Diehl <st***********@gmx.net> wrote in message
news:<bp*************@news.t-online.com>...
I was playing around with defining new types and have seen the
following behaviour:

Python 2.3.1
============
>>> class Int(int):pass

...
>>> a = Int(7)
>>> b = Int(8)
>>> c = a + b
>>> type(c)

<type 'int'>

Basicly: Int is not closed under it's defined operations. :-(


You want my "innermethods" module. Originally I wrote it as a recipe
for the cookbook, but then I forgot to post it ;)


Yes, thanks, this is most helpfull.

Although, the question was more along the line, if (in the light of the
principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as real
types would be much better, if they were safe under inheritance.
Jul 18 '05 #3
Stephan Diehl <st***********@gmx.net> writes:
Although, the question was more along the line, if (in the light of the
principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as real
types would be much better, if they were safe under inheritance.


The problem is that it's impossible for the int type to know about the
requirements of your subclass' constructor. Explicit is better than
implicit, and all that.

For the example you posted, I don't see much of an advantage to
inheriting from int.

Cheers,
mwh

--
If a train station is a place where a train stops, what's a
workstation? -- unknown (to me, at least)
Jul 18 '05 #4
Stephan Diehl <st***********@gmx.net> wrote in
news:bp*************@news.t-online.com:
Although, the question was more along the line, if (in the light of
the principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as
real types would be much better, if they were safe under inheritance.

There are some tradeoffs here.

I think that the majority of users would say that the speed of operations
using 'int' is more important than the ease of inheriting from them. If you
can make the 'int' operations work this way, but keep them at least as fast
as they are today, then there may be a case for changing the behaviour.

The other problem though is that this would break backwards compatibility.
For example if any code were to currently add booleans, it would suddenly
get a boolean result. The (untested) code below, currently counts how many
items in a list are greater than a specified value, but under your scheme
it would return a boolean.

def HowManyGreaterThan(aList, aValue):
return reduce(operator.add, [ x > aValue for x in aList ])

I think what would be most useful would be new subclasses of int etc. which
have the properties you desire, but you can write them yourself easily
enough.

What rules, BTW, are you proposing for operations between two separate
subclasses of int? e.g. given your mod7 class, and a corresponding mod9
class should this print 3, 6, 24 or throw an exception?

x = mod7(3)
y = mod9(8)
print x*y

and does this do the same?

print y*x

--
Duncan Booth du****@rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?
Jul 18 '05 #5
Duncan Booth wrote:
Stephan Diehl <st***********@gmx.net> wrote in
news:bp*************@news.t-online.com:
Although, the question was more along the line, if (in the light of
the principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as
real types would be much better, if they were safe under inheritance.
There are some tradeoffs here.

I think that the majority of users would say that the speed of operations
using 'int' is more important than the ease of inheriting from them. If
you can make the 'int' operations work this way, but keep them at least as
fast as they are today, then there may be a case for changing the
behaviour.


O.K., since the stuff I'm concerned about here is of no relevance for
99.9 % of all python programmers, execution speed is a very valid reason for
this (and I'll consider this behaviour as a feature :-)

The other problem though is that this would break backwards compatibility.
For example if any code were to currently add booleans, it would suddenly
get a boolean result. The (untested) code below, currently counts how many
items in a list are greater than a specified value, but under your scheme
it would return a boolean.

def HowManyGreaterThan(aList, aValue):
return reduce(operator.add, [ x > aValue for x in aList ])
Which, of course, would bring us to the discussion if a bool should be a
subtype of int (and since this was decided long ago, it should not be
discussed, of course)

I think what would be most useful would be new subclasses of int etc.
which have the properties you desire, but you can write them yourself
easily enough.

What rules, BTW, are you proposing for operations between two separate
subclasses of int? e.g. given your mod7 class, and a corresponding mod9
class should this print 3, 6, 24 or throw an exception?

x = mod7(3)
y = mod9(8)
print x*y

and does this do the same?

print y*x


tough question. I'd probably throw an exception.

thanks for your input

Stephan
Jul 18 '05 #6
Michael Hudson wrote:
Stephan Diehl <st***********@gmx.net> writes:
Although, the question was more along the line, if (in the light of the
principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as
real types would be much better, if they were safe under inheritance.
The problem is that it's impossible for the int type to know about the
requirements of your subclass' constructor. Explicit is better than
implicit, and all that.

For the example you posted, I don't see much of an advantage to
inheriting from int.


This is probably more a theoretical question, but if I decide to have an
operation within one specific domain, I want the result in that domain too.
Otherwise, there would be no point at all to define such a numeric class at
all.

Stephan
Cheers,
mwh


Jul 18 '05 #7
In article <m3************@pc150.maths.bris.ac.uk>,
Michael Hudson <mw*@python.net> wrote:
Stephan Diehl <st***********@gmx.net> writes:
Although, the question was more along the line, if (in the light of the
principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as real
types would be much better, if they were safe under inheritance.
The problem is that it's impossible for the int type to know about the
requirements of your subclass' constructor. Explicit is better than
implicit, and all that.


Not strictly true. A numeric operation can access the
objects class, as:

def __mul__ (self, other):
if not isinstance (other, Decimal):
other = Decimal (other)
return self.__class__ (self._v * other._v, self._e + other._e)

so that operations on a descendant of the Decimal class will
return objects of the descendants class. (Strange that I
didn't code `isinstance (other, self.__class__)`, etc. Must
think out the consequences of that.)

What this would mean in runtime for the bazillions of int
operations that run every day, I don't know.
For the example you posted, I don't see much of an advantage to
inheriting from int.


True. With int working as it does, it might be better to
pull out all the stops and write an Int class that supports
full inheritance, and work from there.

Regards. Mel.
Jul 18 '05 #8
On Mon, 24 Nov 2003 18:13:34 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:

....
This is probably more a theoretical question, but if I decide to have an
operation within one specific domain, I want the result in that domain too.
Otherwise, there would be no point at all to define such a numeric class at
all.

Stephan


I understand what you're saying, but there's no universal rule that
says that the result of operations between members of a set are also
members of the set. Obvious examples include division on the set of
integers, and division over the set of real numbers, i.e.division by
zero is not a real number.
--dang
Jul 18 '05 #9
mw*****@the-wire.com (Mel Wilson) writes:
In article <m3************@pc150.maths.bris.ac.uk>,
Michael Hudson <mw*@python.net> wrote:
Stephan Diehl <st***********@gmx.net> writes:
Although, the question was more along the line, if (in the light of the
principle of least surprise) this behaviour makes sense.
My private opinion would be, that the usefullness of builtin types as real
types would be much better, if they were safe under inheritance.
The problem is that it's impossible for the int type to know about the
requirements of your subclass' constructor. Explicit is better than
implicit, and all that.


Not strictly true.


Um, did you actually read what I said? Again, with emphasis:
The problem is that it's impossible for the int type to know about the
*REQUIREMENTS OF YOUR SUBCLASS' CONSTRUCTOR*. A numeric operation can access the objects class, as:

def __mul__ (self, other):
if not isinstance (other, Decimal):
other = Decimal (other)
return self.__class__ (self._v * other._v, self._e + other._e)

so that operations on a descendant of the Decimal class will
return objects of the descendants class.
Yes, but now you're constrainting future subclasses' constructors.
What this would mean in runtime for the bazillions of int
operations that run every day, I don't know.


There would be ways to avoid that, I think.
For the example you posted, I don't see much of an advantage to
inheriting from int.


True. With int working as it does, it might be better to
pull out all the stops and write an Int class that supports
full inheritance, and work from there.


I think someone has written such a UserInt somewhere...

It seems to be generally good advice to only subclass builtin types in
Python if you want to ADD behaviour, not change it. Not 100% true,
but close.

Cheers,
mwh

--
LINTILLA: You could take some evening classes.
ARTHUR: What, here?
LINTILLA: Yes, I've got a bottle of them. Little pink ones.
-- The Hitch-Hikers Guide to the Galaxy, Episode 12
Jul 18 '05 #10
Dang Griffith wrote:
On Mon, 24 Nov 2003 18:13:34 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:

...
This is probably more a theoretical question, but if I decide to have an
operation within one specific domain, I want the result in that domain
too. Otherwise, there would be no point at all to define such a numeric
class at all.

Stephan


I understand what you're saying, but there's no universal rule that
says that the result of operations between members of a set are also
members of the set. Obvious examples include division on the set of
integers, and division over the set of real numbers, i.e.division by
zero is not a real number.
--dang


If we have a look at the mathematical definition of numbers, the interesting
thing is not the set of these numbers, but the set combined with some
usefull operators (like addition and multiplication).
It is (mathematicaly speaking) not possible to have a result under these
operations that are outside the definition.

In that sense, there IS this universal rule, you were talking about. (and
division by zero is just not allowed by definition).

Stephan
Jul 18 '05 #11
On Mon, 24 Nov 2003 19:35:51 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:
Dang Griffith wrote:
On Mon, 24 Nov 2003 18:13:34 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:

...
This is probably more a theoretical question, but if I decide to have an
operation within one specific domain, I want the result in that domain
too. Otherwise, there would be no point at all to define such a numeric
class at all.

Stephan


I understand what you're saying, but there's no universal rule that
says that the result of operations between members of a set are also
members of the set. Obvious examples include division on the set of
integers, and division over the set of real numbers, i.e.division by
zero is not a real number.
--dang


If we have a look at the mathematical definition of numbers, the interesting
thing is not the set of these numbers, but the set combined with some
usefull operators (like addition and multiplication).
It is (mathematicaly speaking) not possible to have a result under these
operations that are outside the definition.

In that sense, there IS this universal rule, you were talking about. (and
division by zero is just not allowed by definition).

Stephan

And for the set of whole numbers, some divisions are allowed, but any
division that results in a fraction would not be allowed. By
definition, i.e. a combination of operators and operands that result
in a value not in the same domain is not a valid combination. It
works, but seems circular. :-)
--dang
Jul 18 '05 #12
Dang Griffith wrote:
On Mon, 24 Nov 2003 19:35:51 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:
Dang Griffith wrote:
On Mon, 24 Nov 2003 18:13:34 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:

...
This is probably more a theoretical question, but if I decide to have an
operation within one specific domain, I want the result in that domain
too. Otherwise, there would be no point at all to define such a numeric
class at all.

Stephan

I understand what you're saying, but there's no universal rule that
says that the result of operations between members of a set are also
members of the set. Obvious examples include division on the set of
integers, and division over the set of real numbers, i.e.division by
zero is not a real number.
--dang


If we have a look at the mathematical definition of numbers, the
interesting thing is not the set of these numbers, but the set combined
with some usefull operators (like addition and multiplication).
It is (mathematicaly speaking) not possible to have a result under these
operations that are outside the definition.

In that sense, there IS this universal rule, you were talking about. (and
division by zero is just not allowed by definition).

Stephan

And for the set of whole numbers, some divisions are allowed, but any
division that results in a fraction would not be allowed. By
definition, i.e. a combination of operators and operands that result
in a value not in the same domain is not a valid combination. It
works, but seems circular. :-)
--dang


You might have noticed, I was talking about Mathematics, not the imperfect
implementation of it in computers :-)
To have division as a meaningfull operation, the set in question must be a
group under the '*' operation (See for example
"http://en2.wikipedia.org/wiki/Group_(mathematics)" )
The point is, that division is the reverse operation to multiplication.

Cheers, Stephan
Jul 18 '05 #13
On Tue, 25 Nov 2003 16:04:57 +0100, Stephan Diehl
<st*****************@gmx.net> wrote:

[snip]

You might have noticed, I was talking about Mathematics, not the imperfect
implementation of it in computers :-)
To have division as a meaningfull operation, the set in question must be a
group under the '*' operation (See for example
"http://en2.wikipedia.org/wiki/Group_(mathematics)" )
The point is, that division is the reverse operation to multiplication.


But when talking of "numbers" a group is not enough, you want a field
- a set with two operations (in some situations something weaker, like
integral domains, is enough). In fields, such as real numbers, complex
numbers, p mod integers, p-adic fields, etc. every number has a
multiplicative inverse *except* the zero.

Pedantically yours,
G. Rodrigues
Jul 18 '05 #14
Michael Hudson wrote:
I think someone has written such a UserInt somewhere...


There have been a couple of UserInts floating around.
I think the most recent was mine.

The bad news is that my UserInt module actually returns
ints for all operations.

The good news is that, being a lazy programmer, I didn't
actually write my "UserInt" module -- I let my computer
do it for me, by writing a script which would generate
the module.

The main reason I posted the script is because it can
easily be adapted to create any sort of UserXXX classes,
as well as to add any sort of behavior mods to those
classes. I think it would be trivial to create a UserInt
class which returns other instances of itself for arithmetic
operations by using the script:

http://groups.google.com/groups?hl=e...t%40python.org

Regards,
Pat
Jul 18 '05 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: dayzman | last post by:
Hi, I've read somewhere that feature-based analysis can be used to extract the semantic structure of HTML documents. By semantic structure, they mean the model of the rendered view a reader...
5
by: scsharma | last post by:
Hi, I am using .Net on Windows XP Professional. I am facing a unique problem with visual studio where intellisense feature is getting turned off. If i close IDE and reopen my solution the...
4
by: christopher diggins | last post by:
A feature that I find signficantly missing in C# is the ability to write functions in interfaces that can call other functions of the interface. Given an interface ISomeInteface the only way we can...
18
by: Kamen Yotov | last post by:
hi all, i first posted this on http://msdn.microsoft.com/vcsharp/team/language/ask/default.aspx (ask a c# language designer) a couple of days ago, but no response so far... therefore, i am...
7
by: Russell Mangel | last post by:
I was thinking about what IDE feature I would want the most in the next version of VC++? I would definately ask for the C# feature: #region / #endregion. In my opinion this feature was a...
30
by: Raymond Hettinger | last post by:
Proposal -------- I am gathering data to evaluate a request for an alternate version of itertools.izip() with a None fill-in feature like that for the built-in map() function: >>> map(None,...
12
by: Raymond Hettinger | last post by:
I am evaluating a request for an alternate version of itertools.izip() that has a None fill-in feature like the built-in map function: >>> map(None, 'abc', '12345') # demonstrate map's None...
12
by: =?Utf-8?B?RGFyYSBQ?= | last post by:
Would like to know from the crowd that why do we require a Partial Class. By having such feature aren't we going out of the scope of Entity Concept. Help me to understand in what context this...
20
by: Luke R | last post by:
One thing i used to use alot in vb6 was that tiny little button in the bottom left of the code window which allowed you to view either the whole code file, or just the function/sub you are currenly...
10
by: Conrad Lender | last post by:
In a recent thread in this group, I said that in some cases object detection and feature tests weren't sufficient in the development of cross-browser applications, and that there were situations...
0
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...
0
isladogs
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...
1
isladogs
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...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
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)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
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 using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.