2009-04-23 7 views
7

compact() und extract() sind Funktionen in PHP finde ich enorm praktisch. compact() nimmt eine Liste von Namen in der Symboltabelle und erstellt eine Hashtabelle nur mit ihren Werten. Auszug macht das Gegenteil. z. B.Python Äquivalent von PHP's compact() und extract()

$foo = 'what'; 
$bar = 'ever'; 
$a = compact('foo', 'bar'); 
$a['foo'] 
# what 
$a['baz'] = 'another' 
extract(a) 
$baz 
# another 

Gibt es eine Möglichkeit, dasselbe in Python zu tun? Ich habe mich rundherum umgeschaut und das nächste, was ich je gesehen habe, ist this thread, das scheint mich zu verärgern.

Ich weiß über Locals(), Globals() und Vars(), aber wie kann ich nur eine Teilmenge ihrer Werte auswählen?

Hat Python etwas noch besser, das die Notwendigkeit dafür beseitigt?

+4

Ok, ich denke ich sehe was mich verwirrte. Es sieht so aus, als ob Ihre Zeile 3 "$ a = kompakt ('foo', 'bar') sein sollte;" stattdessen. – pantsgolem

+0

oops, danke. Ich habe es gerade korrigiert. – Turadg

+0

Kann ich fragen, warum Sie sie praktisch finden? Ich sehe nicht, wofür sie gut sind, die mit hashtables nicht sauberer implementiert werden könnten. –

Antwort

10

Es ist nicht sehr Pythonic, aber wenn Sie wirklich müssen:

import inspect 

def compact(*names): 
    caller = inspect.stack()[1][0] # caller of compact() 
    vars = {} 
    for n in names: 
     if n in caller.f_locals: 
      vars[n] = caller.f_locals[n] 
     elif n in caller.f_globals: 
      vars[n] = caller.f_globals[n] 
    return vars 

def extract(vars): 
    caller = inspect.stack()[1][0] # caller of extract() 
    for n, v in vars.items(): 
     caller.f_locals[n] = v # NEVER DO THIS - not guaranteed to work 

ich diese Implementierungen ziemlich viel gearbeitet haben, und sie arbeiten, aber technisch Das Ändern von f_locals wird nicht unterstützt.

Im Ernst, wenn Sie wirklich das Gefühl haben, dass Sie diese Funktionen brauchen, tun Sie wahrscheinlich etwas falsch. Es scheint in mindestens drei Punkten gegen Python's philosophy zu laufen: "Explizit ist besser als Implizit", "Einfach ist besser als Komplex", "Wenn die Implementierung schwer zu erklären ist, ist es eine schlechte Idee", vielleicht mehr (und wirklich, wenn Sie haben genug Erfahrung in Python, Sie wissen, dass solche Sachen einfach nicht gemacht werden. Ich könnte sehen, dass es nützlich für einen Debugger oder Post-Mortem-Analyse, oder vielleicht für eine Art von sehr allgemeinen Framework, das häufig Variablen mit dynamisch gewählten Namen und Werten erstellen muss, aber es ist eine Strecke.

Wenn Sie diese Funktionen verwenden, sollten Sie zumindest die enthaltenen extract Variablen in kleinen Bereichen halten. Wickeln Sie sie in Funktionen, die Sie dann als "Black Boxes" betrachten können. Der Hauptgrund, extract ist schlecht ist, dass es Variablen in Ihre Symboltabelle in einer Weise platziert, die aus der Überprüfung des Codes nicht klar ist. Wenn Sie die Auswirkungen dieser Variablen auf eine sehr kleine Funktion beschränken und erklären, was Sie mit klarem Code und Kommentaren tun, ist das kein großes Problem.

2

Ich denke, das Äquivalent von extract($x)globals().update(x) ist, wie für compact() ist es eine Teilmenge von vars()

>>> foo, bar, baz = 1, 2, 3 
# extract 
>>> globals().update({"foo": 4, "qux": 5}) 
>>> foo 
4 
>>> qux 
5 
# compact 
>>> d = dict((k, v) for k, v in vars().iteritems() if k in ["foo", "bar"]) 
>>> d 
{'bar': 2, 'foo': 1} 
9

Ich fürchte, es gibt keine Äquivalente in Python. Bis zu einem gewissen Grad kann man die Wirkung mit (und passing) simuliert locals:

>>> def compact(locals, *keys): 
...  return dict((k, locals[k]) for k in keys) 
... 
>>> a = 10 
>>> b = 2 
>>> compact(locals(), 'a', 'b') 
{'a': 10, 'b': 2} 

>>> def extract(locals, d): 
...  for k, v in d.items(): 
...   locals[k] = v 
... 
>>> extract(locals(), {'a': 'foo', 'b': 'bar'} 
>>> a 
'foo' 
>>> b 
'bar' 

Aber ich glaube nicht, diese Funktionen sind „enorm praktisch“. Dynamische globale/lokale Variablen sind böse und fehleranfällig - PHP-Leute haben gelernt, dass sie register_globals entmutigen. Aus meiner Erfahrung verwenden nur wenige erfahrene PHP-Programmierer oder wichtige Frameworks compact() oder extract().

In Python explicit is better than implicit:

a = 1 
b = 2 
# compact 
c = dict(a=a, b=b) 

# extract 
a, b = d['a'], d['b'] 
+0

Ich bin alles für explizite, aber warum muss es redundant sein? wäre das nicht weniger fehleranfällig? c = kompakt (a, b) – Turadg

+6

Ändern Sie nicht die Locals()! http://docs.python.org/library/functions.html#locals –

6

Ist es erwähnenswert, dass extract() (und in geringerem Maße, compact()) ist einer der „bösen“ Features von PHP (zusammen mit register_globals und eval), und soll vermieden werden?

extract macht es viel schwieriger zu bestimmen, wo eine Variable definiert wurde. Wenn es schwieriger ist, eine Variable zurück zu verfolgen, wo sie definiert wurde, ist es schwieriger, nach allgemeinen Sicherheitsproblemen zu suchen, wie zum Beispiel nicht initialisierte Variablen oder ungefilterte Variablen, die von Benutzereingaben stammen.

compact ist nicht so schlecht, aber wenn es schlecht verwendet wird, kann es immer noch schwieriger als sonst sein, zu sehen, wo ein Array-Mitglied aus einer Variablen gesetzt wird.

Das Äquivalent von extract() in vielen anderen Sprachen ist das with Schlüsselwort. Python hat jetzt ein with Schlüsselwort, obwohl es ein bisschen anders funktioniert, was es nicht ganz wie extract() macht. In anderen Sprachen wie z. B. Javascript, das with Stichwort also has a poor reputation.

Ich denke, der beste Rat wäre, anders zu denken - anstatt zu versuchen, ein schlechtes Feature von PHP zu emulieren, denke über andere Möglichkeiten nach, was du mit klarem und lesbarem Code machen willst.

+1

Bitte beachten Sie, dass die 'with'-Anweisung in Python eine völlig andere Semantik als in JavaScript hat und keinen "Variablenbereich" ändert. Es ist auch ein ziemlich neues Feature und hat sicherlich keinen schlechten Ruf. Du hast recht mit dem JavaScript- "mit", though. –

+0

Danke Ferdinand, ich habe die Antwort ein wenig bearbeitet – thomasrutter

+0

Ich habe es so bearbeitet, dass es keinen Sinn mehr macht, weil es nicht in einen Kommentar passt, aber alles ist wichtig. Ich habe es danach nicht zurückgerollt, weil es in einen Kommentar umgewandelt wurde. Ich habe es gelöscht, weil ich gespürt habe, dass es die Frage nicht beantwortet hat, denn, wie es im ersten Satz Ihres Kommentars steht, zeigen Sie nur etwas an. – Ryan

3

kompakte Funktion in Python PHP (funktioniert mit 2.6, nicht garantiert mit früheren Versionen von Python arbeiten):

import inspect 
def compact(*args): 
    return dict([(i, inspect.currentframe().f_back.f_locals.get(i, None)) 
        for i in args]) 

ich ausführliche darüber geschrieben habe: Python can be just as ugly as PHP.

1

Sie können dies tun (obwohl ich würde nur sparsam vorschlagen ...) mit der locals()-Funktion, die eine aktualisierbare dict zurückgibt. Beispiel:

$ python 
Python 2.7.12 (default, Jul 1 2016, 15:12:24) 
>>> locals().update({'derek':'anderson'}) 
>>> derek 
'anderson' 
>>> 

So locals() würde "compact alle" sein und locals().update() würde extract sein.

Viel Glück!