python - What does CPython actually do when "=" is performed on primitive type variables? -
for instance:
a = some_process_that_generates_integer_result() b =
someone told me b , a point same chunk of integer object, b modify reference count of object. code executed in function pyobject* ast2obj_expr(void* _o)
in python-ast.c:
static pyobject* ast2obj_object(void *o) { if (!o) o = py_none; py_incref((pyobject*)o); return (pyobject*)o; } ...... case num_kind: result = pytype_genericnew(num_type, null, null); if (!result) goto failed; value = ast2obj_object(o->v.num.n); if (!value) goto failed; if (pyobject_setattrstring(result, "n", value) == -1) goto failed; py_decref(value); break;
however, think modifying reference count without ownership change futile. expect each variable holding primitive values (floats, integers, etc.) have own value, instead of referring same object.
and in execution of simple test code, found break point in above num_kind
branch never reached:
def some_function(x, y): return (x+y)*(x-y) = some_function(666666,66666) print b = print print b b = + 999999 print print b b = print print b
i'm using python2.7-dbg program provided debian. i'm sure program , source code matches, because many other break points works properly.
so, cpython on primitive type objects?
first of all, there no “primitive objects” in python. object, of same kind, , handled in same way on language level. such, following assignments work same way regardless of values assigned:
a = some_process_that_generates_integer_result() b =
in python, assignments always reference copies. whatever function returns, reference copied variable a
. , in second line, reference again copied variable b
. such, both variables refer exact same object.
you can verify using id()
function tell identity of object:
print id(a) print id(b)
this print same identifying number twice. note though, wil doing this, copied reference 2 more times: it’s not variables passed functions copies of references.
this different other languages differentiate between “call value” , “call reference”. former means create copy of value , pass function, means new memory allocated value; latter means actual reference passed , changes reference affect original variable well.
what python called “call assignment”: every function call pass arguments assignment new variables (which available function). , assignment copies reference.
when object, simple strategy. , said above, happens integers no different happens other objects. “special” thing integers immutable, cannot change values. means integer object refers exact same value. makes easy share object (in memory) multiple values. every operation yields new result gives different object, when series of arithmetic operations, changing object variable pointing time.
the same happens other immutable objects too, example strings. every operation yields changed string gives different string object.
assignments mutable objects same too. it’s changing value of objects possible, appear different. consider example:
a = [1] # creates new list object b = # copies reference same list object c = [2] # creates new list object b = + c # concats 2 lists , creates new list object d = b # @ point, have *three* list objects d.append(3) # mutates list object print(d) print(b) # same result since b , d reference same list object
now coming question , c code cite there, looking @ wrong part of cpython explanation there. ast abstract syntax tree parser creates when parsing file. reflects syntax structure of program says nothing actual run-time behavior yet.
the code showed num_kind
responsible creating num
ast objects. can idea of when using ast
module:
>>> import ast >>> doc = ast.parse('foo = 5') # document contains assignment >>> doc.body[0] <_ast.assign object @ 0x0000000002322278> # target of assignment has id `foo` >>> doc.body[0].targets[0].id 'foo' # , value of assignment `num` object # created in c code, `n` property containing value >>> doc.body[0].value <_ast.num object @ 0x00000000023224e0> >>> doc.body[0].value.n 5
if want idea of actual evaluation of python code, should first @ byte code. byte code being executed @ run-time virtual machine. can use dis
module see byte code python code:
>>> def test(): foo = 5 >>> import dis >>> dis.dis(test) 2 0 load_const 1 (5) 3 store_fast 0 (foo) 6 load_const 0 (none) 9 return_value
as can see, there 2 major byte code instructions here: load_const
, store_fast
. load_const
load constant value onto evaluation stack. in example, load constant number, load value function call instead (try playing dis
module figure out how works).
the assignment made using store_fast
. byte code interpreter the following instruction:
target(store_fast) { v = pop(); setlocal(oparg, v); fast_dispatch(); }
so gets value (the reference integer object) stack, , calls setlocal
assign value local variable.
note though, not increase reference count of value. that’s happens load_const
, or other byte code instruction gets value somewhere:
target(load_const) { x = getitem(consts, oparg); py_incref(x); push(x); fast_dispatch(); }
so tl;dr: assignments in python reference copies. references copied whenever value used (but in many other situations copied reference exists short time). ast responsible creating object representation of parsed programs (only syntax), while byte code interpreter runs compiled byte code actual stuff @ run-time , deal real objects.
Comments
Post a Comment