2016-03-08 123 views
0

我的OpenERP 7.0工作,我想重寫等被定義功能__compute如下:如何覆蓋在python中以兩個下劃線開頭的函數?

class account_account(osv.osv): 
    _name = "account.account" 
    _description = "Account" 

    def __compute(self, cr, uid, ids, field_names, arg=None, context=None, 
        query='', query_params=()): 
     """ compute the balance, debit and/or credit for the provided 
     account ids 
     Arguments: 
     `ids`: account ids 
     `field_names`: the fields to compute (a list of any of 
         'balance', 'debit' and 'credit') 
     `arg`: unused fields.function stuff 
     `query`: additional query filter (as a string) 
     `query_params`: parameters for the provided query string 
         (__compute will handle their escaping) as a 
         tuple 
     """ 
     mapping = { 
      'balance': "COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance", 
      'debit': "COALESCE(SUM(l.debit), 0) as debit", 
      'credit': "COALESCE(SUM(l.credit), 0) as credit", 
      # by convention, foreign_balance is 0 when the account has no secondary currency, because the amounts may be in different currencies 
      'foreign_balance': "(SELECT CASE WHEN currency_id IS NULL THEN 0 ELSE COALESCE(SUM(l.amount_currency), 0) END FROM account_account WHERE id IN (l.account_id)) as foreign_balance", 
     } 
     #get all the necessary accounts 
     children_and_consolidated = self._get_children_and_consol(cr, uid, ids, context=context) 
     #compute for each account the balance/debit/credit from the move lines 
     accounts = {} 
     res = {} 
     null_result = dict((fn, 0.0) for fn in field_names) 
     if children_and_consolidated: 
      aml_query = self.pool.get('account.move.line')._query_get(cr, uid, context=context) 

      wheres = [""] 
      if query.strip(): 
       wheres.append(query.strip()) 
      if aml_query.strip(): 
       wheres.append(aml_query.strip()) 
      filters = " AND ".join(wheres) 
      # IN might not work ideally in case there are too many 
      # children_and_consolidated, in that case join on a 
      # values() e.g.: 
      # SELECT l.account_id as id FROM account_move_line l 
      # INNER JOIN (VALUES (id1), (id2), (id3), ...) AS tmp (id) 
      # ON l.account_id = tmp.id 
      # or make _get_children_and_consol return a query and join on that 
      request = ("SELECT l.account_id as id, " +\ 
         ', '.join(mapping.values()) + 
         " FROM account_move_line l" \ 
         " WHERE l.account_id IN %s " \ 
          + filters + 
         " GROUP BY l.account_id") 
      params = (tuple(children_and_consolidated),) + query_params 
      cr.execute(request, params) 

      for row in cr.dictfetchall(): 
       accounts[row['id']] = row 

      # consolidate accounts with direct children 
      children_and_consolidated.reverse() 
      brs = list(self.browse(cr, uid, children_and_consolidated, context=context)) 
      sums = {} 
      currency_obj = self.pool.get('res.currency') 
      while brs: 
       current = brs.pop(0) 

       for fn in field_names: 
        sums.setdefault(current.id, {})[fn] = accounts.get(current.id, {}).get(fn, 0.0) 
        for child in current.child_id: 
         if not child.active: 
          continue 
         if child.company_id.currency_id.id == current.company_id.currency_id.id: 
          try: 
           sums[current.id][fn] += sums[child.id][fn] 
          except: 
           sums[current.id][fn] += accounts.get(child.id, {}).get(fn, 0.0) 
         else: 
          sums[current.id][fn] += currency_obj.compute(cr, uid, child.company_id.currency_id.id, current.company_id.currency_id.id, sums[child.id][fn], context=context) 

       # as we have to relay on values computed before this is calculated separately than previous fields 
       if current.currency_id and current.exchange_rate and \ 
          ('adjusted_balance' in field_names or 'unrealized_gain_loss' in field_names): 
        # Computing Adjusted Balance and Unrealized Gains and losses 
        # Adjusted Balance = Foreign Balance/Exchange Rate 
        # Unrealized Gains and losses = Adjusted Balance - Balance 
        adj_bal = sums[current.id].get('foreign_balance', 0.0)/current.exchange_rate 
        sums[current.id].update({'adjusted_balance': adj_bal, 'unrealized_gain_loss': adj_bal - sums[current.id].get('balance', 0.0)}) 
      for id in ids: 
       res[id] = sums.get(id, null_result) 
     else: 
      for id in ids: 
       res[id] = null_result 
     return res 

    account_account() 

我讀到,當你想覆蓋雙下劃線的功能,你多一個下劃線前綴的方法名稱和定義類名如下:

def _account_account__compute(self, cr, uid, ids, field_names, arg=None, context=None, 
       query='', query_params=()): 

但它不起作用。

回答

2

你讀的是雙下劃線前綴方法變成私人歸因於name mangling。此過程會重寫類定義中的名稱以指向新名稱。新名稱按照您的說法構建:_<class name><class method name>。請看下面的例子:

class A(): 
    def public(self): print('public() called') 
    def _internal_use(self): print('_internal_use() called') 
    def __private(self): print('__private() called') 
    def f(self): self.__private() 

現在讓我們來看看A.__dict__這就是方法的名字存儲結構:

>>> A.__dict__ 
mappingproxy({ 
    'f': <function A.f at 0x1028908c8>, 
    '_A__private': <function A.__private at 0x1028906a8>, 
    '_internal_use': <function A._internal_use at 0x102890620>, 
    '__weakref__': <attribute '__weakref__' of 'A' objects>, 
    '__dict__': <attribute '__dict__' of 'A' objects>, 
    '__module__': '__main__', 
    '__doc__': None, 
    'public': <function A.public at 0x102890598> 
}) 

其中,注意到你有_A__private_internal_usepublic

注意這些名稱不在模塊範圍內,它們只存在於類的__dict__內。當Python解析成員訪問時,它看起來在對象的__dict__裏面。如果不是來源,它會查看「__dict__」和「超級」__dict__

a = A() 
a.public 
# Python looks into a.__dict__. If not found, it looks into type(a).__dict__ 

這樣,您就可以訪問public_internal_use,但你不能找到__private,因爲這個名字甚至不存在。你可以訪問是_A__private

這個名字的
a.public  # works 
a.f    # works 
a._internal_use # works 
a.__private  # AttributeError! 
a._A__private # works again 

通知沒有在模塊全局範圍內定義既不是:

public   # NameError! 
_internal_use # NameError! 
__private  # NameError! 
_A__private # NameError! 

但你嘗試通過簡單地定義與模塊功能覆蓋功能名稱。那麼,Python成員訪問解析將永遠不會涉及全局範圍。所以,你有兩個選擇:

  1. 您可以創建另一個繼承類和重定義功能:

    class B(A): 
        def _A__private(self): print('New __private() called') 
    
        a = A() 
        a.f() # prints __private() called 
        b = B() 
        b.f() # prints New __private() called 
    
  2. 您可以與任何其他功能(甚至一個lambda)直接覆蓋的方法:

    A._A__private = lambda self: print('This is a lambda') 
    a = A() 
    a.f() # prints This is a lambda 
    
+0

謝謝你很多的你的解釋 –

0

您需要創建從odoo類繼承的account_account類。然後,你可以使用super()方法重載的方法:

class stock_move(osv.osv): 
    _inherit = "account.account" 

    # new columns 
    # ... 
    def __compute(self, cr, uid, ids, field_names, arg=None, context=None, 
       query='', query_params=()): 
     # do your stuff 
     # call parent method if needed 
     return super(stock_move, self).__compute(self, cr, uid, ids, field_names, arg=None, context=None, query='', query_params=()) 

這裏一個例子,重寫一個創建方法,它是很常見的,因爲你可能希望創建一個對象時添加一些額外的功能:

class mrp_product_produce(osv.osv_memory): 

    _inherit = "mrp.product.produce" 

    def create(self, cr, uid, vals, context=None): 
     res ={} 
     res = super(product_product, self).create(cr, uid, vals, context) 
     if 'supply_method' in vals and vals['supply_method'] == 'produce': 
      sequence_type_obj = self.pool.get('ir.sequence.type') 
      id_type = sequence_type_obj.create(cr, uid, {'name': vals['name'], 'code': 'product_produce_' + str(res)}) 
      sequence_obj = self.pool.get('ir.sequence') 
      sequence_obj.create(cr, uid, {'name': vals['name'], 'code': 'product_produce_' + str(res), 'padding': 7, 'number_increment': 1, 'number_next': 1 }) 
     return res