Python Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me

The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.

Go Back   Dev Shed ForumsProgramming LanguagesPython Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old December 4th, 2012, 05:23 AM
SuperOscar SuperOscar is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2007
Location: Joensuu, Finland
Posts: 403 SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 5 h 1 m 25 sec
Reputation Power: 65
Why can’t I subclass str (truly)

For a very specific and hidden purpose, I tried to subclass strings. That can be done. What cannot be done, however, is modifying the __init__() function so that the new subclass could take additional parameters different from those of the superclass (which is exactly what I needed).

You can subclass lists this way:

Code:
>>> class Spam(list):
    def __init__(self, data=None, eggs=0):
        if data is None:
            data = []
        list.__init__(self, data)
        self.eggs = eggs


>>> test = Spam()
>>> test.eggs
0
>>> another_test = Spam(['a', 'b', 'c'], 10)
>>> another_test.eggs
10


Both tests work: I can create a Spam() object, a subclass of list, either with default or explicit values.

With string subclasses, only default value seem to work after the first parameter:

Code:
>>> class MoreSpam(str):
    def __init__(self, data='', eggs=0):
        str.__init__(self, data)
        self.eggs = eggs


>>> test = MoreSpam('')
>>> test.eggs
0
>>> wtf = MoreSpam('', 10)
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    wtf = MoreSpam('', 10)
TypeError: str() argument 2 must be str, not int


It seems that for whatever reason, the __init__() function of the str subclasses is not re-defining the parameter list. Instead, Python looks straight at whatever is in the base class’s parameter list, namely two string parameters: the value of the string object itself and its encoding.

Am I getting this right? Shouldn’t this rightly be called a bug, or am I doing something completely different than I think I’m doing?
__________________
My armada: openSUSE 12.3 (home desktop, laptop, work desktop), Ubuntu 12.04 LTS (mini laptop), Debian GNU/Linux 7.0 (server), Mythbuntu 12.04 LTS (HTPC), Bodhi Linux 2.0 & Windows 7 Ultimate (test desktop), FreeBSD 9.1 (test server)

Reply With Quote
  #2  
Old December 4th, 2012, 12:54 PM
b49P23TIvg's Avatar
b49P23TIvg b49P23TIvg is offline
Contributing User
Dev Shed Loyal (3000 - 3499 posts)
 
Join Date: Aug 2011
Posts: 3,357 b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level) 
Time spent in forums: 1 Month 2 Weeks 3 Days 9 h 10 m 17 sec
Reputation Power: 383
looks like a bug to me!

Code:
>>> class c(tuple):
...  def __init__(s,a,b):
...   tuple.__init__(s,a)
...   self.b = b
...
>>> c(tuple(),666)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: tuple() takes at most 1 argument (2 given)

I guess you'll need to write some extra code to work around this. Affects my installations of python 2 and 3.
I'll report it to bugs.python.org
reported
__________________
[code]Code tags[/code] are essential for python code!

Reply With Quote
  #3  
Old December 4th, 2012, 01:47 PM
b49P23TIvg's Avatar
b49P23TIvg b49P23TIvg is offline
Contributing User
Dev Shed Loyal (3000 - 3499 posts)
 
Join Date: Aug 2011
Posts: 3,357 b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level)b49P23TIvg User rank is Major (30000 - 40000 Reputation Level) 
Time spent in forums: 1 Month 2 Weeks 3 Days 9 h 10 m 17 sec
Reputation Power: 383
I'm rebuffed at bugs.python.org.

You can't call __init__ on an immutable.

You'll need to use type or str.__new__ or object__new__ but I completely forget how to make this work.

Reply With Quote
  #4  
Old December 4th, 2012, 02:08 PM
SuperOscar SuperOscar is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2007
Location: Joensuu, Finland
Posts: 403 SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 5 h 1 m 25 sec
Reputation Power: 65
Quote:
Originally Posted by b49P23TIvg
I'm rebuffed at bugs.python.org.

You can't call __init__ on an immutable.

You'll need to use type or str.__new__ or object__new__ but I completely forget how to make this work.


Okay, looks like subclassing immutable objects isn’t so easy I guess I could revert to subclassing “object” and use a silly class variable like self.data to hold the string. Darn. The methods would like much nicer when I could be slicing just “self” instead of “self.data”.

Reply With Quote
  #5  
Old December 4th, 2012, 02:37 PM
Nyktos Nyktos is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Dec 2012
Posts: 75 Nyktos User rank is Corporal (100 - 500 Reputation Level)Nyktos User rank is Corporal (100 - 500 Reputation Level)Nyktos User rank is Corporal (100 - 500 Reputation Level)Nyktos User rank is Corporal (100 - 500 Reputation Level) 
Time spent in forums: 1 Day 3 h 5 m 40 sec
Reputation Power: 2
Quote:
Originally Posted by b49P23TIvg
You'll need to use type or str.__new__ or object__new__ but I completely forget how to make this work.

Code:
class MoreSpam(str):
    def __new__(cls, data='', eggs=0):
        return str.__new__(cls, data)

    def __init__(self, data='', eggs=0):
        self.eggs = eggs


Works just fine:
Code:
>>> test = MoreSpam('')
>>> test.eggs
0
>>> wtf = MoreSpam('', 10)
>>> wtf.eggs
10


Edit: You could also put everything into the __new__ method:
Code:
class MoreSpam(str):
    def __new__(cls, data='', eggs=0):
        spam =  str.__new__(cls, data)
        spam.eggs = eggs
        return spam
Comments on this post
b49P23TIvg agrees: Please post the object creation sequence. Thanks!

Reply With Quote
  #6  
Old December 5th, 2012, 02:48 AM
SuperOscar SuperOscar is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2007
Location: Joensuu, Finland
Posts: 403 SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level)SuperOscar User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 5 h 1 m 25 sec
Reputation Power: 65
Quote:
Originally Posted by Nyktos
Edit: You could also put everything into the __new__ method:
Code:
class MoreSpam(str):
    def __new__(cls, data='', eggs=0):
        spam =  str.__new__(cls, data)
        spam.eggs = eggs
        return spam


Nice! Although the necessity to “return” anything from __new__() seems strange to me but who cares if it works and doesn’t require much extra code lines.

Reply With Quote
Reply

Viewing: Dev Shed ForumsProgramming LanguagesPython Programming > Why can’t I subclass str (truly)

Developer Shed Advertisers and Affiliates



Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.

© 2003-2013 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap