Gdb Pretty Printer: *(char*){hex_address} equivalent in python - gdb-python

I have C++ classes in following format (copying just important parts):
class my_stringimpl {
public:
static sample_string* create(const char* str, int len) {
my_stringimpl* sample = static_cast<my_stringimpl*>(malloc(sizeof(my_stringimpl) + len*sizeof(char)));
char* data_ptr = reinterpret_cast<char*>(sample+1);
memset(data_ptr, 0, len);
memcpy(data_ptr, str, len);
return new (sample) my_stringimpl(len);
}
private:
int m_length;
};
class my_string {
public:
my_string(const char* str, int len)
: m_impl(my_stringimpl::create(str, len)) { }
~my_string() {
delete m_impl;
}
private:
my_stringimpl* m_impl;
};
For this my_string class I am adding pretty printer. I added the following defs in a python script (which I am including in my .gdbinit file) - just func defs copied here:
def string_to_char(ptr, length=None):
error_message = ''
if length is None:
length = int(0)
error_message = 'null string'
else:
length = int(length)
string = ''.join([chr((ptr + i).dereference()) for i in xrange(length)])
return string + error_message
class StringPrinter(object):
def __init__(self, val):
self.val = val
class StringImplPrinter(StringPrinter):
def get_length(self):
return self.val['m_length']
def get_data_address(self):
return self.val.address + 1
def to_string(self):
return string_to_char(self.get_data_address(), self.get_length())
class MyStringPrinter(StringPrinter):
def stringimpl_ptr(self):
return self.val['m_impl']
def get_length(self):
if not self.stringimpl_ptr():
return 0
return StringImplPrinter(self.stringimpl_ptr().dereference()).get_length()
def to_string(self):
if not self.stringimpl_ptr():
return '(null)'
return StringImplPrinter(self.stringimpl_ptr().dereference()).to_string()
But, on usage I am getting the below error -
Python Exception <class 'gdb.error'> Cannot convert value to int.:
If I try to change the value in 'ptr' to int and then do the arthimetic before casting back to char (like in def above), it gives below error:
Python Exception <type 'exceptions.AttributeError'> 'NoneType' object has no attribute 'cast':
Can anybody tell what is that I am doing wrong? I am really struck here. :(. In nutshell, I am trying to achieve the following c/c++ expr equivalent,
*(char*){hex_address}
in python. How can I do it?

It's better to post full stack traces or at least to indicate exactly which lines throws the exception. Python provides this...
Your string_to_char function can be replaced by Value.string or Value.lazy_string, which were designed for exactly this use. I imagine the error is coming from there; in which case this ought to remove it.
Also, your printers should implement "hint" methods that return "string".

Related

Registering a gdb pretty-printer for a specialization of std::unordered_map

I'm trying to register a pretty-printer for a specific specialization of std::unordered_map, but for some reason it always uses the standard pretty-printer for std::unordered_map in gdb instead of my specialized version.
Consider the following class
namespace ns {
class MyClass {
public:
std::string name;
int value = 0;
};
} // namespace ns
I have a gdb pretty-printer defined for it as
# myprinters.py -> sourced in gdb
class MyClassPrinter:
def __init__(self, val):
self.name = val["name"]
self.val = val["value"]
def to_string(self):
return f"MyClass(name={self.name}, value={self.val})"
import gdb.printing
pp = gdb.printing.RegexpCollectionPrettyPrinter('myprinters')
pp.add_printer('MyClass', 'MyClass', MyClassPrinter)
gdb.printing.register_pretty_printer(gdb.current_objfile(), pp, replace=True)
Now consider the main function below
int main(int argc, char *argv[]) {
std::tuple<int, MyClass> mytuple{10, {"name10", 10}};
std::unordered_map<int, MyClass> mymap;
mymap.insert({10, {"name10", 10}});
mymap.insert({15, {"name15", 15}});
mymap.insert({25, {"name25", 25}});
auto myobj = MyClass{"name5", 5};
std::unordered_map<int, MyClass *> mymap2;
mymap2.insert({10, new MyClass{"name10", 10}}); // don't worry about the new
mymap2.insert({15, new MyClass{"name15", 15}});
mymap2.insert({25, new MyClass{"name25", 25}});
std::cout << "The end" << std::endl;
return 0;
}
If a add a breakpoint in the cout line and print myobjI get $7 = MyClass(name="name5", value=5) as expected. Printing mytuple and mymap also works, since gdb has pretty-printers for the containers in STL. We get something like
$8 = std::tuple containing = {
[1] = 10,
[2] = MyClass(name="name10", value=10)
}
$9 = std::unordered_map with 3 elements = {
[25] = MyClass(name="name25", value=25),
[15] = MyClass(name="name15", value=15),
[10] = MyClass(name="name10", value=10)
}
However, what I actually have are containers with MyClass* and not MyClass, such as the mymap2 variable. Printing that results in
$10 = std::unordered_map with 3 elements = {
[25] = 0x555555576760,
[15] = 0x555555576710,
[10] = 0x555555576650
}
which is not very useful.
For my particular needs, I only need the "name" field of each MyClass object pointed in mymap2. Then I created a pretty-printer for std::unordered_map<int, MyClass *>, but I'm not able to register it correctly (maybe the version for just std::unordered_map is taking precedence, but I could not correctly disable to test this hypothesis. I get an error when I try to disable the pretty-printer as suggested in this question).
I tried with
class MyUnorderedMapOfMyClassPrinter:
def __init__(self, val):
self.val = val
def to_string(self):
return "MyUnorderedMapOfMyClassPrinter"
and then added the line below to the python script defining my pretty-printers
pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<int, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
to include the new pretty-printer.
But printing the unordered_map does not use my pretty-printer. It still uses the regular std::unordered_map pretty-printer from gdb.
If I do create a new type like
class MyUnorderedMap : public std::unordered_map<int, MyClass *> {};
and register a pretty-printer for MyUnorderedMap then it works. But I don't want to create another type just to be able to register a pretty-printer.
How can I register a pretty-printer for a specific specialization of std::unordered_map?
Edit:
I could not disable only the std::unordered_map pretty-printer, but
I disabled all pretty-printers with disable pretty-printer in gdb, and then enabled only my pretty-printers with enable pretty-printer global myprinters. This allowed me try the regexp to register my pretty-printer and to make it work for a std::unordered_map specialization with with pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<.*, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter) (note the "*" at the end, since I only want it to work for MyClass pointers).
Interesting, pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<int, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
did not work. I had to use .* instead of intto make it work for some reason.
However, when all pretty-printers are enabled the standard std::unordered_map pretty printer still takes precedence over my specialization. How can I make my pretty-printer takes precedence?
For making things easily reproducible, here is the full main.cpp file
#include <iostream>
#include <string>
#include <tuple>
#include <unordered_map>
namespace ns {
class MyClass {
public:
std::string name;
int value = 0;
};
} // namespace ns
using namespace ns;
int main(int argc, char *argv[]) {
std::tuple<int, MyClass> mytuple{10, {"name10", 10}};
std::unordered_map<int, MyClass> mymap;
mymap.insert({10, {"name10", 10}});
mymap.insert({15, {"name15", 15}});
mymap.insert({25, {"name25", 25}});
auto myobj = MyClass{"name5", 5};
std::unordered_map<int, MyClass *> mymap2;
mymap2.insert({10, new MyClass{"name10", 10}});
mymap2.insert({15, new MyClass{"name15", 15}});
mymap2.insert({25, new MyClass{"name25", 25}});
std::cout << "The end" << std::endl;
return 0;
}
and the full myprinters.py file defining the pretty-printers
class MyClassPrinter:
def __init__(self, val):
self.name = str(val["name"])
self.val = val["value"]
def to_string(self):
return f"MyClass(name={self.name}, value={self.val})"
class MyClassPointerPrinter:
def __init__(self, val):
self.ptr = val
self.name = str(val.dereference()["name"])
self.val = val.dereference()["value"]
def to_string(self):
return f"Pointer to MyClass(name={self.name}, value={self.val})"
class MyUnorderedMapOfMyClassPrinter:
def __init__(self, val):
self.val = val
def to_string(self):
return "MyUnorderedMapOfMyClassPrinter"
import gdb.printing
pp = gdb.printing.RegexpCollectionPrettyPrinter('myprinters')
pp.add_printer('MyClass', '^ns::MyClass$', MyClassPrinter)
# pp.add_printer('MyClass', 'MyClass\*', MyClassPointerPrinter)
# pp.add_printer('MyClass', 'MyClass.?\*', MyClassPointerPrinter)
# pp.add_printer('MyClass', 'MyClass \*', MyClassPointerPrinter)
pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<.*, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
gdb.printing.register_pretty_printer(gdb.current_objfile(), pp, replace=True)
def my_pp_func(val):
if str(val.type) == "ns::MyClass *":
return MyClassPointerPrinter(val)
gdb.pretty_printers.append(my_pp_func)
After more investigation and comments in the question from "n. 'pronouns' m.", I was able to solve the problem, although the question is still technically not solved.
In summary, with
class MyUnorderedMapOfMyClassPrinter:
def __init__(self, val):
self.val = val
def to_string(self):
return "MyUnorderedMapOfMyClassPrinter"
import gdb.printing
pp = gdb.printing.RegexpCollectionPrettyPrinter('myprinters')
pp.add_printer('MyClass', '^ns::MyClass$', MyClassPrinter)
pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<.*, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
a pretty printer is registered for my specialization of unordered_map. However, the version for the general unordered_map is still used and if I print the mymap2variable the string "MyUnorderedMapOfMyClassPrinter" is not shown as expected. If we disable all pretty printers and enable only our pretty-printers, then "MyUnorderedMapOfMyClassPrinter" is shown, thus confirming that it was correctly registered. That is why the question is technically not solved, since disabling all other pretty-printers is not a good solution.
But registering a pretty-printer for MyClass* does work, as suggested in the comments, as long as we use a lookup function instead of relying on the RegexpCollectionPrettyPrinter. This solves the original problem, since the gdb regular pretty-printer for unordered_map will now be enough.
More specifically, we can create a pretty-printer as
class MyClassPointerPrinter:
def __init__(self, val):
self.ptr = val
self.name = str(val.dereference()["name"])
self.val = val.dereference()["value"]
def to_string(self):
return f"Pointer to MyClass(name={self.name}, value={self.val})"
and register it with
def my_pp_func(val):
if str(val.type) == "ns::MyClass *":
return MyClassPointerPrinter(val)
gdb.pretty_printers.append(my_pp_func)
We can even extend this further and create a pretty-printer for any pointer. For instance, we can define a pretty printer as
class MyPointerPrettyPrinter:
def __init__(self, val):
self.ptr = val
def to_string(self):
default_visualizer = gdb.default_visualizer(self.ptr.dereference())
return f"({self.ptr.type}) {self.ptr.format_string(raw=True)} -> {default_visualizer.to_string()}"
and register it with
def my_pointer_func(val):
# This matches any pointer
if val.type.code == gdb.TYPE_CODE_PTR:
# Only if the pointed object has a registered pretty-printer we will use
# our pointer pretty-printer
if gdb.default_visualizer(val.dereference()) is not None:
return MyPointerPrettyPrinter(val)
gdb.pretty_printers.append(my_pointer_func)
This will match any pointer and print something like "(ClassName *) 0x<pointer_address> -> OBJ_REP", where "OBJ_REP" is the pretty-printing of the pointed object. If there is no visualizer registered for ClassName, then only "(ClassName *) 0x<pointer_address>" is shown.
For me, the problem is that gdb.current_objfile() always returns None. Thus your pretty printer is registered as a global one, whereas all the standard ones are object level. Object level pretty-printers take precedence.
I have no idea why, but I was unable to make this function work.
It is possible to use this workaround:
gdb.printing.register_pretty_printer(gdb.objfiles()[0], pp, replace=True)

Display a particular std::vector's element in GDB pretty printer

Suppose I have a simple struct:
struct S {
int index;
const std::vector<int>& vec;
};
I want to write a pretty printer for GDB that would display vec[index] for an object of type S.
This is how I do it now:
class SPrinter:
def __init__(self, name, val):
self.val = val
def to_string(self):
i = int(self.val['index'])
ptr = self.val['vec']['_M_impl']['_M_start'] + i
return str(ptr.dereference())
Is there a simpler way to access the given element of std::vector? Is it possible to call operator[] (in GDB I can do p s.vec[0] and get what I want)? I'd like my printer to be independent of the particular implementation of std::vector.
After reading this answer, I came up with the following solution:
def get_vector_element(vec, index):
type = gdb.types.get_basic_type(vec.type)
return gdb.parse_and_eval('(*(%s*)(%s))[%d]' % (type, vec.address, index))
class SPrinter(object):
def __init__(self, name, val):
self.val = val
def to_string(self):
return get_vector_element(self.val['vec'], int(self.val['index']))

Calling embedded function in class method using pybind11

I'm working on a c++ application that uses pybind11 to embed python and I've run into a bit of a problem when trying to call an embedded function from a class method.
to start with here are my bindings:
#ifdef _DEBUG
#undef _DEBUG
#include <python.h>
#define _DEBUG
#else
#include <python.h>
#endif
#include <embed.h>
namespace py = pybind11;
using namespace py::literals;
void DebugInfo(std::string string_)
{
String LogMessage_(string_.c_str());
LOGINFO(LogMessage_);
}
PYBIND11_EMBEDDED_MODULE(Test, m) {
m.def("DebugInfo", &DebugInfo, "Posts message to DEBUGINFO");
}
I could then have a .py file with:
import Test
test.DebugInfo("I'm a lumberjack and that's OK")
and it will print just fine to debug
The trouble starts when I try and call it from within a class method.
import Test
class PyTest(object):
def __init__(self):
test.DebugInfo("I'm a lumberjack and that's OK")
test = PyTest()
when this runs it throws an exception against cast.h specifically against line 1985 which is part of this function:
template <return_value_policy policy>
class unpacking_collector {
public:
template <typename... Ts>
explicit unpacking_collector(Ts &&...values) {
// Tuples aren't (easily) resizable so a list is needed for collection,
// but the actual function call strictly requires a tuple.
auto args_list = list();
int _[] = { 0, (process(args_list, std::forward<Ts>(values)), 0)... };
ignore_unused(_);
m_args = std::move(args_list);
}
const tuple &args() const & { return m_args; }
const dict &kwargs() const & { return m_kwargs; }
tuple args() && { return std::move(m_args); }
dict kwargs() && { return std::move(m_kwargs); }
/// Call a Python function and pass the collected arguments
object call(PyObject *ptr) const {
PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr());
if (!result)
throw error_already_set(); //EXCEPTION THROWS HERE!
return reinterpret_steal<object>(result);
}
And because it's probably relevant here's how I'm calling the whole thing from my main application
//Start the Python Interpreter
py::scoped_interpreter guard{};
//Python variables
py::object thing_;
std::string test_py = Import_File("test.py");
auto locals = py::dict();
py::exec(test_py, py::globals(), locals);
thing_ = locals["test"].cast<py::object>();
thing_.attr("start")();
and the contents of test.py
import Test
class PyTest(object):
def __init__(self, message = "Test Object initialized"):
self.message = message
iterstr = str(self.iter)
message = self.message + iterstr
self.iter = 0
Test.DebugInfo(message)
def start(self):
self.message = "Starting Python Object"
self.iter = self.iter + 1
iterstr = str(self.iter)
message = self.message + iterstr
Test.DebugInfo(message)
def update(self):
self.message = "Python Object Update Cycle:"
self.iter = self.iter + 1
iterstr = str(self.iter)
message = self.message + iterstr
Test.DebugInfo(message)
test = PyTest()
I'm not sure if I've run into a limitation of pybind11, a bug in it, or if I've just screwed the whole thing up.
Any insight would be greatly appreciated.
This was also filed as an issue with pybind11 here: https://github.com/pybind/pybind11/issues/1452
I came across both this SO and the issue, but I figured this out. Copying it here for anyone who stumbles across this first in the future
Basically, you don't actually want a blank py::dict for locals; it will cause all sorts of problems. If you look embedding sample code from the docs or the tests, the locals value always copies the global scope.
See:
* https://pybind11.readthedocs.io/en/stable/advanced/embedding.html
* https://github.com/pybind/pybind11/blob/master/tests/test_embed/test_interpreter.cpp#L57
Your options are to copy the global scope, or, in this case, simply don't pass in a locals
py::scoped_interpreter guard{};
auto globals = py::globals();
py::exec(test_py, globals);
thing_ = globals["Object"].cast<py::object>();
thing_.attr("start")();
It looks like that in the case of top-level code (not inside any module), the globals variable holds the values at this scope.
So after some experimentation I discovered that the problem is caused by pybind not being able to detect an imported module outside of the scope of the function.
import foo
def bar():
foo.func()
will always cause an error. However,
def bar():
import foo
foo.func()
will function as intended.

Boost Python - Unbound method call

I'm trying to use Python embedded in C++ with Boost::python.
My embedded script are supposed to use decorator to register their methods like following:
class Test:
def __init__(self, object_id):
self.object_id = object_id
#decorator('my_id_1')
def func1(self):
print("{}.func1".format(self.object_id))
decorator is declared on the C++ side, defining the method the __init__ and __call__. Everything works has expected, until the call of the method, which lead to SIGSEGV or SIGARBT.
Here is an example of what I would like to do in Python:
#CPP side
item = {}
class decorator:
def __init__(self, _id):
self._id = _id
def __call__(self, func):
item[self._id] = func #saved as PyObject* in CPP
print func
return func
#Script side
class Test(CppBase):
def __init__(self, object_id):
CppBase.__init__(self)
self.object_id = object_id
#decorator('my_id_1')
def func1(self):
print("{}.func1".format(self.object_id))
#decorator('my_id_2')
def func2(self):
print("{}.func2".format(self.object_id))
#CPP side
obj1 = Test("obj1")
item['my_id_1'](obj1) #The crash append here
To do the call, I'm using the following function: boost::python::call<void>(my_PyObject_func, boost::ref(my_obj_instance))
I won't put my all C++ code because I'm actually updating a working project made from the old Python C API, and the whole API is quite huge. However, if you think I forgot some significant part of it, just tell me, and I will post those parts. Furthermore, I removed a lot of simple check such as being sure that the global Python var contain my object, no python error happened or the hash contain the requested id, to make the code lighter.
Here are my C++ Object definition
class CppBase: public boost::python::object {
public:
CppBase();
void open(std::string, boost::python::tuple arg);
void setRoutes(const std::hash<std::string, const Route*>&);
inline std::hash<std::string, const Route*>*const routes() const { return route; }
private:
std::string name;
QHash<std::string, const Decorator*> *route;
};
class Decorator {
public:
Decorator(std::string identifier);
PyObject* call(PyObject* func);
void invoke(boost::python::object&, boost::python::tuple) const;
static void commit(CppBase&);
private:
PyObject* method;
std::string identifier;
static std::hash<std::string, const Decorator*> routes;
};
Here is how I register my Python module
BOOST_PYTHON_MODULE(app)
{
boost::python::class_<CppBase, boost::noncopyable>("CppApp") //I tried to remove 'noncopyable', nothing change
;
boost::python::class_<Decorator, boost::noncopyable>("decorator", boost::python::init<std::string>())
.def("__repr__", &Decorator::repr)
.def("__call__", &Decorator::call)
;
}
Here is the implementation of CppBase::open that I think is the only one important to show in my class definition.
...
void CppBase::open(std::string id, boost::python::tuple arg /* unused so far */){
boost::python::call<void>(route->value(id), boost::ref(*this))
}
...
Here is the Python script sample, running with this example:
class MyScriptSubClass(CppApp):
def __init__(self, object_id):
CppBase.__init__(self)
self.object_id = object_id
#decorator('my_id_1')
def func1(self):
print("{}.func1".format(self.object_id))
Here is how I try to make everything work
//... Creating Python context, Executing the Script file...
boost::python::object cls(main_module.attr("MyScriptSubClass")); //Getting the classDefinition
CppBase core = boost::python::extract<CppBase>(cls()); //Instanciating the object with the previous catched definition
Decorator::commit(core); //Save all the decorator intercepted until now into the object
core.open('my_id_1'); //Calling the function matching with this id
I hope I made everything clear.
In advance, thank you.

What is the most Pythonic way of implementing classes with auto-incrementing instance attributes?

I have several classes. The desired behavior on an instance creation is that an instance is assigned an ID. For simplicity, let us assume that IDs should start at 0 and increase by 1 with every instance creation. For each of these several classes, the IDs should be incremented independently.
I know how to do this in C++. I have actually also done that in Python, but I do not like it as much as the C++ solution, and I am wondering whether it is due to my limited knowledge of Python (little more than 6 weeks), or whether there is a better, more Pythonic way.
In C++, I have implemented this both using inheritance, and using composition. Both implementations use the Curiously Recurring Template Pattern (CRPT) idiom. I slightly prefer the inheritance way:
#include <iostream>
template<class T>
class Countable{
static int counter;
public:
int id;
Countable() : id(counter++){}
};
template<class T>
int Countable<T>::counter = 0;
class Counted : public Countable<Counted>{};
class AnotherCounted: public Countable<AnotherCounted>{};
int main(){
Counted element0;
Counted element1;
Counted element2;
AnotherCounted another_element0;
std::cout << "This should be 2, and actually is: " << element2.id << std::endl;
std::cout << "This should be 0, and actually is: " << another_element0.id << std::endl;
}
to the composion way:
#include <iostream>
template<class T>
class Countable{
static int counter;
public:
int id;
Countable() : id(counter++){}
};
template<class T>
int Countable<T>::counter = 0;
class Counted{
public:
Countable<Counted> counterObject;
};
class AnotherCounted{
public:
Countable<AnotherCounted> counterObject;
};
int main(){
Counted element0;
Counted element1;
Counted element2;
AnotherCounted another_element0;
std::cout << "This should be 2, and actually is: " << element2.counterObject.id << std::endl;
std::cout << "This should be 0, and actually is: " << another_element0.counterObject.id << std::endl;
}
Now, in python, there are no templates which would give me different counters for each class. Thus, I wrapped the countable class to a function, and obtained the following implementation: (inheritance way)
def Countable():
class _Countable:
counter = 0
def __init__(self):
self.id = _Countable.counter
_Countable.counter += 1
return _Countable
class Counted ( Countable() ) :
pass
class AnotherCounted( Countable() ):
pass
element0 = Counted()
element1 = Counted()
element2 = Counted()
another_element0 = AnotherCounted()
print "This should be 2, and actually is:", element2.id
print "This should be 0, and actually is:", another_element0.id
and the composition way:
def Countable():
class _Countable:
counter = 0
def __init__(self):
self.id = _Countable.counter
_Countable.counter += 1
return _Countable
class Counted ( Countable() ) :
counterClass = Countable()
def __init__(self):
self.counterObject = Counted.counterClass()
class AnotherCounted( Countable() ):
counterClass = Countable()
def __init__(self):
self.counterObject = self.counterClass()
element0 = Counted()
element1 = Counted()
element2 = Counted()
another_element0 = AnotherCounted()
print "This should be 2, and actually is:", element2.counterObject.id
print "This should be 0, and actually is:", another_element0.counterObject.id
What troubles me is this. In C++, I have a good idea what I am doing, and e.g. I see no problems even if my classes actually inherit multiply (not just from Countable<> templated class) - everything is very simple.
Now, in Python, I see the following issues:
1) when I use composition, I instantiate the counting class like that:
counterClass = Countable()
I have to do this for every class, and this is possibly error-prone.
2) when I use inheritance, I will bump to further troubles when I will want to ihnerit multiply. Note that above, I have not defined the __init__'s of Counted nor of AnotherCounted, but if I inherited multiply I would have to call base class constructors explicitly, or using super(). I do not like this (yet?) I could also use metaclasses, but my knowledge is limited there and it seems that it adds complexity rather than simplicity.
In conclusion, I think that composition way is probably better for Python implementation, despite the issue with having to explicitly define the counterClass class attribute with Countable().
I would appreciate your opinion on validity of my conclusion.
I would also appreciate hints on better solutions than mine.
Thank you.
I would use __new__, that way you don't have to remember doing anything in __init__:
class Countable(object):
counter = 0
def __new__(cls, *a, **kw):
instance = super(Countable, cls).__new__(cls, *a, **kw)
instance.id = cls.counter + 1
cls.counter = instance.id
return instance
class A(Countable):
pass
class B(Countable):
pass
print A().id, A().id # 1 2
print B().id # 1
I might use a simple class decorator ...
import itertools
def countable(cls):
cls.counter = itertools.count()
return cls
#countable
class Foo(object):
def __init__(self):
self.ID = next(self.__class__.counter)
#countable
class Bar(Foo):
pass
f = Foo()
print f.ID
b = Bar()
print b.ID
If you really want to do this the "fancy" way, you could use a metaclass:
import itertools
class Countable(type):
def __new__(cls,name,bases,dct):
dct['counter'] = itertools.count()
return super(Countable,cls).__new__(cls,name,bases,dct)
class Foo(object):
__metaclass__ = Countable
def __init__(self):
self.ID = next(self.__class__.counter)
class Bar(Foo):
pass
f = Foo()
print f.ID
b = Bar()
print b.ID