* mpzmodule.c: removed redundant mpz_print function.
* object.[ch], bltinmodule.c, fileobject.c: changed str() to call
  strobject() which calls an object's __str__ method if it has one.
  strobject() is also called by writeobject() when PRINT_RAW is passed.
* ceval.c: rationalize code for PRINT_ITEM (no change in function!)
* funcobject.c, codeobject.c: added compare and hash functionality.
  Functions with identical code objects and the same global dictionary are
  equal.  Code objects are equal when their code, constants list and names
  list are identical (i.e. the filename and code name don't count).
  (hash doesn't work yet since the constants are in a list and lists can't
  be hashed -- suppose this should really be done with a tuple now we have
  resizetuple!)
diff --git a/Include/object.h b/Include/object.h
index ab270f8..24989bf 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -214,6 +214,7 @@
 /* Generic operations on objects */
 extern int printobject PROTO((object *, FILE *, int));
 extern object * reprobject PROTO((object *));
+extern object * strobject PROTO((object *));
 extern int cmpobject PROTO((object *, object *));
 extern object *getattr PROTO((object *, char *));
 extern int hasattr PROTO((object *, char *));
diff --git a/Modules/mpzmodule.c b/Modules/mpzmodule.c
index a3e903e..5ff0801 100644
--- a/Modules/mpzmodule.c
+++ b/Modules/mpzmodule.c
@@ -265,24 +265,6 @@
 	DEL(mpzp);
 } /* mpz_dealloc() */
 
-/* ARGSUSED */
-static int
-mpz_print(v, fp, flags)
-	object *v;
-	FILE *fp;
-	int flags; /* Not used but required by interface */
-{
-	stringobject *str
-		= (stringobject *)mpz_format(v, 10, (unsigned char)1);
-
-	if (str == NULL)
-		return -1;
-
-	fputs(GETSTRINGVALUE(str), fp);
-	DECREF(str);
-	return 0;
-} /* mpz_print() */
-
 
 /* pointers to frequently used values 0, 1 and -1 */
 static mpzobject *mpz_value_zero, *mpz_value_one, *mpz_value_mone;
@@ -1658,7 +1640,7 @@
 	0,			/*tp_itemsize*/
 	/* methods */
 	mpz_dealloc,	/*tp_dealloc*/
-	mpz_print,	/*tp_print*/
+	0,		/*tp_print*/
 	mpz_getattr,	/*tp_getattr*/
 	0,		/*tp_setattr*/
 	mpz_compare,	/*tp_compare*/
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 7ed4fcd..518fe04 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -680,16 +680,13 @@
 	writer = getattr(f, "write");
 	if (writer == NULL)
 		return -1;
-	if ((flags & PRINT_RAW) && is_stringobject(v)) {
-		value = v;
-		INCREF(value);
-	}
-	else {
+	if (flags & PRINT_RAW)
+		value = strobject(v);
+	else
 		value = reprobject(v);
-		if (value == NULL) {
-			DECREF(writer);
-			return -1;
-		}
+	if (value == NULL) {
+		DECREF(writer);
+		return -1;
 	}
 	result = call_object(writer, value);
 	DECREF(writer);
diff --git a/Objects/object.c b/Objects/object.c
index 73fba50..7a7383e 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -124,7 +124,11 @@
 					op->ob_type->tp_name, (long)op);
 			}
 			else {
-				object *s = reprobject(op);
+				object *s;
+				if (flags & PRINT_RAW)
+					s = strobject(op);
+				else
+					s = reprobject(op);
 				if (s == NULL)
 					ret = -1;
 				else if (!is_stringobject(s)) {
@@ -171,6 +175,36 @@
 		return (*v->ob_type->tp_repr)(v);
 }
 
+object *
+strobject(v)
+	object *v;
+{
+	if (v == NULL)
+		return newstringobject("<NULL>");
+	if (is_stringobject(v)) {
+		INCREF(v);
+		return v;
+	}
+	else {
+		object *func = getattr(v, "__str__");
+		object *args;
+		object *res;
+		if (func == NULL) {
+			err_clear();
+			return reprobject(v);
+		}
+		args = newtupleobject(0);
+		if (args == NULL)
+			res = NULL;
+		else {
+			res = call_object(func, args);
+			DECREF(args);
+		}
+		DECREF(func);
+		return res;
+	}
+}
+
 int
 cmpobject(v, w)
 	object *v, *w;
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 9210bd1..97ed2f4 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1096,12 +1096,7 @@
 		err_badarg();
 		return NULL;
 	}
-	if (is_stringobject(v)) {
-		INCREF(v);
-		return v;
-	}
-	else
-		return reprobject(v);
+	return strobject(v);
 }
 
 static object *
diff --git a/Python/ceval.c b/Python/ceval.c
index 324ecdf..425e2a0 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -38,6 +38,8 @@
 #include "graminit.h"
 #include "pythonrun.h"
 
+#include <ctype.h>
+
 /* Turn this on if your compiler chokes on the big switch: */
 /* #define CASE_TOO_BIG 1  	/**/
 
@@ -660,16 +662,15 @@
 			w = sysget("stdout");
 			if (softspace(w, 1))
 				writestring(" ", w);
-			if (is_stringobject(v)) {
+			err = writeobject(v, w, PRINT_RAW);
+			if (err == 0 && is_stringobject(v)) {
+				/* XXX move into writeobject() ? */
 				char *s = getstringvalue(v);
 				int len = getstringsize(v);
-				err = writeobject(v, w, PRINT_RAW);
-				if (err == 0 && len > 0 && s[len-1] == '\n')
+				if (len > 0 && isspace(s[len-1]) &&
+				    s[len-1] != ' ')
 					softspace(w, 0);
 			}
-			else {
-				err = writeobject(v, w, 0);
-			}
 			DECREF(v);
 			break;