Search code examples
pythonpython-3.xodoo-12

Is it possible to delete a record after "return" statement?


I made a function in 'hr.contract' that generate a payslip. But this payslip is used to simulate and calculate some salaries, so after create the payslip I must delete it.

Also, I made a function to print the payslip report, from the contract form. The problem is, when I click "print" button I create the payslip and return its report, but then I can't figure out a way to delete the payslip created.

def generate_report(self):
        # I get this values from another methods,
        # I put 1 and 20 just to avoid confution in the question.
        run_id = 1
        indicador_id = 20

        payslip = self.generate_fake_nominee(run_id, self.employee_id.id, indicador_id, self.id)

        report = payslip.print_nominee_report()
        return report

I can't do stuff after the return, so any ideas?


Solution

  • Assuming payslip is the only reference, it should be deleted when the function returns. If it holds resources that might not be cleaned up properly, either:

    1. It should implement the context management protocol and a with statement could be used:

      with self.generate_fake_nominee(run_id, self.employee_id.id, indicador_id, self.id) as payslip:
          return payslip.print_nominee_report()
      

      or,

    2. If you need to call some cleanup function manually, a finally block can be used:

      payslip = self.generate_fake_nominee(run_id, self.employee_id.id, indicador_id, self.id)
      try:
          return payslip.print_nominee_report()
      finally:
          payslip.cleanup_function()
      

    To be clear, putting del payslip in a finally block would be completely pointless; the name will be unbound when the function returns anyway, so del accomplishes nothing. Either the object bound to payslip would be freed anyway (if it had no other aliases) or it wouldn't be free regardless (it's aliased elsewhere). payslip is unbound when the function returns no matter what, and all del does is make the unbinding explicit, which is slower and pointlessly verbose.


    Update: It seems like the report in your original code has a live dependency on the payslip object, so you can't actually clean up the payslip until the caller is done with the report. If that's the case, you have two options as well:

    1. Figure out how to remove the live dependency, so report is a standalone set of data (depends on code you haven't shown us, but this is the best solution when possible)

    2. Use a finalizer tied to report that preserves payslip until report is garbage collected, at which point it cleans it up, a la:

      # At top of module
      import weakref
      
      def generate_report(self):
          # I get this values from another methods,
          # I put 1 and 20 just to avoid confution in the question.
          run_id = 1
          indicador_id = 20
      
          payslip = self.generate_fake_nominee(run_id, self.employee_id.id, indicador_id, self.id)
      
          report = payslip.print_nominee_report()
          # Ensure cleanup_function is called when report is gc-ed
          weakref.finalize(report, payslip.cleanup_function)
          return report
      

      This option isn't perfect; even on CPython with deterministic reference counting, if a reference cycle gets involved, even when you're done with report it can take an arbitrary amount of time before the cycle collector is invoked and report actually gets collected (and the cleanup function invoked). On non-CPython interpreters with true garbage collectors, this will happen even without reference cycles.