Comments:"Fixing Python's String class"
URL:http://pydanny.com/fixing-pythons-string-class.html
Monday, April 01, 2013 (permalink)
Ever wonder why Python's str or unicode types lack obvious length methods? Yes, we can get the length via the special __len__() method, but instead as Python developers we get the so-called 'luxury' of discovering length via the Python's built-in len() function. So instead of calling the length of objects the way Rubyists or Javascripters do...
>># ruby>>s="Hello, World!"=>"Hello, World!">>s.length13
// javascriptvars="Hello, world!"console.log(s.length)13
...as Python developers we suffer through it like this:
>>># python>>>s="Hello, World!">>>len(s)13>>>s.__len__()# This is what len() calls to get the length13
I'm sure Python luminaries like Guido Van Rossum, Alex Gaynor, David Beazley, and Raymond Hettiger can explain why Python works this way. Their opinions are probably full of logic, history, and grand reasoning.
None of that applies to this blog post.
Fixing the String Class
Clearly, it's time for Python to catch up with the other hip dynamic languages. Therefore, after years of careful study, I give you a Fixed String class.
classString(str):""" Adding critically unimportant functionality to Python's str type """deflen(self):returnself.__len__()
As you can see it improves on Python's str type by adding a built-in len() method. Total success!
Improving the String Class
Now that I've fixed things in Python by creating the String class, it's time to improve it. Ruby and Javascript both have a length property/attribute/method/thingee that even my String class lacks. Ruby's String object even beats up Javascript's String Prototype by including a handy size method that serves as an alias for it's own length method.
Fortunately, I come armed with the knowledge of how to use Python's property decorator:
classString(str):""" Adding critically unimportant functionality to Python's str type """deflen(self):returnself.__len__()@propertydeflength(self):returnself.len()@propertydefsize(self):returnself.length
Bam! Python is now equal to Ruby!
Winning with the String Class
It's time for Python to take the lead. We've suffered for too long as second class citizens in terms of string length discovery. Let's add some more utility methods to our String class:
classString(str):""" Adding critically unimportant functionality to Python's str type """deflen(self):returnself.__len__()@propertydeflength(self):returnself.len()@propertydefsize(self):returnself.length@propertydefwidth(self):returnself.length@propertydefheight(self):returnself.length@propertydefarea(self):returnself.height*self.width
Boom! Python now dominates with invaluable properties that provide developers with the width, height, and area of a string. And to think I'm just getting started...
Conquering with the String Class
So far I've carefully changed the Python ecosystem with my brilliant addition to the language. What if I want to get stupidly dangerous? What if I want to allow developers the dangerous capability to alter the returned length of a String? Fortunately for me, and unfortunately for anyone who uses this code on a real project, I know how to be this stupidly dangerous.
I've present to you the ConqueringString class:
importmathclassConqueringString(String):""" Adding stupidly dangerous functionality to Python's str type """def__init__(self,text):super(ConqueringString,self).__init__(text)self._length=self.__len__()def__len__(self):try:returnself._lengthexceptAttributeError:returnsuper(ConqueringString,self).__len__()deflen(self,value=None):ifvalueisNone:returnself._lengthself._length=value@propertydeflength(self):returnself.len()@length.setterdeflength(self,value):self._length=value@propertydefsize(self):returnself.length@size.setterdefsize(self,value):self.length=value@propertydefarea(self):returnself.height*self.width@area.setterdefarea(self,value):self.length=math.sqrt(value)
Does it work?
if__name__=="__main__":s=ConqueringString("Hello, World!")print(s)print(s.length)s.length=5print(s.length)print(s.area)s.area=50print(s.area)print(len(s))print(s[5:10])# slicing still works!print(s.upper())# other methods still work!
Run it and see. Or grab it off PyPI with pip install stringtheory.
Summary
Don't forget pip install stringtheory!
We can implement this power using Python lists, tuples, dictionaries, and everything else we can imagine. Let's do it!
Resources: