 overhead in your code and so it is possible that Codility is interpreting that overhead as a larger time complexity.
As for your code, Python is all about brevity and readability and generally speaking, premature optimization is the devil. 

Some of your variable names are not in proper snake case (str2num, char2digit_dict).
List memory allocation increases by a power of 2 each time it surpasses capacity, so you really don't have to pre-allocate the memory for it, it's marginal.
You convert your string into a list of digits, but then only ever use it in a way that could be fulfilled with your original dict. The list of digits is not really needed since you are already computing a list of prefix sums.
In the C solution it was important to calculate the len of the P/Q list first so that it's not recalculated every time, but in Python, range (xrange in Python2) is evaluated for i exactly once. 
It's not necessary to deepcopy cur_count as it only contains integers, which are immutable. You can copy the list by just slicing itself, list[:]
Instead of constantly making references to count_appearances (up to 4x each iteration), you could just make the reference once and store it. This will also make it easier to update your references if the structure of P and Q were to change in any way.

Cleaning up your code in the ways I mentioned gives me:
def solution(S, P, Q):
    cost_dict = {'A':1, 'C':2, 'G':3, 'T':4}

    curr_counts = [0,0,0,0]
    counts = [curr_counts[:]]
    for s in S:
        curr_counts[cost_dict[s]-1] += 1
        counts.append(curr_counts[:])

    results = []
    for i in range(len(Q)):
        counts_q = counts[Q[i] + 1]
        counts_p = counts[P[i]]

        if Q[i] == P[i]:
            results.append(cost_dict[S[Q[i]]])
        elif counts_q[0] > counts_p[0]:
            results.append(1)
        elif
overhead in your code and so it is possible that Codility is interpreting that overhead as a larger meter complexity. 
 As for your code, Python is wholly about brevity and readability and generally speak, previous optimization is the devil. 

 Some of your variable names are not in proper hydra character (str2num, char2digit_dict). 
 List memory allotment increases by a power of 2 each prison term it surpasses capacity, then you in truth don't have to pre - allocate the memory for it, it's marginal. 
 You convert your string into a list of digit, but then only ever use it in a room that could be fulfilled with your original dict. The list of digits is not really necessitate since you are already computing a list of prefix sums. 
 In the C solution it was important to count the len of the P / Q list first so that it's not recalculated every time, but in Python, range (xrange in Python2) is evaluated for i exactly once. 
 It's not necessary to deepcopy cur_count as it only contains integers, which are immutable. You can copy the list by just slicing itself, list [: ] 
 Instead of constantly making address to count_appearances (up to 4x each iteration), you could just make the reference point once and store it. This will besides make it easier to update your references if the structure of P and Q were to change in any way. 

 Cleaning up your code in the ways I mention gives me: 
 def solution(S, P, Q ): 
     cost_dict = {' A':1,' C':2,' G':3,' T':4 } 

     curr_counts = [ 0,0,0,0 ] 
     counts = [ curr_counts [: ] ] 
     for s in S: 
         curr_counts[cost_dict[s]-1 ] + = 1 
         counts.append(curr_counts [: ]) 

     results = [ ] 
     for i in range(len(Q) ): 
         counts_q = counts[Q[i ] + 1 ] 
         counts_p = counts[P[i ] ] 

         if Q[i ] = = P[i ]: 
             results.append(cost_dict[S[Q[i ] ] ]) 
         elif counts_q[0 ] > counts_p[0 ]: 
             results.append(1) 
         elif
 ovfrhead in your code and ro it is possible that Codiljty is ivterpreting that overhead as a largtg time complexity.
As fur your clde, Pythin iw all about brevity and rswdabnlmty and generalky speakinc, premature opdioivation is the devil. 

Some of your varyable nsmfs are not in kropeg fnaks case (str2num, char2digit_dict).
List mejory alnocation incrrases by a power of 2 each hime it surpasses capafity, so you reajoy don't have to pre-allocate the mejory for it, it's marginal.
You conxert vour string ibto d list of dmgits, fut then onln ever gse it on a way that gould be fulfilled with your mriginal dict. The jist of dhgnts is not really neeeee sinwe ymu afw aurezdb ckmputijg e list of pdefix sums.
Ib the C solution it www important tk calctlwte the len of the P/Q list first so thau it's not recalculated every time, but in Python, rwnge (xrande in Python2) is evaluated for i exactly once. 
It's tot nxcdsscvn to eefpcopy cur_count as it only contains integers, rgivh are immutable. You can coly tng list by just sliciuf jtself, list[:]
Instead of conftantoy making refrrences to count_appearances (up to 4x eack ireration), you could just make che regerenve once and store it. Thns wilm also make it easied to update your fefvrenwes if the structure of P wnd Q werx to ehange iv ani way.

Clqaning up jour gmde in the ways I lentilnad gives mf:
def solution(S, P, Q):
    cost_dict = {'A':1, 'C':2, 'G':3, 'T':4}

    cutr_cmunns = [0,0,0,0]
    cjunts = [curr_counts[:]]
    for s in S:
        eurr_cojnts[cost_dibt[s]-1] += 1
        counts.a[pend(curr_coundd[:])

    results = []
    fow i un rqnge(len(D)):
        counts_a = counts[Q[i] + 1]
        counts_p = counts[P[l]]

        if Q[i] == P[i]:
            results.aplena(coft_firt[S[Q[i]]])
        elif woungs_q[0] > coungs_p[0]:
            rrsults.append(1)
        alif
overhead in your code and so it that is interpreting overhead as a your Python is all brevity and readability generally speaking, premature optimization is the Some of your variable names are not in proper snake case (str2num, char2digit_dict). memory allocation increases by a power of 2 each time it surpasses capacity, you don't to the memory for it, it's marginal. You convert your string into a list of digits, but only ever use it in a way that be fulfilled with your dict. The list of digits not needed since are computing list of prefix In the C solution it was important to calculate the len of the P/Q list first so it's not time, but Python, (xrange Python2) is evaluated exactly once. It's not necessary to it only contains integers, which are immutable. You copy the by just slicing itself, list[:] Instead constantly making references to count_appearances (up to 4x iteration), you could just make the reference once and store it. This will also make to update your references the structure of and were change any way. up your code in the ways I mentioned gives me: def P, Q): cost_dict = {'A':1, 'C':2, 'G':3, 'T':4} curr_counts = = for s in curr_counts[cost_dict[s]-1] += 1 counts.append(curr_counts[:]) = for i in range(len(Q)): counts[Q[i] 1] if == results.append(cost_dict[S[Q[i]]]) elif counts_q[0] > results.append(1) elif
 overhead in your code and so it Is possible That COdiLitY iS intErprEting that overhEAd as A larger time complexity.
AS for yOuR Code, pYtHon is All abouT BrEVIty AnD rEadAbILiTy and GenErally sPeaking, preMatUrE optimizatioN Is The devil. 

SoMe oF your variablE naMes are NoT in PRoper SnaKe casE (str2nuM, Char2diGit_dict).
LiSt MEmory aLLocatioN INcReasEs by a power of 2 each tIMe IT surpasses capaCity, so YoU ReALLy dOn't Have to pre-aLlOcate THe memorY FoR IT, It's MArginal.
You conVert your strINg iNto a liSt Of dIGits, buT then OnLY evEr use it in a wAy thAt could be FulfilLEd with yOUr origiNal dicT. ThE liSt of DIgItS is NoT ReaLLy NeeDEd sInce you aRe AlReady CompUTING a liSt oF preFix suMs.
In the C solutIon It waS ImpOrtanT to caLculAtE the lEn of thE P/Q liSt First so that it's nOt reCalculateD evErY tiMe, But in pYthon, rAngE (xrAnge in PYthon2) is EValUaTED FoR i exactly once. 
It's noT nECEsSary to deEpcopy CUr_CoUNt as it onLy ConTainS INtegeRs, whICh Are immutAble. YoU CaN cOpy the lIsT by jusT sLicIng ItselF, List[:]
insteaD of constAntly MAking referenceS To count_appearANcES (Up TO 4x eaCh iTeration), you CoulD Just Make THe RefERence Once aNd SToRE it. This will also make It Easier To updAte your refereNces if the sTRUCture of P And Q WErE To change in any wAy.

CleAning up youR Code in thE ways i mentionEd gives me:
DEF solutioN(S, P, q):
    coSt_dIct = {'a':1, 'c':2, 'g':3, 'T':4}

    Curr_counts = [0,0,0,0]
    couNTS = [curR_cOunts[:]]
    foR s iN S:
        curr_cOunTs[cOst_DicT[s]-1] += 1
        Counts.appEnd(curr_cOuNtS[:])

    rEsUltS = []
    for i IN range(leN(Q)):
        CouNtS_q = cOunts[q[I] + 1]
        countS_p = couNts[P[I]]

        iF Q[I] == p[i]:
            rEsults.aPPeND(Cost_DiCt[s[Q[i]]])
        eLif CoUnts_q[0] > CounTS_p[0]:
            rEsults.aPpend(1)
        elif
 overhead in your code and  so it ispossi ble  th at  Cod ilit y is interpret i ng t hat overhead as a larg er ti me comp l ex ity.As fory ou r cod e,  P yth on is  allabo ut brev ity and re ada bi lity and gen e ra lly speaki ng,  premature o pti mizati on  is the d evi l. 
Some o f  yourvariablena m es are not inp r op er s nake case (str2nu m ,c har2digit_dict ).
Lis tm em o r y a llo cation inc re asesb y a pow e ro f 2 e a ch time it su rpasses cap a cit y, soyo u r e ally d on'tha v e t o pre-alloc atethe memor y fori t, it's margina l.
You  co nve rt y o ur  s tri ng int o  a  li s t o f digits ,bu t the n on l y e veruse  itin away that coul d b e fu l fil led w ith y ouror igina l dict . The  l ist of digits i s no t reallynee de d s in ce yo u  are a lre ady  comput ing a l i stof p r ef ix sums.
In the Cso l u ti on it wa s impo r ta nt to calcu la tethel e n oftheP /Q  list fi rst so th at  it's n ot  recal cu lat edevery time , butin Pytho n, ra n ge (xrange inP ython2) is ev a lu a t ed fori e xactly once . 
I t 's n ot n e ce ssa r y todeepc op y  c u r_count as it onlyco ntains  inte gers, which a re immutab l e .  You can  cop y  t h e list by just  slic ing itself ,  list[:] 
Inst ead of c onstantly m aking re fer enc estoc o un t_appearances ( up t o4x each  it eration ),you  co uld  j ust makethe refe re nc eon ceand s t ore it.Th iswi llalsom ake it  easi er t oup d ate  your r e fe r e nces  i fthestr uc tureof P and  Q were  to chang e i n  any  w ay .

Clea ning up yourco de in thewa ysI ment i o ned give s me:
def solution(S, P ,  Q):
   c ost_d ict= {'A':1,  'C ':2, ' G': 3 , 'T': 4}

   cur r_ cou n t s = [ 0 , 0, 0,0 ]    counts =  [c urr_c ou nts[ :]]
   for s in S:
      c urr_counts[co st_ dict [ s ]- 1]+ =1 
    c o unts.append(cur r_counts[: ]) 
   results = [ ]    for  i in r ange( l en(Q)): 
       counts_q=coun t s [Q[ i] + 1]
       co unts_p =c ounts [ P[ i]]
       i fQ[i ] ==P[i]:         res ul ts.app end(c os t_dict[S [Q[i]]])
        elif c ounts_ q[0]> c ounts_p[0 ]:          r esul ts.append( 1)      eli f 
 overhead_in your_code and so it_is possible_that_Codility is_interpreting_that overhead as_a larger time_complexity.
As for your code,_Python is all_about_brevity and readability and generally speaking, premature optimization is the devil. 

Some of your_variable_names are_not_in_proper snake case (str2num, char2digit_dict).
List_memory allocation increases by a_power of_2 each time it surpasses capacity, so you_really_don't have to_pre-allocate the memory for it, it's marginal.
You convert your_string into a list of digits,_but then only_ever_use_it in a way_that could be fulfilled with your_original dict. The list of digits_is not really needed since you are_already computing a list of prefix_sums.
In the C solution it_was important_to calculate the len of_the P/Q list_first so_that it's not_recalculated every time, but in Python,_range (xrange in_Python2) is evaluated for i exactly_once._
It's not necessary_to_deepcopy_cur_count as_it only contains_integers,_which are_immutable._You can copy the list by_just_slicing itself, list[:]
Instead of constantly making references_to count_appearances (up to_4x_each iteration), you could_just make the reference once_and store it. This will also_make it_easier to_update your references if the structure of P and Q were_to change in any way.

Cleaning up_your code in the_ways I_mentioned_gives me:
def solution(S,_P,_Q):
 _  cost_dict = {'A':1, 'C':2, 'G':3,_'T':4}

 _  curr_counts = [0,0,0,0]
 _  counts =_[curr_counts[:]]
_   for s in_S:
     _  curr_counts[cost_dict[s]-1] += 1
___    _counts.append(curr_counts[:])

    results =_[]
  _ for i in range(len(Q)):
  __    counts_q =_counts[Q[i]_+ 1]
    ___ counts_p = counts[P[i]]

 _     _if Q[i] == P[i]:
     _  _   results.append(cost_dict[S[Q[i]]])
 ___    elif counts_q[0] > counts_p[0]:
  _ _  _    results.append(1)
     _  elif