Ponteiros em Python?
Eu sei que o Python não tem ponteiros, mas existe uma maneira de ter este rendimento 2
em vez disso
>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1
?
Aqui está um exemplo: eu quero form.data['field']
e form.field.value
ter sempre o mesmo valor. Não é completamente necessário, mas acho que seria bom.
6 answers
Isto é viável, porque envolve nomes decorados e indexação -- isto é, completamente construções diferentes dos barenamesEu quero
form.data['field']
eform.field.value
Ter sempre o mesmo valor
a
e estás a perguntar sobre isso, e porque com o teu pedido é totalmente impossível. Por que pedir algo impossível e totalmente diferente da (possível) coisa que você realmente quer?!
Talvez não saibas. perceba como barenames e nomes decorados são drasticamente diferentes. Quando você se refere a um barename a
, Você está obtendo exatamente o objeto a que a
foi vinculado pela última vez neste escopo (ou uma exceção se ele não estava vinculado neste escopo) -- este é um aspecto tão profundo e fundamental do Python que ele não pode ser subvertido. Quando você se refere a um decorado nome x.y
, você está pedindo a um objeto (o objeto x
se refere a) para por favor fornecer "o atributo y
" -- e em resposta a isso request, the object can perform totally arbitrary computations (and indexing is quite similar: it also allows arbitrary computations to be performed in response).
Agora, o teu exemplo de "desiderata real" é misterioso porque em cada caso dois níveis de indexação ou de atribuição de atributos estão envolvidos, por isso a subtileza que desejas pode ser introduzida de muitas maneiras. Que outros atributos é form.field
suponha ter, por exemplo, além de value
? Sem mais cálculos .value
, as possibilidades incluem:
class Form(object):
...
def __getattr__(self, name):
return self.data[name]
E
class Form(object):
...
@property
def data(self):
return self.__dict__
A presença de .value
sugere escolher a primeira forma, mais uma espécie de invólucro inútil:
class KouWrap(object):
def __init__(self, value):
self.value = value
class Form(object):
...
def __getattr__(self, name):
return KouWrap(self.data[name])
Se as atribuições tais form.field.value = 23
também é suposto definir a entrada em form.data
, Então o invólucro deve tornar-se mais complexo de facto, e não tudo o que inútil:
class MciWrap(object):
def __init__(self, data, k):
self._data = data
self._k = k
@property
def value(self):
return self._data[self._k]
@value.setter
def value(self, v)
self._data[self._k] = v
class Form(object):
...
def __getattr__(self, name):
return MciWrap(self.data, name)
O último exemplo é o mais próximo que se chega, em Python, ao sentido de "um ponteiro" como parece querer -- mas é crucial entendo que tais sutilezas nunca pode apenas trabalhar com indexação e/ou nomes decorados, nunca com barenames como você originalmente pediu!
a = [1]
b = a
a[0] = 2
b[0]
Que cria uma lista, atribui a referência a, então b também, usa a referência a para definir o primeiro elemento para 2, em seguida, acessa usando a variável de referência B.
Quando você olha para o operador ' = ' em Python, não pense em termos de atribuição. Não se atribui coisas, prende-se. = é um operador de ligação.
Assim, no seu código, você está dando ao valor 1 um nome: a. Então, você está dando o valor em 'a'um nome: B. Então você está ligando o valor 2 ao nome 'a'. O valor ligado a b não muda nesta operação.
Vindo de linguagens semelhantes A C, isto pode ser confuso, mas uma vez você fica acostumado a ele, você descobre que ele ajuda você a ler e raciocinar sobre o seu código mais claramente: o valor que tem o nome " b " não vai mudar a menos que você explicitamente alterá-lo. E se você fizer um 'import this', você verá que o Zen dos Estados Python que é Explícito é melhor do que implícito.Note bem que linguagens funcionais como Haskell também usam este paradigma, com grande valor em termos de robustez.
dict1 = {'first':'hello', 'second':'world'}
dict2 = dict1 # pointer assignation mechanism
dict2['first'] = 'bye'
dict1
>>> {'first':'bye', 'second':'world'}
Aqui está um exemplo de atribuição de cópias
a = 1
b = a # copy of memory mechanism. up to here id(a) == id(b)
b = 2 # new address generation. therefore without pointer behaviour
a
>>> 1
A atribuição de ponteiros é uma ferramenta bastante útil para aliar sem o desperdício de memória extra, em certas situações para executar o código confortável,
class cls_X():
...
def method_1():
pd1 = self.obj_clsY.dict_vars_for_clsX['meth1'] # pointer dict 1: aliasing
pd1['var4'] = self.method2(pd1['var1'], pd1['var2'], pd1['var3'])
#enddef method_1
...
#endclass cls_X
Mas é preciso estar ciente desta utilização para evitar erros de código.
Para concluir, por padrão, algumas variáveis são barenames (objetos simples, como int, float, str,...), e alguns são ponteiros quando atribuídos entre eles (por exemplo, dict1 = dict2). Como reconhecê-los? experimenta esta experiência com eles. Em IDEs com o painel Explorer variável normalmente parece ser o endereço de memória ("@axbbbbb...") in the definition of pointer-mechanism objects.
Sugiro que investiguem o assunto. Há muitas pessoas que sabem muito mais sobre este tema com certeza. (ver módulo" ctypes"). Espero que seja útil. Aproveite o bom uso dos objetos! Regards, José CrespoDe um ponto de vista, Tudo é um ponteiro em Python. O seu exemplo funciona muito como o código C++.
int* a = new int(1);
int* b = a;
a = new int(2);
cout << *b << endl; // prints 1
(um equivalente mais próximo usaria algum tipo de shared_ptr<Object>
em vez de int*
.)
Eis um exemplo: formulario.dados ["Campo"] e formulario.campo.valor para ter sempre o o mesmo valor. Não é completamente necessário, mas acho que seria bom.
Pode fazer isto sobrecarregando __getitem__
na classe de form.data
.
id(1)
1923344848 # identity of the location in my memory
>> a = 1
>> b = a # or equivalently b = 1, because 1 is immutable
>> id(a)
1923344848
>> id(b)
1923344848
Como podem ver a
e b
são apenas Nomes que se referem ao mesmo objecto 1
. Se mais tarde escrever a = 2
, irá atribuir o nome a
a um objecto diferente 2
, mas não ao b
que irá continuar a referir-se a 1
:
>> id(2)
1923344880
>> a = 2
>> id(a)
1923344880 # same as id(2)
>> id(b)
1923344848 # same as id(1)
O que acontecerá se tiver um objecto mutável?
>> id([1])
328817608
>> id([1])
328664968 # different
>> a = [1]
>> id(a)
328817800
>> id(a)
328817800 # same as before
>> b = a # not equivalent to b = [1]
>> id(b)
328817800 # same as id(a)
Agora, estás a referir-te ao mesmo objecto de Lista pelos nomes a
e b
. Você pode mutar esta lista, mas ela permanecerá o mesmo objeto, e a
e b
ambos vão continuar a referir-se a ele
>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800 # same as before
>> id(b)
328817800 # same as before