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')
Related
working through "Learning Python: Powerful Object-Oriented Programming'
chapter 28 has you create a class that will list all instance attributes of an object.
then the book offers some ideas, such as listing all attributes up the inheritance tree. when doing so, i used the #classmethod decorator shown below - and was wondering if there's a way to filter those types of methods out of my listing:
"""Assorted class utilities and tools"""
class ShowAttrs(object):
"""
A class to show all available (including inherited, excluding special) attributes
"""
#classmethod
def getAttrs(cls, child_cls):
my_attrs = [_ for _ in child_cls.__dict__ if _.startswith('_') is False]
my_name = child_cls.__name__
listed_attrs = [my_name + ': ' + ', '.join(my_attrs)]
try:
bases = child_cls.__bases__
inherited_attrs = []
for base in bases[::-1]:
if base.__name__ != 'ShowAttrs' and base.__name__ != 'object':
inherited_lists = [ShowAttrs.getAttrs(base)]
for _ in inherited_lists:
inherited_attrs.extend(_)
except NameError:
return
inherited_attrs.extend(listed_attrs)
return inherited_attrs
def __repr__(self):
child_cls = self.__class__
all_attrs = ShowAttrs.getAttrs(child_cls)
len_attrs = reversed(list(range(len(all_attrs))))
all_attrs_unique = [ x for i,x in zip(len_attrs,all_attrs[::-1]) if i <= all_attrs.index(x) ]
return '\n'.join(reversed(all_attrs_unique))
if __name__ == '__main__':
class Parent(ShowAttrs):
var3 = 'Parent'
def parentMethod(self):
print('this is a Parent')
class Child(Parent):
var2 = 'Child'
def childMethod(self):
print('this is a Child')
class GrandChild(Child):
var1 = 'GrandChild'
#classmethod
def howCanIFilterThisOneOut(cls):
pass
def grandchildMethod(self):
print('this is a GrandChild')
def grandchildMethod2(self):
pass
def grandchildMethod3(self):
pass
class GrandChild2(Child):
var11 = 'GrandChild2'
class GreatGrandChild(GrandChild, GrandChild2):
var0 = 'GreatGrandChild'
x = GreatGrandChild()
print(x)
when i run this:
Python 3
x = GreatGrandChild()
print(x)
Console
Parent: var3, parentMethod
Child: var2, childMethod
GrandChild2: var11
GrandChild: var1,howCanIFilterThisOneOut, grandchildMethod, grandchildMethod2, grandchildMethod3
GreatGrandChild: var0
but howCanIFilterThisOneOut is a classmethod, not an instance method. so just wondering if it's possible to differentiate.
thanks
sandbox to try it:
https://edube.org/sandbox/af4390bc-77aa-11ec-ab3f-0242157e55ca
isinstance(x, classmethod) does the trick.
my_attrs = [
name for (name, value)
in child_cls.__dict__.items()
if not name.startswith('_') and not isinstance(value, classmethod)
]
As an aside, your code could simplify, with duplicate removal and all, into something like
import inspect
def get_fields(cls):
seen = set()
for cls in inspect.getmro(cls)[::-1]:
if cls is object:
continue
attr_names = {
name
for name in cls.__dict__
if name not in seen and not name.startswith("_")
}
seen.update(attr_names)
yield (cls.__name__, sorted(attr_names))
I created a child class that extends a single parameter from the Parent to *args and yields the outputs. However, it looks cleaner with a decorator instead of writing for arg in self.args: yield in multiple methods.
# Parent class
class _greet:
def _hello(self,name):
return "hello " + name
def _hey(self,name):
return "hey " + name
# Child class
class Greet(_greet):
def __init__(self,*names):
self.names = names
def hello(self):
for name in self.names:
yield super()._hello(name)
def hey(self):
for name in self.names:
yield super()._hey(name)
Although, all of my tries generated an error, because the decorator cannot "find" self.args.
Edit:
The idea behind this is to get something like:
class Greet(_greet):
def __init__(self,*names):
self.names = names
#args(names)
def hello(self, var=name):
super()._hello(var)
Firstly, It would be perfect if you could extend your parent-class with desired behaviour.
Secondly, you should think over the meaning of behaviour extending. Functions _hello and hello are fundamentally different. _hello takes one additional arg and returns created output. hello takes no additional args and creates generator. So may be you don't need to create child class? May be you need to create absolutely independent class (or new function)? Also all your functions in _greet doesn't use self arg - may be they should be static (via #staticmethod)?
Thirdly, are you sure that you need exactly decorators? There are something like 10 idioms I know to emulate same behaviour. Some of them have better productivity, some of them require a small amount of code. Some works with multiple inheritance - some do not. The realisation you have presented (if I understand it correctly) looks like adapter pattern (with mistakes).
Here it is adapter solution:
from itertools import repeat
class Greet(object):
age = 666
#staticmethod
def hello(name):
return f'hello {name}'
#staticmethod
def hey(name):
return f'hey {name}'
def say_age(self, name):
return f'{name} is {self.age} years old'
def multiple_greet_adapter(adapter):
return lambda self: map(adapter, repeat(self), self.names)
class MultipleGreet0(Greet):
def __init__(self, *names):
self.names = names
#multiple_greet_adapter
def hello_many(self, name):
return super().hello(name)
hey_many = multiple_greet_adapter(lambda self, name: super().hey(name))
say_age_many = multiple_greet_adapter(lambda self, name: super().say_age(name))
One of the disadvantages of such implementation is that you still have to write many similar code. Also this not as productive as we want.
Approach 1 - less code, but not productive as well:
from functools import partial
class MultipleGreet1(Greet):
def __init__(self, *names):
self.names = names
_corresponding_names = dict(
hello_many = 'hello',
hey_many = 'hey',
say_age_many = 'say_age',
)
def __getattr__(self, attr_name):
try:
single_greet_handler = getattr(super(), self._corresponding_names[attr_name])
except KeyError:
raise AttributeError()
else:
return partial(map, single_greet_handler, self.names)
Approach 2 - the same, but with descriptors:
class ManyGreets(object):
def __init__(self, attr_name):
self._attr_name = attr_name
def __get__(self, owner_inst, owner_cls):
if owner_inst is None:
return self
else:
return partial(map, getattr(super(owner_cls, owner_inst), self._attr_name), owner_inst.names)
class MultipleGreet2(Greet):
def __init__(self, *names):
self.names = names
hello_many = ManyGreets('hello')
hey_many = ManyGreets('hey')
say_age_many = ManyGreets('say_age')
Approach 3 - a good way you can do if MultipleGreet is independent class:
def _create_many_greets(single_greet_handler, method=True):
if method:
return lambda self: map(single_greet_handler, repeat(self), self.names)
else:
return lambda self: map(single_greet_handler, self.names)
class MultipleGreet3(object):
def __init__(self, *names):
self.names = names
age = 123
hello_many = _create_many_greets(Greet.hello, False)
hey_many = _create_many_greets(Greet.hey, False)
say_age_many = _create_many_greets(Greet.say_age)
Approach 4 - the way I recommend if MultipleGreet depends on Greet:
class ManyGreetsCreator(object):
def __init__(self, attr_name):
self._attr_name = attr_name
def __set_name__(self, owner_cls, set_name):
attr_name = self._attr_name
many_greets = lambda s: map(getattr(super(owner_cls, s), attr_name), s.names)
setattr(owner_cls, set_name, many_greets)
class MultipleGreet4(Greet):
def __init__(self, *names):
self.names = names
hello_many = ManyGreetsCreator('hello')
hey_many = ManyGreetsCreator('hey')
say_age_many = ManyGreetsCreator('say_age')
Tests:
>>> mg0 = MultipleGreet0('Nick', 'John')
>>> mg1 = MultipleGreet1('Nick', 'John')
>>> mg2 = MultipleGreet2('Nick', 'John')
>>> mg3 = MultipleGreet3('Nick', 'John')
>>> mg4 = MultipleGreet4('Nick', 'John')
>>> list(mg4.hello_many())
['hello Nick', 'hello John']
>>> list(mg0.hello_many()) == list(mg1.hello_many()) == list(mg2.hello_many()) ==\
list(mg3.hello_many()) == list(mg4.hello_many())
True
>>> list(mg0.say_age_many()) == list(mg1.say_age_many()) == list(mg2.say_age_many()) ==\
list(mg4.say_age_many())
True
>>> list(mg4.say_age_many())
['Nick is 666 years old', 'John is 666 years old']
>>> list(mg3.say_age_many())
['Nick is 123 years old', 'John is 123 years old']
You can read more about descriptors, about __getattr__, about super-class. There are also approaches based on __init_subclass__
I want to have simple representation of any class, like { property = value }, is there auto __repr__?
Simplest way:
def __repr__(self):
return str(self.__dict__)
Yes, you can make a class "AutoRepr" and let all other classes extend it:
>>> class AutoRepr(object):
... def __repr__(self):
... items = ("%s = %r" % (k, v) for k, v in self.__dict__.items())
... return "<%s: {%s}>" % (self.__class__.__name__, ', '.join(items))
...
>>> class AnyOtherClass(AutoRepr):
... def __init__(self):
... self.foo = 'foo'
... self.bar = 'bar'
...
>>> repr(AnyOtherClass())
"<AnyOtherClass: {foo = 'foo', bar = 'bar'}>"
Note that the above code will not act nicely on data structures that (either directly or indirectly) reference themselves. As an alternative, you can define a function that works on any type:
>>> def autoRepr(obj):
... try:
... items = ("%s = %r" % (k, v) for k, v in obj.__dict__.items())
... return "<%s: {%s}." % (obj.__class__.__name__, ', '.join(items))
... except AttributeError:
... return repr(obj)
...
>>> class AnyOtherClass(object):
... def __init__(self):
... self.foo = 'foo'
... self.bar = 'bar'
...
>>> autoRepr(AnyOtherClass())
"<AnyOtherClass: {foo = 'foo', bar = 'bar'}>"
>>> autoRepr(7)
'7'
>>> autoRepr(None)
'None'
Note that the above function is not defined recursively, on purpose, for the reason mentioned earlier.
Well, I played a little bit with other answers and got a very pretty solution:
class data:
#staticmethod
def repr(obj):
items = []
for prop, value in obj.__dict__.items():
try:
item = "%s = %r" % (prop, value)
assert len(item) < 20
except:
item = "%s: <%s>" % (prop, value.__class__.__name__)
items.append(item)
return "%s(%s)" % (obj.__class__.__name__, ', '.join(items))
def __init__(self, cls):
cls.__repr__ = data.repr
self.cls = cls
def __call__(self, *args, **kwargs):
return self.cls(*args, **kwargs)
You use it as a decorator:
#data
class PythonBean:
def __init__(self):
self.int = 1
self.list = [5, 6, 7]
self.str = "hello"
self.obj = SomeOtherClass()
and get a smart __repr__ out of the box:
PythonBean(int = 1, obj: <SomeOtherClass>, list = [5, 6, 7], str = 'hello')
This works with any recursive classes, including tree structures. If you try to put a self-reference in the class self.ref = self, the function will try (successfully) to work it out for about a second.
Of course, always mind your boss - mine would not like such a syntax sugar ))
Do you mean
__dict__
?
class MyClass:
def __init__(self, foo: str, bar: int):
self.foo = foo
self.bar = bar
self._baz: bool = True
def __repr__(self):
f"{self.__class__.__name__}({', '.join([f'{k}={v!r}' for k, v in self.__dict__.items() if not k.startswith('_')])})"
mc = MyClass('a', 99)
print(mc)
# MyClass(foo='a', bar=99)
# ^^^ Note that _baz=True was hidden here
I use this helper function to generate repr s for my classes. It is easy to run in a unittest function, ie.
def test_makeRepr(self):
makeRepr(Foo, Foo(), "anOptional space delimitedString ToProvideCustom Fields")
this should output a number of potential repr to the console, that you can then copy/paste into your class.
def makeRepr(classObj, instance = None, customFields = None):
"""Code writing helper function that will generate a __repr__ function that can be copy/pasted into a class definition.
Args:
classObj (class):
instance (class):
customFields (string):
Returns:
None:
Always call the __repr__ function afterwards to ensure expected output.
ie. print(foo)
def __repr__(self):
msg = "<Foo(var1 = {}, var2 = {})>"
attributes = [self.var1, self.var2]
return msg.format(*attributes)
"""
if isinstance(instance, classObj):
className = instance.__class__.__name__
else:
className=classObj.__name__
print('Generating a __repr__ function for: ', className,"\n")
print("\tClass Type: "+classObj.__name__, "has the following fields:")
print("\t"+" ".join(classObj.__dict__.keys()),"\n")
if instance:
print("\tInstance of: "+instance.__class__.__name__, "has the following fields:")
print("\t"+" ".join(instance.__dict__.keys()),"\n")
else:
print('\tInstance of: Instance not provided.\n')
if customFields:
print("\t"+"These fields were provided to makeRepr:")
print("\t"+customFields,"\n")
else:
print("\t"+"These fields were provided to makeRepr: None\n")
print("Edit the list of fields, and rerun makeRepr with the new list if necessary.\n\n")
print("repr with class type:\n")
classResult = buildRepr( classObj.__name__, " ".join(classObj.__dict__.keys()))
print(classResult,"\n\n")
if isinstance(instance, classObj):
instanceResult = buildRepr( instance.__class__.__name__, " ".join(instance.__dict__.keys()))
else:
instanceResult = "\t-----Instance not provided."
print("repr with instance of class:\n")
print(instanceResult,"\n\n")
if customFields:
customResult = buildRepr( classObj.__name__, customFields)
else:
customResult = '\t-----Custom fields not provided'
print("repr with custom fields and class name:\n")
print(customResult,"\n\n")
print('Current __repr__')
print("Class Object: ",classObj)
if instance:
print("Instance: ",instance.__repr__())
else:
print("Instance: ", "None")
def buildRepr(typeName,fields):
funcDefLine = "def __repr__(self):"
msgLineBase = ' msg = "<{typename}({attribute})>"'
attributeListLineBase = ' attributes = [{attributeList}]'
returnLine = ' return msg.format(*attributes)'
x = ['self.' + x for x in fields.split()]
xResult = ", ".join(x)
y = [x + ' = {}' for x in fields.split()]
yResult = ', '.join(y)
msgLine = msgLineBase.format(typename = typeName, attribute = yResult)
attributeListLine = attributeListLineBase.format(attributeList = xResult)
result = "{declaration}\n{message}\n{attributes}\n{returnLine}".format(declaration = funcDefLine,
message = msgLine,
attributes = attributeListLine,
returnLine =returnLine )
return result
To make #uzi's answer clearer, I have included more sample code. This is handy for a quick and dirty script:
class MyClass:
def __repr__(self):
return "MyClass:" + str(self.__dict__)
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.
I want to have simple representation of any class, like { property = value }, is there auto __repr__?
Simplest way:
def __repr__(self):
return str(self.__dict__)
Yes, you can make a class "AutoRepr" and let all other classes extend it:
>>> class AutoRepr(object):
... def __repr__(self):
... items = ("%s = %r" % (k, v) for k, v in self.__dict__.items())
... return "<%s: {%s}>" % (self.__class__.__name__, ', '.join(items))
...
>>> class AnyOtherClass(AutoRepr):
... def __init__(self):
... self.foo = 'foo'
... self.bar = 'bar'
...
>>> repr(AnyOtherClass())
"<AnyOtherClass: {foo = 'foo', bar = 'bar'}>"
Note that the above code will not act nicely on data structures that (either directly or indirectly) reference themselves. As an alternative, you can define a function that works on any type:
>>> def autoRepr(obj):
... try:
... items = ("%s = %r" % (k, v) for k, v in obj.__dict__.items())
... return "<%s: {%s}." % (obj.__class__.__name__, ', '.join(items))
... except AttributeError:
... return repr(obj)
...
>>> class AnyOtherClass(object):
... def __init__(self):
... self.foo = 'foo'
... self.bar = 'bar'
...
>>> autoRepr(AnyOtherClass())
"<AnyOtherClass: {foo = 'foo', bar = 'bar'}>"
>>> autoRepr(7)
'7'
>>> autoRepr(None)
'None'
Note that the above function is not defined recursively, on purpose, for the reason mentioned earlier.
Well, I played a little bit with other answers and got a very pretty solution:
class data:
#staticmethod
def repr(obj):
items = []
for prop, value in obj.__dict__.items():
try:
item = "%s = %r" % (prop, value)
assert len(item) < 20
except:
item = "%s: <%s>" % (prop, value.__class__.__name__)
items.append(item)
return "%s(%s)" % (obj.__class__.__name__, ', '.join(items))
def __init__(self, cls):
cls.__repr__ = data.repr
self.cls = cls
def __call__(self, *args, **kwargs):
return self.cls(*args, **kwargs)
You use it as a decorator:
#data
class PythonBean:
def __init__(self):
self.int = 1
self.list = [5, 6, 7]
self.str = "hello"
self.obj = SomeOtherClass()
and get a smart __repr__ out of the box:
PythonBean(int = 1, obj: <SomeOtherClass>, list = [5, 6, 7], str = 'hello')
This works with any recursive classes, including tree structures. If you try to put a self-reference in the class self.ref = self, the function will try (successfully) to work it out for about a second.
Of course, always mind your boss - mine would not like such a syntax sugar ))
Do you mean
__dict__
?
class MyClass:
def __init__(self, foo: str, bar: int):
self.foo = foo
self.bar = bar
self._baz: bool = True
def __repr__(self):
f"{self.__class__.__name__}({', '.join([f'{k}={v!r}' for k, v in self.__dict__.items() if not k.startswith('_')])})"
mc = MyClass('a', 99)
print(mc)
# MyClass(foo='a', bar=99)
# ^^^ Note that _baz=True was hidden here
I use this helper function to generate repr s for my classes. It is easy to run in a unittest function, ie.
def test_makeRepr(self):
makeRepr(Foo, Foo(), "anOptional space delimitedString ToProvideCustom Fields")
this should output a number of potential repr to the console, that you can then copy/paste into your class.
def makeRepr(classObj, instance = None, customFields = None):
"""Code writing helper function that will generate a __repr__ function that can be copy/pasted into a class definition.
Args:
classObj (class):
instance (class):
customFields (string):
Returns:
None:
Always call the __repr__ function afterwards to ensure expected output.
ie. print(foo)
def __repr__(self):
msg = "<Foo(var1 = {}, var2 = {})>"
attributes = [self.var1, self.var2]
return msg.format(*attributes)
"""
if isinstance(instance, classObj):
className = instance.__class__.__name__
else:
className=classObj.__name__
print('Generating a __repr__ function for: ', className,"\n")
print("\tClass Type: "+classObj.__name__, "has the following fields:")
print("\t"+" ".join(classObj.__dict__.keys()),"\n")
if instance:
print("\tInstance of: "+instance.__class__.__name__, "has the following fields:")
print("\t"+" ".join(instance.__dict__.keys()),"\n")
else:
print('\tInstance of: Instance not provided.\n')
if customFields:
print("\t"+"These fields were provided to makeRepr:")
print("\t"+customFields,"\n")
else:
print("\t"+"These fields were provided to makeRepr: None\n")
print("Edit the list of fields, and rerun makeRepr with the new list if necessary.\n\n")
print("repr with class type:\n")
classResult = buildRepr( classObj.__name__, " ".join(classObj.__dict__.keys()))
print(classResult,"\n\n")
if isinstance(instance, classObj):
instanceResult = buildRepr( instance.__class__.__name__, " ".join(instance.__dict__.keys()))
else:
instanceResult = "\t-----Instance not provided."
print("repr with instance of class:\n")
print(instanceResult,"\n\n")
if customFields:
customResult = buildRepr( classObj.__name__, customFields)
else:
customResult = '\t-----Custom fields not provided'
print("repr with custom fields and class name:\n")
print(customResult,"\n\n")
print('Current __repr__')
print("Class Object: ",classObj)
if instance:
print("Instance: ",instance.__repr__())
else:
print("Instance: ", "None")
def buildRepr(typeName,fields):
funcDefLine = "def __repr__(self):"
msgLineBase = ' msg = "<{typename}({attribute})>"'
attributeListLineBase = ' attributes = [{attributeList}]'
returnLine = ' return msg.format(*attributes)'
x = ['self.' + x for x in fields.split()]
xResult = ", ".join(x)
y = [x + ' = {}' for x in fields.split()]
yResult = ', '.join(y)
msgLine = msgLineBase.format(typename = typeName, attribute = yResult)
attributeListLine = attributeListLineBase.format(attributeList = xResult)
result = "{declaration}\n{message}\n{attributes}\n{returnLine}".format(declaration = funcDefLine,
message = msgLine,
attributes = attributeListLine,
returnLine =returnLine )
return result
To make #uzi's answer clearer, I have included more sample code. This is handy for a quick and dirty script:
class MyClass:
def __repr__(self):
return "MyClass:" + str(self.__dict__)