Sé que Python no tiene punteros, pero ¿hay alguna manera de tener este rendimiento en su 2
lugar?
>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1
?
He aquí un ejemplo: quiero form.data['field']
y form.field.value
tener siempre el mismo valor. No es completamente necesario, pero creo que estaría bien.
En PHP, por ejemplo, puedo hacer esto:
<?php
class Form {
public $data = [];
public $fields;
function __construct($fields) {
$this->fields = $fields;
foreach($this->fields as &$field) {
$this->data[$field['id']] = &$field['value'];
}
}
}
$f = new Form([
[
'id' => 'fname',
'value' => 'George'
],
[
'id' => 'lname',
'value' => 'Lucas'
]
]);
echo $f->data['fname'], $f->fields[0]['value']; # George George
$f->data['fname'] = 'Ralph';
echo $f->data['fname'], $f->fields[0]['value']; # Ralph Ralph
Salida:
GeorgeGeorgeRalphRalph
O así en C ++ (creo que esto es correcto, pero mi C ++ está oxidado):
#include <iostream>
using namespace std;
int main() {
int* a;
int* b = a;
*a = 1;
cout << *a << endl << *b << endl; # 1 1
return 0;
}
a, b = b, a
.Respuestas:
Esto es factible, porque implica nombres decorados e indexación, es decir, construcciones completamente diferentes de las barenames
a
y sobre lasb
que estás preguntando, y porque con tu solicitud es completamente imposible. ¿Por qué pedir algo imposible y totalmente diferente de lo (posible) que realmente quieres ?Tal vez no se dé cuenta de lo drásticamente diferentes que son las barenames y los nombres decorados. Cuando se refiere a un nombre desnudo
a
, obtiene exactamente el objeto al quea
se vinculó por última vez en este alcance (o una excepción si no estaba vinculado en este alcance); este es un aspecto tan profundo y fundamental de Python que puede Posiblemente no sea subvertido. Cuando te refieres a un nombre decoradox.y
, le estás pidiendo a un objeto (al que sex
refiere el objeto ) que proporcione "ely
atributo", y en respuesta a esa solicitud, el objeto puede realizar cálculos totalmente arbitrarios (y la indexación es bastante similar: también permite realizar cálculos arbitrarios en respuesta).Ahora, su ejemplo de "desiderata real" es misterioso porque en cada caso están involucrados dos niveles de indexación o obtención de atributos, por lo que la sutileza que anhela podría introducirse de muchas maneras. ¿Qué otros atributos se
form.field
supone que tiene, por ejemplo, ademásvalue
? Sin esos.value
cálculos adicionales , las posibilidades incluirían:y
La presencia de
.value
sugiere elegir la primera forma, además de una especie de envoltorio inútil:Si se supone que estas asignaciones
form.field.value = 23
también establecen la entradaform.data
, entonces el contenedor debe volverse más complejo, y no tan inútil:El último ejemplo es más o menos lo más parecido, en Python, al sentido de "un puntero" que parece desear, pero es crucial comprender que tales sutilezas solo pueden funcionar con indexación y / o nombres decorados , nunca con barenames como pediste originalmente!
fuente
No hay forma de que puedas hacer eso cambiando solo esa línea. Tu puedes hacer:
Eso crea una lista, asigna la referencia a a, luego b también, usa la referencia a para establecer el primer elemento en 2, luego accede usando la variable de referencia b.
fuente
a
yb
es la lista, no el valor en la lista. Las variables no cambian de asignación, el objeto es el mismo objeto. Si cambiara, como en el caso de cambiar el número entero (cada uno de los cuales son objetos diferentes),a
ahora se asignaría a otro objeto y no hay nada que indique lob
siguiente. Aquí,a
no se está reasignando, sino que está cambiando un valor dentro del objeto al que está asignado. Dadob
que todavía está vinculado a ese objeto, reflejará ese objeto y los cambios en los valores dentro de él.No es un error, es una característica :-)
Cuando observe el operador '=' en Python, no piense en términos de asignación. No asignas cosas, las atas. = es un operador vinculante.
Entonces, en su código, le está dando al valor 1 un nombre: a. Entonces, le está dando al valor en 'a' un nombre: b. Entonces estás vinculando el valor 2 al nombre 'a'. El valor ligado a b no cambia en esta operación.
Viniendo de lenguajes similares a C, esto puede ser confuso, pero una vez que se acostumbre a él, encontrará que le ayuda a leer y razonar sobre su código más claramente: el valor que tiene el nombre 'b' no cambiará a menos que usted cambiarlo explícitamente. Y si hace una 'importación de esto', encontrará que el Zen de Python establece que Explícito es mejor que implícito.
Tenga en cuenta también que los lenguajes funcionales como Haskell también utilizan este paradigma, con un gran valor en términos de robustez.
fuente
a = 1; b = a; a = 2;
es exactamente el mismo en Python, C y Java: b es 1. ¿Por qué este enfoque en "= no es una asignación, es vinculante"?a
yb
mientras que en Python, ambos se refieren al mismo "1" (creo). Por lo tanto, si pudiera cambiar el valor de 1 (como con los objetos), sería diferente. Lo que lleva a algunos problemas extraños de boxeo / unboxing, escuché.¡Si! ¡Hay una forma de usar una variable como puntero en Python!
Lamento decir que muchas de las respuestas fueron parcialmente incorrectas. En principio, cada asignación igual (=) comparte la dirección de memoria (verifique la función id (obj)), pero en la práctica no es así. Hay variables cuyo comportamiento igual ("=") funciona en último término como una copia del espacio de memoria, principalmente en objetos simples (por ejemplo, objeto "int"), y otras en las que no (por ejemplo, objetos "lista", "dict") .
Aquí hay un ejemplo de asignación de puntero
Aquí hay un ejemplo de asignación de copia
La asignación de puntero es una herramienta bastante útil para crear un alias sin desperdiciar memoria extra, en ciertas situaciones para realizar un código cómodo,
pero hay que ser consciente de este uso para evitar errores de código.
Para concluir, por defecto algunas variables son barenames (objetos simples como int, float, str, ...), y algunas son punteros cuando se asignan entre ellas (por ejemplo, dict1 = dict2). ¿Cómo reconocerlos? prueba este experimento con ellos. En IDE con panel de explorador de variables, generalmente aparece la dirección de memoria ("@axbbbbbb ...") en la definición de objetos de mecanismo de puntero.
Sugiero investigar en el tema. Seguro que hay mucha gente que sabe mucho más sobre este tema. (ver módulo "ctypes"). Espero que sea útil. ¡Disfruta del buen uso de los objetos! Saludos, José Crespo
fuente
Como se puede ver
a
, yb
son sólo dos nombres diferentes que hacen referencia a la misma objeto inmutable (int)1
. Si luego escribea = 2
, reasigna el nombrea
a un objeto diferente (int)2
, pero lab
referencia continúa a1
:¿Qué pasaría si tuviera un objeto mutable en su lugar, como una lista
[1]
?Nuevamente, estamos haciendo referencia al mismo objeto (lista)
[1]
con dos nombres diferentesa
yb
. Sin embargo ahora podemos mutar esta lista mientras que sigue siendo el mismo objeto, ya
,b
a los dos para continuar haciendo referencia a ellafuente
Desde un punto de vista, todo es un puntero en Python. Su ejemplo funciona de manera muy similar al código C ++.
(Un equivalente más cercano usaría algún tipo de en
shared_ptr<Object>
lugar deint*
).Puede hacer esto sobrecargando la clase de
__getitem__
inform.data
.fuente
form.data
no es una clase. ¿Es necesario convertirlo en uno o puedo anularlo sobre la marcha? (Es solo un dictado de Python) Además, los datos tendrían que tener una referenciaform
para acceder a los campos ... lo que hace que implementar esto sea feo.Este es un puntero de Python (diferente de c / c ++)
fuente
Escribí la siguiente clase simple como, efectivamente, una forma de emular un puntero en Python:
Aquí hay un ejemplo de uso (de una página de cuaderno de jupyter):
Por supuesto, también es fácil hacer que esto funcione para dict elementos o atributos de un objeto. Incluso hay una forma de hacer lo que pidió el OP, usando globals ():
Esto imprimirá 2, seguido de 3.
Jugar con el espacio de nombres global de esta manera es, de manera transparente, una idea terrible, pero muestra que es posible (si no es aconsejable) hacer lo que pidió el OP.
El ejemplo es, por supuesto, bastante inútil. Pero he encontrado que esta clase es útil en la aplicación para la que la desarrollé: un modelo matemático cuyo comportamiento se rige por numerosos parámetros matemáticos configurables por el usuario, de diversos tipos (que, debido a que dependen de argumentos de línea de comando, no se conocen en tiempo de compilación). Y una vez que el acceso a algo se ha encapsulado en un objeto de parámetro, todos esos objetos se pueden manipular de manera uniforme.
Aunque no se parece mucho a un puntero C o C ++, esto está resolviendo un problema que habría resuelto con punteros si estuviera escribiendo en C ++.
fuente
El siguiente código emula exactamente el comportamiento de los punteros en C:
A continuación se muestran ejemplos de uso:
Pero ahora es el momento de dar un código más profesional, incluida la opción de eliminar punteros, que acabo de encontrar en mi biblioteca personal:
fuente