Example Needed: Change the Default Print Method of an Object

Example Needed: Change the default print method of an object

Here's an example to get you started. Once you get the basic idea of how S3 methods are dispatched, have a look at any of the print methods returned by methods("print") to see how you can achieve more interesting print styles.

## Define a print method that will be automatically dispatched when print()
## is called on an object of class "myMatrix"
print.myMatrix <- function(x) {
n <- nrow(x)
for(i in seq_len(n)) {
cat(paste("This is row", i, "\t: " ))
cat(x[i,], "\n")
}
}

## Make a couple of example matrices
m <- mm <- matrix(1:16, ncol=4)

## Create an object of class "myMatrix".
class(m) <- c("myMatrix", class(m))
## When typed at the command-line, the 'print' part of the read-eval-print loop
## will look at the object's class, and say "hey, I've got a method for you!"
m
# This is row 1 : 1 5 9 13
# This is row 2 : 2 6 10 14
# This is row 3 : 3 7 11 15
# This is row 4 : 4 8 12 16

## Alternatively, you can specify the print method yourself.
print.myMatrix(mm)
# This is row 1 : 1 5 9 13
# This is row 2 : 2 6 10 14
# This is row 3 : 3 7 11 15
# This is row 4 : 4 8 12 16

How to print instances of a class using print()?

>>> class Test:
... def __repr__(self):
... return "Test()"
... def __str__(self):
... return "member of Test"
...
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test

The __str__ method is what gets called happens when you print it, and the __repr__ method is what happens when you use the repr() function (or when you look at it with the interactive prompt).

If no __str__ method is given, Python will print the result of __repr__ instead. If you define __str__ but not __repr__, Python will use what you see above as the __repr__, but still use __str__ for printing.

How to create a println/print method for a custom class

You will need to override the toString method and return a string representation of what you want.

So for example:

public class Pair {

Object key;
Object value;

public Pair(Object k, Object v)
{
key = k;
value = v;
}

public Object getKey() {
return key;
}

public Object getValue() {
return value;
}

public String toString() {
return "Key: " + getKey() + ", Value: " + getValue();
}
}

Than you can do the following:

List<Pair> pairs = new ArrayList<Pair>();
pairs.Add(new Pair("pair1key", "pair1value"));
pairs.Add(new Pair("pair2key", "pair2value"));

for (Pair p : pairs) {
System.out.println(p);
}

How do I print my Java object without getting SomeType@2f92e0f4 ?

Background

All Java objects have a toString() method, which is invoked when you try to print the object.

System.out.println(myObject);  // invokes myObject.toString()

This method is defined in the Object class (the superclass of all Java objects). The Object.toString() method returns a fairly ugly looking string, composed of the name of the class, an @ symbol and the hashcode of the object in hexadecimal. The code for this looks like:

// Code of Object.toString()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

A result such as com.foo.MyType@2f92e0f4 can therefore be explained as:

  • com.foo.MyType - the name of the class, i.e. the class is MyType in the package com.foo.
  • @ - joins the string together
  • 2f92e0f4 the hashcode of the object.

The name of array classes look a little different, which is explained well in the Javadocs for Class.getName(). For instance, [Ljava.lang.String means:

  • [ - an single-dimensional array (as opposed to [[ or [[[ etc.)
  • L - the array contains a class or interface
  • java.lang.String - the type of objects in the array


Customizing the Output

To print something different when you call System.out.println(myObject), you must override the toString() method in your own class. Here's a simple example:

public class Person {

private String name;

// constructors and other methods omitted

@Override
public String toString() {
return name;
}
}

Now if we print a Person, we see their name rather than com.foo.Person@12345678.

Bear in mind that toString() is just one way for an object to be converted to a string. Typically this output should fully describe your object in a clear and concise manner. A better toString() for our Person class might be:

@Override
public String toString() {
return getClass().getSimpleName() + "[name=" + name + "]";
}

Which would print, e.g., Person[name=Henry]. That's a really useful piece of data for debugging/testing.

If you want to focus on just one aspect of your object or include a lot of jazzy formatting, you might be better to define a separate method instead, e.g. String toElegantReport() {...}.



Auto-generating the Output

Many IDEs offer support for auto-generating a toString() method, based on the fields in the class. See docs for Eclipse and IntelliJ, for example.

Several popular Java libraries offer this feature as well. Some examples include:

  • ToStringBuilder from Apache Commons Lang

  • MoreObjects.ToStringHelper from Google Guava

  • @ToString annotation from Project Lombok



Printing groups of objects

So you've created a nice toString() for your class. What happens if that class is placed into an array or a collection?

Arrays

If you have an array of objects, you can call Arrays.toString() to produce a simple representation of the contents of the array. For instance, consider this array of Person objects:

Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));

// Prints: [Fred, Mike]

Note: this is a call to a static method called toString() in the Arrays class, which is different to what we've been discussing above.

If you have a multi-dimensional array, you can use Arrays.deepToString() to achieve the same sort of output.

Collections

Most collections will produce a pretty output based on calling .toString() on every element.

List<Person> people = new ArrayList<>();
people.add(new Person("Alice"));
people.add(new Person("Bob"));
System.out.println(people);

// Prints [Alice, Bob]

So you just need to ensure your list elements define a nice toString() as discussed above.

What is the default print method of a class when called in a console?

For print x, x.__str__ is called.
For output in a REPL when an object is returned, x.__repr__ is called.

Read about str and repr functions.

Is there a built-in function to print all the current properties and values of an object?

You are really mixing together two different things.

Use dir(), vars() or the inspect module to get what you are interested in (I use __builtins__ as an example; you can use any object instead).

>>> l = dir(__builtins__)
>>> d = __builtins__.__dict__

Print that dictionary however fancy you like:

>>> print l
['ArithmeticError', 'AssertionError', 'AttributeError',...

or

>>> from pprint import pprint
>>> pprint(l)
['ArithmeticError',
'AssertionError',
'AttributeError',
'BaseException',
'DeprecationWarning',
...

>>> pprint(d, indent=2)
{ 'ArithmeticError': <type 'exceptions.ArithmeticError'>,
'AssertionError': <type 'exceptions.AssertionError'>,
'AttributeError': <type 'exceptions.AttributeError'>,
...
'_': [ 'ArithmeticError',
'AssertionError',
'AttributeError',
'BaseException',
'DeprecationWarning',
...

Pretty printing is also available in the interactive debugger as a command:

(Pdb) pp vars()
{'__builtins__': {'ArithmeticError': <type 'exceptions.ArithmeticError'>,
'AssertionError': <type 'exceptions.AssertionError'>,
'AttributeError': <type 'exceptions.AttributeError'>,
'BaseException': <type 'exceptions.BaseException'>,
'BufferError': <type 'exceptions.BufferError'>,
...
'zip': <built-in function zip>},
'__file__': 'pass.py',
'__name__': '__main__'}

Can I change the default __add__ method in Python?

If you are looking for information about how the C level built-ins are defined you would want to look at some of the source code, note that I'm linking specifically to floats but the structure exists for all number types:

static PyNumberMethods float_as_number = {
float_add, /* nb_add */
float_sub, /* nb_subtract */
float_mul, /* nb_multiply */

this is the structure for all the C function pointers that implement number methods, (for floats in this case) each builtin type that defines any number related methods will define a PyNumberMethods structure, this is then used in the formal definition of the type:

PyTypeObject PyFloat_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"float",
sizeof(PyFloatObject),

...

&float_as_number, /* tp_as_number */

the PyTypeObject represents all the relevant information needed to construct the float object in python, (or equivalently, int or str etc.) containing all the methods, attributes, and necessary meta-data to work as a python type. So if you really wanted to change adding floats to instead do another well defined task you'd just change it to point to the other function:

static PyNumberMethods float_as_number = {
float_sub, /* nb_add. overrides to do subtraction because I want to break everything >:D */
float_sub, /* nb_subtract */

If you wanted to write your own behaviour you could write your own function and point to it in this structure instead.

Can I replace an existing method of an object in Python?

Using some tips from:

Is it possible to change an instance's method implementation without changing all other instances of the same class?

you can do the following, by using the types module to assign a method to the object created without affecting the class. You need to do this because a function does not automatically receive the self object as the first variable, but a method does.

import types

joe = Person()
bob = Person()

joe.SayHi()
>>> Hello!

def greedy_has_good_mood(self):
return self.Cash > 100

joe.HasGoodMood = types.MethodType(greedy_has_good_mood, joe)

joe.SayHi()
>>> Hmpf.
bob.SayHi()

>>> Hello!

custom print statement for python function objects

Few errors:

>>> def f():
... pass
...
>>> g = f() <---- g is the return value of running f
>>> print g
None

in the first case, when you call print, you are calling a string representation of f

>>> f = F()
>>> print f <----- f is an instance of class F and
<----- print f tries to provide a suitable string representation
<----- by calling f.__str__

You should use doc strings for your motives

>>> def f():
... " some doc"
... pass
...
>>>
>>> f.__doc__
' some doc'
>>>

What you are trying to do is override the method wrapper __str__.

>>> def f():
... "some documentation .."
... pass
...
>>>
>>> f.__str__
<method-wrapper '__str__' of function object at 0x100430140>
>>>


Related Topics



Leave a reply



Submit