How to distinguish timers when running multiple modal operators?

bpy.ops is the interface for calling operators only, you can’t access the operator instance, it’s class variables or attributes or anything this way. You need to use the class name (standard python). Inside class methods, you can either use the explicit name, or self.class to refer to the class instead of the instance (=self).

In the below example, I use both the explicit and the self.class way inside the class methods.

Whether something is a class variable or an attribute (=instance variable) is automatically determined by python and fully depends on how you use it:

class ClassName:
    var = 123

var could be a class variable, as well as an attribute. If you access it via the class name (ClassName.var), then it will be a class variable, if you refer to it inside a class method via self.var, then it’s an attribute.

It’s different with class / static methods in classes, they require explicit declaration:

@classmethod
def func(cls):
    ...

@staticmethod
def func():
    ...
import bpy


class ModalTimerOperator(bpy.types.Operator):
    """Useful for multiple modal operators all utilizing Timers"""
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Timer 1"

    _timer = None
    _count = 0

    def modal(self, context, event):
        if self.__class__._timer is None:
            return {'CANCELLED'}

        if event.type == 'TIMER':
            ModalTimerOperator._count += 1
            redraw_region(context, 'PROPERTIES')
        return {'PASS_THROUGH'}


    def invoke(self, context, event):
        if self.__class__._timer is None:
            if ModalTimerOperator2._timer is not None:
                bpy.ops.wm.modal_timer_operator_2('INVOKE_DEFAULT')
            self.__class__._timer = context.window_manager.event_timer_add(0.008, context.window)
            context.window_manager.modal_handler_add(self)
        else:
            return self.cancel(context)
        return {'RUNNING_MODAL'}


    def cancel(self, context):
        context.window_manager.event_timer_remove(self.__class__._timer)
        self.__class__._timer = None
        ModalTimerOperator._count = 0
        return {'CANCELLED'}
    

class ModalTimerOperator2(bpy.types.Operator):
    """Useful for multiple modal operators all utilizing Timers"""
    bl_idname = "wm.modal_timer_operator_2"
    bl_label = "Timer 2"

    _timer = None
    _count = 0

    def modal(self, context, event):
        if self.__class__._timer is None:
            return {'CANCELLED'}

        if event.type == 'TIMER':
            ModalTimerOperator2._count += 1
            redraw_region(context, 'PROPERTIES')
        return {'PASS_THROUGH'}


    def invoke(self, context, event):
        if self.__class__._timer is None:
            if ModalTimerOperator._timer is not None:
                bpy.ops.wm.modal_timer_operator('INVOKE_DEFAULT')
            self.__class__._timer = context.window_manager.event_timer_add(0.5, context.window)
            context.window_manager.modal_handler_add(self)
        else:
            return self.cancel(context)
        return {'RUNNING_MODAL'}


    def cancel(self, context):
        context.window_manager.event_timer_remove(self.__class__._timer)
        self.__class__._timer = None
        ModalTimerOperator2._count = 0
        return {'CANCELLED'}
    
def redraw_region(context, area_type, region_type='WINDOW'):
    for area in context.screen.areas:
        if area.type == area_type:
            for region in area.regions:
                if region.type == region_type:
                    region.tag_redraw()
    
def draw_func(self, context):
    layout = self.layout
    top1 = ModalTimerOperator
    top2 = ModalTimerOperator2
    layout.operator(ModalTimerOperator.bl_idname, text=top1.bl_label if top1._timer is None else str(top1._count))
    layout.operator(ModalTimerOperator2.bl_idname, text=top2.bl_label if top2._timer is None else str(top2._count))
    
    layout.label("Timer 1: %s" % ModalTimerOperator._timer)
    layout.label("Timer 2: %s" % ModalTimerOperator2._timer)

def register():
    bpy.utils.register_module(__name__)
    bpy.types.RENDER_PT_render.prepend(draw_func)
    
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.RENDER_PT_render.remove(draw_func)
    
if __name__ == '__main__':
    register()