diff --git a/vm/src/vm.rs b/vm/src/vm.rs
index 17a7498360..6494bb9777 100644
--- a/vm/src/vm.rs
+++ b/vm/src/vm.rs
@@ -455,9 +455,31 @@ impl VirtualMachine {
         }
     }
 
-    pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
-        // 1. Try __sub__, next __rsub__, next, give up
-        if let Ok(method) = self.get_method(a.clone(), "__sub__") {
+    /// Calls default method, reverse method or exception
+    ///
+    /// * `a` - First argument.
+    /// * `b` - Second argument.
+    /// * `d` - Default method to try and call (such as `__and__`).
+    /// * `r` - Reverse method to try and call (such as `__rand__`), in case first one fails.
+    /// * `op` - Operator for the exception text, for example `&`.
+    ///
+    /// Given the above example, it will
+    /// 1. Try to call `__and__` with `a` and `b`
+    /// 2. If above fails try to call `__rand__` with `a` and `b`
+    /// 3. If above fails throw an exception:
+    ///    `TypeError: Unsupported operand types for '&': 'float' and 'int'`
+    ///    if `a` is of type float and `b` of type int
+    ///
+    pub fn call_or_unsupported(
+        &mut self,
+        a: PyObjectRef,
+        b: PyObjectRef,
+        d: &str,
+        r: &str,
+        op: &str,
+    ) -> PyResult {
+        // Try to call the first method
+        if let Ok(method) = self.get_method(a.clone(), d) {
             match self.invoke(
                 method,
                 PyFuncArgs {
@@ -474,8 +496,8 @@ impl VirtualMachine {
             }
         }
 
-        // 2. try __rsub__
-        if let Ok(method) = self.get_method(b.clone(), "__rsub__") {
+        // 2. Try to call reverse method
+        if let Ok(method) = self.get_method(b.clone(), r) {
             match self.invoke(
                 method,
                 PyFuncArgs {
@@ -492,16 +514,21 @@ impl VirtualMachine {
             }
         }
 
-        // 3. It all failed :(
-        // Cannot sub a and b
+        // 3. Both failed, throw an exception
+        // TODO: Move this chunk somewhere else, it should be
+        // called in other methods as well (for example objint.rs)
         let a_type_name = objtype::get_type_name(&a.typ());
         let b_type_name = objtype::get_type_name(&b.typ());
         Err(self.new_type_error(format!(
-            "Unsupported operand types for '-': '{}' and '{}'",
-            a_type_name, b_type_name
+            "Unsupported operand types for '{}': '{}' and '{}'",
+            op, a_type_name, b_type_name
         )))
     }
 
+    pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
+        self.call_or_unsupported(a, b, "__sub__", "__rsub__", "-")
+    }
+
     pub fn _add(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
         self.call_method(&a, "__add__", vec![b])
     }
@@ -527,54 +554,11 @@ impl VirtualMachine {
     }
 
     pub fn _or(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
-        self.call_method(&a, "__or__", vec![b])
+        self.call_or_unsupported(a, b, "__or__", "__ror__", "|")
     }
 
     pub fn _and(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
-        // 1. Try __and__, next __rand__, next, give up
-        if let Ok(method) = self.get_method(a.clone(), "__and__") {
-            match self.invoke(
-                method,
-                PyFuncArgs {
-                    args: vec![b.clone()],
-                    kwargs: vec![],
-                },
-            ) {
-                Ok(value) => return Ok(value),
-                Err(err) => {
-                    if !objtype::isinstance(&err, &self.ctx.exceptions.not_implemented_error) {
-                        return Err(err);
-                    }
-                }
-            }
-        }
-
-        // 2. try __rand__
-        if let Ok(method) = self.get_method(b.clone(), "__rand__") {
-            match self.invoke(
-                method,
-                PyFuncArgs {
-                    args: vec![a.clone()],
-                    kwargs: vec![],
-                },
-            ) {
-                Ok(value) => return Ok(value),
-                Err(err) => {
-                    if !objtype::isinstance(&err, &self.ctx.exceptions.not_implemented_error) {
-                        return Err(err);
-                    }
-                }
-            }
-        }
-
-        // 3. It all failed :(
-        // Cannot and a and b
-        let a_type_name = objtype::get_type_name(&a.typ());
-        let b_type_name = objtype::get_type_name(&b.typ());
-        Err(self.new_type_error(format!(
-            "Unsupported operand types for '&': '{}' and '{}'",
-            a_type_name, b_type_name
-        )))
+        self.call_or_unsupported(a, b, "__and__", "__rand__", "&")
     }
 
     pub fn _eq(&mut self, a: &PyObjectRef, b: PyObjectRef) -> PyResult {