Is there a way to override __format__ method - python

we know that :
str.format('{:+>10}', 'sometext')
will return :
'++sometext'
or :
'{:+>10}'.format('sometext') will return '++sometext'
my question, is there away to override format method of instance of a class.... i have try this:
class A:
def __format__(self, spec):
return spec.format(self)
then instantiate it :
a = A()
a.__format__('{:+>20}')
returning '+>20' how could this happen...
thanks before

In def __format__(self,spec):, spec is the format string itself. If you want to format the class using that spec, you need to specify it as a format to the content of the class instance in some way, such as:
class Value:
def __init__(self,value):
self.value = value
def __format__(self,fmt): # fmt='03' from below.
return f'Value({self.value:{fmt}})' # f'Value({self.value:03})' is evaluated.
v = Value(5)
print(f'{v:03}') # Python 3.6+
print('{:04}'.format(v)) # Python <3.6
Output:
Value(005)
Value(0005)

You could create a class like this which takes in an initial int value as the length. I tested in Python 3 and this works.
class Padded:
def __init__(self, length: int=10, pad='+'):
self.value = '{{:{}>{}}}'.format(pad, length)
def format(self, value):
return self.value.__format__(value)
a=Padded(20)
print(a.__format__('Sometext'))
#++++++++++++Sometext

Can override format this way (refered from python cookbook)
_formats = {
'ymd' : '{d.year}-{d.month}-{d.day}',
'mdy' : '{d.month}-{d.day}-{d.year}'
}
class Date:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
def __format__(self,code):
fmt = _formats[code]
return fmt.format(d=self) #passed self as instance to d (Note using this d in _formats to get the attribute)
d = Date(2021,8,23)
#format method can be called from either these 2 ways
print(d.__format__('ymd'))
print(format(d,'mdy'))
#output
2021-8-23
8-23-2021

Related

how do i return float type when class instantiate in python?

I'm looking for a way to return float when class instantiated, like this :
class SMA:
"""
Simple Moving Average
fomula :
sma = (a1+a2+a3+....) / n
"""
def __init__(self,data_feed,time_period=None):
self.data_feed = data_feed
if not time_period:
self.time_period = len(self.data_feed)
else:
self.time_period = time_period
self.sma = sum(self.data_feed) / self.time_period
def __repr__(self):
return repr(self.sma)
>>> b = SMA(data_feed=[1,2,3,4],time_period=4)
>>> print(type(b))
... float
but there is something wrong because 'b' has SMA type, not float
b is the object of the class SMA, that is why it returns its class type.
to return a float value create a function
class SMA:
def __init__(self,data_feed,time_period=None):
self.data_feed = data_feed
if not time_period:
self.time_period = len(self.data_feed)
else:
self.time_period = time_period
def get_value(self):
return sum(self.data_feed) / self.time_period
b = SMA(data_feed=[1,2,3,4],time_period=4)
type(b.get_value())
__repr__ returns a printable representation of the object.
Yours SMA() is constructor for SMA class, thus b variable being its objects.
For this type of operation i recommend reading about magic methods, dunder methods.
You may try overiding str(self).
Something like:
def __str__(self):
return str(self.sma)

Conditional method execution in a class instance

I want to create monad that is able to handle mathematical errors gracefully. I created something like:
from enum import Enum
class Monad(Enum):
Safe = 1
Fail = 2
class DivisionMonad:
def __init__(self, value=None, type=Monad.Safe):
self.value = value
self.type = type
def __truediv__(self, val):
if self.type == Monad.Fail:
return DivisionMonad(type=Monad.Fail)
try:
return DivisionMonad(self.value / val)
except:
return DivisionMonad(type=Monad.Fail)
def __repr__(self):
return f'< {self.value} >'
d = DivisionMonad(1)
d = d / 3
print(d.value)
print(d.type)
d = d / 0
print(d.value)
print(d.type)
But I believe this could be simpler by making the class use different methods based on the state of the Monad. Is there a way to create conditional execution of methods based on an instance attribute other than if/else statements?

Instantiating a subclass python

Just a simple class definition withh subclasses to show inheritance
import datetime
class LibaryItem: #The base class definition
def __init__(self, t, a, i): # initialiser method
self.__Title = t
self.__Author_Artist = a
self.__ItemID = i
self.__OnLoan = False
self.DueDate = datetime.date.today()
def GetTitle(self):
return(self.__Title)
# All other Get methods go here
def Borrowing(self):
self.__OnLoan = True
self.__DueDate = self.__DueDate + datetime.timedelta(weeks = 3)
def Returning(self):
self.OnLoan = False
def PrintDetails(self):
print(self.__Title, '; ', self.__Author_Artist,'; ',end='') # end='' Appends a space instead of a newline
print(self.__ItemID, '; ', self.__OnLoan,'; ', self.__DueDate)
class Book(LibaryItem):# A subclass definition
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
# This statement calls the constructor for the base class
self.__IsRequested = False
self.__RequestBy = 0
def GetIsRequested(self):
return(self.__IsRequested)
class CD(LibaryItem):
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
self.__Genre = ""
def GetGenre(self):
return(self.__Genre)
def SetGenre(self, g):
self.__Genre = g
Instantiating a subclass
ThisBook = Book('Title', 'Author', 'ItemID')
ThisCD = CD('Title', 'Author', 'ItemID')
This is my problem here I don't understand why the ThisBook the object's attribute doesn't change from False its default value to True.
# Using A method
print(ThisBook.GetIsRequested())
ThisBook.IsRequested = True
print(ThisBook.GetIsRequested())
Thank you a reason to why this doesn't work would be helpful
You probably meant to do
ThisBook.__IsRequested = True
which you can't do because of name mangling. You could write another setter.
But before you dive too deeply into writing a lot of getters and setters you should be aware that the pythonic way is to not use them. Or, if additional logic is required, to use the #property decorator.
class LibaryItem:
def __init__(self, title, author, itemid): # initialiser method
self.title = title
self.author = author
self.itemid = itemid
self._onloan = False
self.duedate = datetime.date.today()
#property
def onloan(self):
return self._onloan
#onloan.setter
def onloan(self, value):
if value:
self.duedate += datetime.timedelta(weeks = 3)
self._onloan = value
def __str__(self):
return "%s; %s; %s; %s; %s" % (self.title, self.author, self.itemid, self.onloan, self.duedate)
class Book(LibaryItem):
def __init__(self, title, author, itemid):
LibaryItem.__init__(self, title, author, itemid)
self.requested = False
self.requestby = 0
and then
ThisBook = Book('Title', 'Author', 'ItemID')
print(ThisBook.requested)
ThisBook.requested = True
ThisBook.onloan = True
print(ThisBook.duedate)
You can't access a field with 2 underscores prefix like that (see What is the meaning of a single- and a double-underscore before an object name?).
You need to write a proper setter:
def SetIsRequested(self, val):
self.__IsRequested = val
What you are experiencing is the typical silliness of dynamic languages. A field on class can be set w/o being declared and the interpreter can't help you by pointing out that you've just created a new field called "IsRequested" in your class. Saves you some typing but costs you in ability of your interpreter and IDE to prevent you from messing up.

Is there a way to auto generate a __str__() implementation in python?

Being tired manually implementing a string representation for my classes, I was wondering if there is a pythonic way to do that automatically.
I would like to have an output that covers all the attributes of the class and the class name. Here is an example:
class Foo(object):
attribute_1 = None
attribute_2 = None
def __init__(self, value_1, value_2):
self.attribute_1 = value_1
self.attribute_2 = value_2
Resulting in:
bar = Foo("baz", "ping")
print(str(bar)) # desired: Foo(attribute_1=baz, attribute_2=ping)
This question came to mind after using Project Lombok #ToString in some Java projects.
You can iterate instance attributes using vars, dir, ...:
def auto_str(cls):
def __str__(self):
return '%s(%s)' % (
type(self).__name__,
', '.join('%s=%s' % item for item in vars(self).items())
)
cls.__str__ = __str__
return cls
#auto_str
class Foo(object):
def __init__(self, value_1, value_2):
self.attribute_1 = value_1
self.attribute_2 = value_2
Applied:
>>> str(Foo('bar', 'ping'))
'Foo(attribute_2=ping, attribute_1=bar)'
wrote this while falsetru answerred.
Its the same idea, mine is very beginner friendly in terms of reading it, his is much nicer implemented imho
class stringMe(object):
def __str__(self):
attributes = dir(self)
res = self.__class__.__name__ + "("
first = True
for attr in attributes:
if attr.startswith("__") and attr.endswith("__"):
continue
if(first):
first = False
else:
res += ", "
res += attr + " = " + str( getattr(self, attr))
res += ")"
return res
class Foo(stringMe):
attribute_1 = None
attribute_2 = None
def __init__(self, value_1, value_2):
self.attribute_1 = value_1
self.attribute_2 = value_2
bar = Foo("baz", "ping")
print(str(bar)) # desired: Foo(attribute_1=baz, attribute_2=ping)
You can use #dataclass, which automatically generates __init__(), __repr__(), __str__(), and more. You just need to add a #dataclass decorator to your class and add type annotations to the members. You can even remove your __init__() implementation then.
from dataclasses import dataclass
#dataclass
class Foo(object):
attribute_1 : str
attribute_2 : str
bar = Foo("baz", "ping")
print(str(bar)) # Prints: Foo(attribute_1='baz', attribute_2='ping')

Python:How to print object key in a dictionary properly?

Say I have a Graph class and a Vertex class, defined as below
Graph.py
class Graph:
def __init__(self):
self.adjacencyList = {}
def __str__(self):
return str(self.adjacencyList)
def addVetex(self,key,value):
if Vertex(key,value) not in self.adjacencyList:
self.adjacencyList[Vertex(key,value)] = []
Vertex.py
class Vertex:
def __init__(self,key,value):
self.key = key
self.value = value
def __str__(self):
return "Key: ",str(self.key)," Value: ",str(self,value)
def __hash__(self):
return self.key
if I do this:
G = Graph()
G.addVetex(1,None)
G.addVetex(2,None)
G.addVetex(1,3)
print G
It print out {<Vertex.Vertex instance at 0x110295b90>: [], <Vertex.Vertex instance at 0x110295bd8>: []} But I am expecting something like {"Key:1 Value:None":[]...}
My question is what I am doing wrong? When a diction got print out, why it does not try to call the str function of its keys/values?
Thanks.
I believe the method you want to implement to get the string you want with your current code is Vertex.__repr__, which is what the python dictionary uses to get string representations of keys.
Here's a related stackoverflow answer that sheds some light on the difference between __repr__ and __str__
Joe's answer is correct, here is the tested version of the code:
def __repr__(self):
return "Key: "+str(self.key)+" Value: "+str(self.value)
to be implemented in Vertex. Also important is that a string is given back, not a tuple as in the question.
This will do it. Note the addition of the repr method (and a little cleanup of the str method).
class Vertex:
def __init__(self,key,value):
self.key = key
self.value = value
def __str__(self):
return "{Key: "+str(self.key)+" Value: "+str(self.value)+"}"
def __hash__(self):
return self.key
def __repr__(self):
return str(self)
You might consider subclassing a dict, though, for your vertex class. You get all the benefits of a dict but can add methods to suit your needs. The simplest version of this would look like:
class Vertex(dict):
pass
You can do smth like:
class Graph(object):
def __str__(self):
return ", ".join("Key: " + str(i.key) + " Value: " + str(i.value) for i in self.adjacencyList)

Categories

Resources