2013-05-12 10 views
6

[EDIT 00]: Ich habe mehrmals den Beitrag und jetzt sogar den Titel bearbeitet, lesen Sie bitte weiter unten.Python String Interpolation Implementierung

ich gerade gelernt, über das Format String-Methode, und seine Verwendung mit Wörterbüchern, wie die mitgelieferten durch vars(), locals() und globals(), Beispiel:

name = 'Ismael' 
print 'My name is {name}.'.format(**vars()) 

Aber ich tun möchte:

name = 'Ismael' 
print 'My name is {name}.' # Similar to ruby 

So kam ich mit auf den Punkt:

def mprint(string='', dictionary=globals()): 
    print string.format(**dictionary) 

Sie können hier mit dem Code interagieren: http://labs.codecademy.com/BA0B/3#:workspace

Schließlich, was ich liebe zu tun ist, um die Funktion in einer anderen Datei haben, my_print.py benannt, so konnte ich tun:

from my_print import mprint 

name= 'Ismael' 
mprint('Hello! My name is {name}.') 

Aber wie es Momentan gibt es ein Problem mit den Scopes. Wie kann ich den Namespace des Hauptmoduls als ein Wörterbuch aus der importierten mprint-Funktion erhalten? (nicht die von my_print.py)

Ich hoffe, ich habe mich verstanden, wenn nicht, versuchen Sie, die Funktion von einem anderen Modul zu importieren. (Die Rückverfolgungs ist in der Verbindung)

Es ist die globals() dict von my_print.py Zugriff, aber natürlich der Variablenname wird nicht in diesem Bereich definiert, alle Ideen, wie dies zu erreichen?

Die Funktion funktioniert, wenn es im selben Modul definiert ist, aber beachten Sie, wie ich globals() verwenden muss, denn wenn nicht, würde ich nur ein Wörterbuch mit den Werten innerhalb mprint() Bereich bekommen.

Ich habe versucht, nichtlokale und Punktnotation zu verwenden, um auf die Hauptmodulvariablen zuzugreifen, aber ich kann es immer noch nicht herausfinden.


[EDIT 01]: Ich glaube, ich habe eine Lösung herausgefunden:

In my_print.py:

def mprint(string='',dictionary=None): 
    if dictionary is None: 
     import sys 
     caller = sys._getframe(1) 
     dictionary = caller.f_locals 
    print string.format(**dictionary) 

In test.py:

from my_print import mprint 

name = 'Ismael' 
country = 'Mexico' 
languages = ['English', 'Spanish'] 

mprint("Hello! My name is {name}, I'm from {country}\n" 
     "and I can speak {languages[1]} and {languages[0]}.") 

Es druckt:

Hello! My name is Ismael, I'm from Mexico 
and I can speak Spanish and English. 

Was denkst du, Leute? Das war schwierig für mich!

Ich mag es, viel lesbarer für mich.


[EDIT 02]: Ich habe ein Modul mit einer interpolate Funktion vorgenommen haben, eine Interpolate Klasse und ein Versuch für eine interpolate Klassenmethode analog der Funktion.

Es hat eine kleine Testsuite und seine dokumentiert!

Ich bin mit der Methodenimplementierung fest, ich verstehe es nicht.

Hier ist der Code: http://pastebin.com/N2WubRSB

Was denkt ihr?


[EDIT 03]: Ok Ich habe jetzt nur mit der interpolate() Funktion angesiedelt.

In string_interpolation.py:

import sys 


def get_scope(scope): 
    scope = scope.lower() 
    caller = sys._getframe(2) 
    options = ['l', 'local', 'g', 'global'] 

    if scope not in options[:2]: 
     if scope in options[2:]: 
      return caller.f_globals 
     else: 
      raise ValueError('invalid mode: {0}'.format(scope)) 
    return caller.f_locals 


def interpolate(format_string=str(),sequence=None,scope='local',returns=False): 
    if type(sequence) is str: 
     scope = sequence 
     sequence = get_scope(scope) 
    else: 
     if not sequence: 
      sequence = get_scope(scope) 

    format = 'format_string.format(**sequence)' 
    if returns is False: 
     print eval(format) 

    elif returns is True: 
     return eval(format) 

Nochmals vielen Dank Jungs! Irgendwelche Meinungen?


[EDIT 04]:

Dies ist meine letzte Version, hat es ein Test, Docstrings und beschreibt einige Einschränkungen die ich gefunden habe: http://pastebin.com/ssqbbs57

Sie können schnell den Code testen hier : http://labs.codecademy.com/BBMF#:workspace

Und Klon grom git Repo hier: https://github.com/Ismael-VC/python_string_interpolation.git

+2

bezogen werden: [? Ist ein String Formatierer, die Variablen von seinem Aufruf Umfang schlechte Praxis zieht] (http://stackoverflow.com/questions/13312240/is- a-string-formatter-that-zieht-variables-from-it-ruf-scope-bad-practice) – jfs

+1

verwandt: [Druck Variablennamen und Inhalte als Debugging-Tool; Suche nach Emacs/Python-Verknüpfung] (http://stackoverflow.com/questions/2813227/printing-variable-names-and-contents-as-debugging-tool-looking-for-emacs-python) – jfs

+0

Dies ist eine interessante Übung , aber ich warne vor dieser Art von implizitem Verhalten: Python rät davon ab ("Explizit ist besser als implizit" bedeutet hier, dass "mprint ('...', vars())' 'besser ist als 'mprint (' ... ')" zurück zum Aufrufer und seine lokalen Variablen erhalten), und ich denke, dass es aus guten Gründen tut (der explizite Code ist zweifellos einfacher zu lesen und beizubehalten). – EOL

Antwort

0

Sprache-Entwurf löst nicht gerade Rätsel: ;)

http://www.artima.com/forums/flat.jsp?forum=106&thread=147358

Edit:PEP-0498 löst dieses Problem!

Die Template Klasse aus dem string Modul, auch tut, was ich brauche (aber ähnlich den String format-Methode), am Ende hat es auch die Lesbarkeit ich suche, es hat auch die Ausführlichkeit empfohlen, ist es in der Standard- Bibliothek und es kann auch leicht angepasst und erweitert werden.

http://docs.python.org/2/library/string.html?highlight=template#string.Template

from string import Template 

name = 'Renata' 
place = 'hospital' 
job = 'Dr.' 
how = 'glad' 
header = '\nTo Ms. {name}:' 

letter = Template(""" 
Hello Ms. $name. 

I'm glad to inform, you've been 
accepted in our $place, and $job Red 
will ${how}ly recieve you tomorrow morning. 
""") 

print header.format(**vars()) 
print letter.substitute(vars()) 

Das Komische ist, dass ich jetzt bin immer mehr gern mit {} statt $ und ich immer noch wie das string_interpolation Modul kam ich mit, weil es weniger Typisierung ist als entweder ein in auf lange Sicht. LOL!

Führen Sie den Code hier:

http://labs.codecademy.com/BE3n/3#:workspace

1

Ein Teil Ihres Problems - nun, der Grund, warum es nicht funktioniert - ist in this question hervorgehoben.

Sie können Ihre Funktion funktionieren lassen, indem Sie globals() als zweites Argument übergeben, mprint('Hello my name is {name}',globals()).

Obwohl es in Ruby bequem sein könnte, würde ich Sie ermutigen, Ruby in Python nicht zu schreiben, wenn Sie das Beste aus der Sprache machen möchten.

+0

Ich möchte nur weniger wirklich eingeben! ;) Ich habe angefangen, das Idiom ''' .format (** vars())' sehr in meinen Skripten zu verwenden, dann habe ich neu formatiert, ich musste das umgestalten, also tat ich es (probiert), es interessiert mich nicht wirklich sieht aus wie Rubin oder nicht, da ich bis vor kurzem nichts über Programmierung wusste, aber es sieht immer noch viel lesbarer für mich aus, und ich benutze es sehr für die einfache Formatierung. Ich möchte es so nennen können: 'from my_print import mprint; name = 'Ismael'; mprint ('Hallo! Mein Name ist {Name}.') 'Ohne die Globals, etc jedes Mal anrufen nur um zu wissen, wie es gemacht werden könnte, muss es einen Weg geben! – SalchiPapa

+0

Im Grunde, was ich erreichen möchte, ist dies das Standardverhalten zu machen: 'mprint ('Hallo, mein Name ist {Name}', vars())' ohne jedesmal explizit vars() aufzurufen.Danke für den Link übrigens! – SalchiPapa

2

Module teilen keine Namespaces in Python, daher wird globals() für my_print immer die globals() der Datei my_print.py sein; d. h. der Ort, an dem die Funktion tatsächlich definiert wurde.

def mprint(string='', dic = None): 
    dictionary = dic if dic is not None else globals() 
    print string.format(**dictionary) 

Sie sollten die Globals() des aktuellen Moduls explizit übergeben, damit es funktioniert.

Ans verwenden keine veränderbaren Objekte als Standardwerte in Python-Funktionen, es kann unexpected results ergeben. Verwenden Sie stattdessen None als Standardwert.

Ein einfaches Beispiel für Bereiche in Module Verständnis:

Datei: my_print.py

x = 10 
def func(): 
    global x 
    x += 1 
    print x 

Datei: main.py

from my_print import * 
x = 50 
func() #prints 11 because for func() global scope is still 
     #the global scope of my_print file 
print x #prints 50 
+0

Gibt es keine Möglichkeit, den Namespace 'main.py' von' my_print.py' als Diktat zu erhalten? Ich lese jetzt gerade über Vererbung, würde nicht eine Klasse Punktnotation den Trick machen? Aber dann müsste ich die Klasse aufrufbar machen? LOL Ich werde es für heute einen Tag nennen, danke Ashwini! – SalchiPapa

+0

Von python docs: http://docs.python.org/2/library/functions.html#vars Also muss ich main.py "__dict__" aus mprint, ist es wirklich unmöglich? Ich kann nicht aufhören darüber nachzudenken. – SalchiPapa

+0

@ user2374329 Sie können 'main .__ dict__' verwenden, aber es enthält nur die Variablen, die definiert wurden, als' main' importiert wurde. Die BTW-Vererbung bezieht sich auf Klassen, nicht auf Module. –