Wiem, Python nie ma wskazówek, ale czy jest jakiś sposób, aby ten plon 2
zamiast
>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1
?
Oto przykład: chcę form.data['field']
i form.field.value
zawsze mieć tę samą wartość. Nie jest to całkowicie konieczne, ale myślę, że byłoby miło.
Na przykład w PHP mogę to zrobić:
<?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
Wynik:
GeorgeGeorgeRalphRalph
Lub tak w C ++ (myślę, że to prawda, ale mój C ++ jest zardzewiały):
#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
.Odpowiedzi:
Jest to możliwe, ponieważ wiąże urządzone nazwiska i indeksowanie - tzn zupełnie różne konstrukcje od barenames
a
ib
że pytasz o, a ze swoim życzeniem jest zupełnie niemożliwe. Po co prosić o coś niemożliwego i całkowicie różniącego się od (możliwej) rzeczy, której naprawdę chcesz ?!Może nie zdajesz sobie sprawy, jak drastycznie różne są barenames i zdobione nazwy. Kiedy odnosisz się do barename
a
, otrzymujesz dokładnie ten obiekt, z któryma
był ostatnio związany w tym zakresie (lub wyjątek, jeśli nie był związany w tym zakresie) - jest to tak głęboki i fundamentalny aspekt Pythona, że może nie może być obalony. Kiedy odnosisz się do ozdobionej nazwyx.y
, prosisz obiekt (obiekt sięx
odnosi) o podanie „y
atrybutu” - w odpowiedzi na to żądanie obiekt może wykonać całkowicie dowolne obliczenia (a indeksowanie jest dość podobne: umożliwia również wykonanie dowolnych obliczeń w odpowiedzi).Twój przykład „rzeczywistych dezyderatów” jest tajemniczy, ponieważ w każdym przypadku występują dwa poziomy indeksowania lub uzyskiwania atrybutów, więc subtelność, której pragniesz, może zostać wprowadzona na wiele sposobów. Jakie inne atrybuty
form.field
mają mieć na przykład na przykładvalue
? Bez tych dalszych.value
obliczeń możliwości obejmowałyby:i
Obecność
.value
sugeruje wybranie pierwszej formy plus rodzaj bezużytecznego opakowania:Jeśli przypisania takie
form.field.value = 23
mają również ustawiać wpisform.data
, to opakowanie musi stać się rzeczywiście bardziej złożone, a nie aż tak bezużyteczne:Ten ostatni przykład jest mniej więcej tak zbliżony, jak to tylko możliwe, w Pythonie, do znaczenia „wskaźnika”, jak chcesz - ale ważne jest, aby zrozumieć, że takie subtelności mogą zawsze działać tylko z indeksowaniem i / lub dekorowanymi nazwami , nigdy z barenames, jak pierwotnie prosiłeś!
źródło
Nie da się tego zrobić, zmieniając tylko tę linię. Możesz to zrobić:
To tworzy listę, przypisuje odniesienie do a, następnie b również, używa odwołania do ustawienia pierwszego elementu na 2, a następnie uzyskuje dostęp za pomocą zmiennej odniesienia b.
źródło
a
ib
lista, a nie wartość na liście. Zmienne nie zmieniają przypisania, obiekt jest tym samym obiektem. Gdyby się zmienił, jak w przypadku zmiany liczby całkowitej (z których każdy jest innym obiektem),a
zostałby teraz przypisany do innego obiektu i nic nie skłaniab
do pójścia w jego ślady. Tutaja
nie jest ponownie przypisywana, a raczej zmienia się wartość wewnątrz obiektu, do którego jest przypisana. Ponieważb
jest nadal powiązany z tym obiektem, będzie odzwierciedlał ten obiekt i zmiany wartości w nim.To nie jest błąd, to jest funkcja :-)
Patrząc na operator „=” w Pythonie, nie myśl w kategoriach przypisania. Nie przypisujesz rzeczy, wiążesz je. = jest operatorem wiążącym.
Zatem w swoim kodzie nadajesz wartości 1 nazwę: a. Następnie podajesz wartość w „a” nazwę: b. Następnie wiążesz wartość 2 z nazwą „a”. Wartość przypisana do b nie zmienia się w tej operacji.
Pochodząc z języków podobnych do języka C, może to być mylące, ale gdy się do tego przyzwyczaisz, okaże się, że pomaga to w jaśniejszym czytaniu i uzasadnianiu kodu: wartość, która ma nazwę `` b '', nie zmieni się, chyba że wyraźnie to zmienić. A jeśli zrobisz „zaimportuj to”, przekonasz się, że Zen of Python stwierdza, że Explicit jest lepsze niż implicit.
Zauważ również, że języki funkcjonalne, takie jak Haskell, również używają tego paradygmatu, z wielką wartością pod względem niezawodności.
źródło
a = 1; b = a; a = 2;
jest dokładnie takie samo w Pythonie, C i Javie: b wynosi 1. Dlaczego skupienie się na "= nie jest przypisaniem, tylko wiąże"?a
ab
podczas gdy w Pythonie oba odnoszą się do tego samego „1” (tak mi się wydaje). Tak więc, gdybyś mógł zmienić wartość 1 (tak jak w przypadku obiektów), byłoby inaczej. Słyszę, że prowadzi to do dziwnych problemów z boksowaniem / rozpakowywaniem.Tak! istnieje sposób na użycie zmiennej jako wskaźnika w Pythonie!
Z przykrością stwierdzam, że wiele odpowiedzi było częściowo błędnych. W zasadzie każde przypisanie równości (=) dzieli adres pamięci (sprawdź funkcję id (obj)), ale w praktyce tak nie jest. Istnieją zmienne, których równe zachowanie („=”) działa w ostatnim terminie jako kopia przestrzeni pamięci, głównie w prostych obiektach (np. Obiekt „int”), i inne, w których nie (np. Obiekty „lista”, „dykt”) .
Oto przykład przypisania wskaźnika
Oto przykład przypisania kopii
Przypisanie wskaźnika to całkiem przydatne narzędzie do aliasingu bez marnowania dodatkowej pamięci, w pewnych sytuacjach do wykonywania wygodnego kodu,
ale trzeba być świadomym tego zastosowania, aby uniknąć błędów w kodzie.
Podsumowując, domyślnie niektóre zmienne to barenames (proste obiekty, takie jak int, float, str, ...), a niektóre są wskaźnikami, gdy są przypisane między nimi (np. Dict1 = dict2). Jak je rozpoznać? po prostu wypróbuj z nimi ten eksperyment. W środowiskach IDE z panelem eksploratora zmiennych zwykle pojawia się adres pamięci („@axbbbbbb…”) w definicji obiektów mechanizmu wskaźnika.
Proponuję zbadać w temacie. Na pewno jest wiele osób, które na ten temat wiedzą znacznie więcej. (zobacz moduł "ctypes"). Mam nadzieję, że jest to pomocne. Ciesz się dobrym użytkowaniem obiektów! Pozdrawiam, José Crespo
źródło
Jak widać
a
ib
są to tylko dwie różne nazwy, które odnoszą się do tego samego niezmiennego obiektu (int)1
. Jeśli później napiszesza = 2
, ponownie przypiszesz nazwęa
do innego obiektu (int)2
, aleb
kontynuacja odwołuje się do1
:Co by się stało, gdybyś zamiast tego miał zmienny obiekt, taki jak lista
[1]
?Ponownie odwołujemy się do tego samego obiektu (listy) za
[1]
pomocą dwóch różnych nazwa
ib
. Jednak teraz możemy mutować tę listę, podczas gdy pozostaje ten sam obiekt, aa
,b
będzie w dalszym ciągu zarówno odniesienie do niegoźródło
Z jednego punktu widzenia w Pythonie wszystko jest wskaźnikiem. Twój przykład działa podobnie jak kod C ++.
(Bliższy odpowiednik użyłby jakiegoś typu
shared_ptr<Object>
zamiastint*
.)Można to zrobić przez przeciążenie
__getitem__
wform.data
„s klasy.źródło
form.data
nie jest klasą. Czy trzeba to zrobić, czy mogę go zastąpić w locie? (To tylko dyktowanie Pythona) Ponadto dane musiałyby mieć odniesienie z powrotem,form
aby uzyskać dostęp do pól ... co sprawia, że implementacja jest brzydka.To jest wskaźnik Pythona (inny niż C / C ++)
źródło
Napisałem następującą prostą klasę jako skuteczny sposób na emulację wskaźnika w Pythonie:
Oto przykład użycia (ze strony notatnika jupyter):
Oczywiście łatwo jest również wykonać tę pracę dla dyktowanych elementów lub atrybutów obiektu. Jest nawet sposób na zrobienie tego, o co prosił OP, używając globals ():
Spowoduje to wydrukowanie 2, a następnie 3.
Majstrowanie w ten sposób z globalną przestrzenią nazw jest w pewnym sensie okropnym pomysłem, ale pokazuje, że można (jeśli jest to niewskazane) zrobić to, o co prosił OP.
Przykład jest oczywiście dość bezcelowy. Okazało się jednak, że ta klasa jest przydatna w aplikacji, dla której ją opracowałem: model matematyczny, którego zachowanie jest regulowane przez wiele ustawianych przez użytkownika parametrów matematycznych, różnego typu (które, ponieważ zależą od argumentów wiersza poleceń, nie są znane w czasie kompilacji). A gdy dostęp do czegoś zostanie zamknięty w obiekcie Parameter, wszystkimi takimi obiektami można manipulować w jednolity sposób.
Chociaż nie wygląda jak wskaźnik C lub C ++, jest to rozwiązanie problemu, który rozwiązałbym za pomocą wskaźników, gdybym pisał w C ++.
źródło
Poniższy kod dokładnie emuluje zachowanie wskaźników w C:
Oto przykłady użycia:
Ale teraz nadszedł czas, aby podać bardziej profesjonalny kod, w tym opcję usuwania wskaźników, które właśnie znalazłem w mojej osobistej bibliotece:
źródło