2013-05-12 23 views
6

[EDIT 00]: Edytowałem kilka razy post, a teraz nawet tytuł, przeczytaj poniżej.Implementacja interpolacji ciągów znaków Python

Właśnie dowiedziałem się o metodzie format string, a jego stosowanie ze słowników, jak te świadczone przez vars(), locals() i globals(), przykład:

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

Ale chcę zrobić:

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

Więc wpadłem na to:

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

można wchodzić w interakcje z kod tutaj: http://labs.codecademy.com/BA0B/3#:workspace

Wreszcie, co chciałbym zrobić, to mieć funkcję w innym pliku, o nazwie my_print.py, więc mogłem zrobić:

from my_print import mprint 

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

ale jak to jest teraz, istnieje problem z zakresami, w jaki sposób mogę uzyskać obszar nazw głównego modułu jako słownik z importowanej funkcji mprint. (nie ten z my_print.py)

Mam nadzieję, że zrobiłem sobie spokój, jeśli nie, spróbuj zaimportować funkcję z innego modułu. (traceback jest w łączu)

Dostęp do dyktafonu globals() od my_print.py, ale oczywiście nazwa zmiennej nie jest zdefiniowana w tym zakresie, żadnych pomysłów, jak to osiągnąć?

Funkcja działa, jeśli jest zdefiniowana w tym samym module, ale zauważ, że muszę użyć globals(), ponieważ jeśli nie, to dostanę tylko słownik z wartościami z zakresu mprint().

Próbowałem używać nielokalnej i notacji kropkowej, aby uzyskać dostęp do zmiennych głównych modułu, ale nadal nie mogę tego rozgryźć.


[EDIT 01]: Myślę, że zorientowali się rozwiązanie:

W 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) 

W 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]}.") 

Drukuje:

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

Jak myślisz, chłopaki? To było dla mnie trudne!

Lubię to, o wiele bardziej czytelne dla mnie.


[Edycja 02]: wprowadzonych modułu z interpolate funkcji, klasy Interpolate i próbą dla sposobu interpolate klasy analogiczny do funkcji.

Ma mały pakiet testowy i jest udokumentowany!

Utknąłem z wdrożenia metody, nie rozumiem.

Oto kod: http://pastebin.com/N2WubRSB

Co sądzisz faceci?


[EDIT 03]: Ok mam rozliczane tylko z funkcji interpolate() teraz.

W 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) 

Jeszcze raz dziękuję wam! Jakieś opinie?


[EDIT 04]:

To moja ostatnia wersja, ma testów, docstrings i opisuje pewne ograniczenia Znalazłem: http://pastebin.com/ssqbbs57

Można szybko przetestować kod tutaj : http://labs.codecademy.com/BBMF#:workspace

A klon Grom git repo tutaj: https://github.com/Ismael-VC/python_string_interpolation.git

+2

related: [? Czy formater ciąg, który ciągnie zmienne z jego wywołującego zakres złej praktyki] (http://stackoverflow.com/questions/13312240/is- a-string-formatter-that-pulls-variables-from-its-calling-scope-bad-practice) – jfs

+1

pokrewne: [drukowanie nazw zmiennych i zawartości jako narzędzie do debugowania; szukanie skrótu emacs/Python] (http://stackoverflow.com/questions/2813227/printing-variable-names-and-contents-as-debugging-toollooking-for-emacs-python) – jfs

+0

To jest ciekawe ćwiczenie , ale ostrzegam przed tego rodzaju niejawnym zachowaniem: Python zniechęca go ("Jawny jest lepszy niż niejawny" oznacza tutaj, że 'mprint (" ... ", vars())' jest lepszy niż 'mprint (" ... ') " wróć do dzwoniącego i uzyskaj jego lokalne zmienne) i myślę, że robi to z ważnych powodów (wyraźny kod jest prawdopodobnie łatwiejszy do odczytania i utrzymania). – EOL

Odpowiedz

0

Język Projekt to nie tylko rozwiązywanie zagadek: ;)

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

Edit:PEP-0498 rozwiązuje ten problem!

Template klasa z modułu string, czy też to, czego potrzebuję (ale bardziej podobna do metody ciąg format), w końcu to ma również czytelność szukam, ma też zalecaną jednoznaczność, to jest w normie Bibliotekę można również łatwo dostosować i rozszerzyć.

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()) 

Najśmieszniejsze jest to, że teraz jestem coraz bardziej lubiący użyciu {} zamiast $ i nadal lubię modułu string_interpolation wymyśliłem, bo to mniej wpisując niż jeden z nich w długi bieg. LOL!

uruchomić kod tutaj:

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

1

Część twojego problemu - cóż, powód, dla którego nie działa - jest podświetlony w this question.

Możesz użyć swojej funkcji, przekazując globals() jako drugi argument, mprint('Hello my name is {name}',globals()).

Chociaż może to być wygodne w Ruby, zachęcam do pisania Rubiego w Pythonie, jeśli chcesz w pełni wykorzystać język.

+0

Po prostu chcę mniej pisać! ;) Zacząłem używać idiomu '' '.format (** vars()) 'dużo w moich skryptach, a potem ponownie widziałem, musiałem to zmienić, więc zrobiłem (próbowałem), nie obchodzi mnie to, Wygląda jak rubin albo nie, ponieważ nie wiedziałem nic o programowaniu do niedawna, ale wciąż wygląda na znacznie czytelniej, a ja używam go do prostego formatowania. Chciałbym móc to tak nazwać: 'from my_print import mprint; name = 'Ismael'; mprint ("Witaj, mam na imię {imię}.") "Bez globali, itd. za każdym razem zadzwoń, żeby wiedzieć, jak to zrobić, musi być jakiś sposób! – SalchiPapa

+0

Zasadniczo chcę osiągnąć to domyślne zachowanie: 'mprint (" Cześć, nazywam się {name} ", vars())' bez jawnego wywoływania vars() za każdym razem.Dzięki za link przy okazji! – SalchiPapa

2

Moduły nie udostępniają przestrzeni nazw w pythonie, więc globals() dla my_print zawsze będzie globals() pliku my_print.py; tj. miejsce, w którym funkcja została faktycznie zdefiniowana.

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

Powinieneś jawnie przekazać globals bieżącego modułu(), aby działał.

Ans nie używaj zmiennoprzecinkowych obiektów jako wartości domyślnych w funkcjach Pythona, może to skutkować unexpected results. Zamiast tego użyj wartości domyślnej None.

Prostym przykładem dla zrozumienia zasięgów w modułach:

pliku: my_print.py

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

pliku: 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

Czy nie istnieje sposób na uzyskanie przestrzeni nazw 'main.py' z,' my_print.py' jako dyktafonu? Czytam teraz o dziedziczeniu, czy notacja klasowa nie wystarczy? Ale wtedy musiałbym skłonić klasę do wywołania ¿? LOL Na razie będę to nazwał, dziękuję Ashwini! – SalchiPapa

+0

Z python docs: http://docs.python.org/2/library/functions.html#vars Muszę więc pobrać main.py '__dict__' z wnętrza mprint, czy to naprawdę niemożliwe? Nie mogę przestać o tym myśleć. – SalchiPapa

+0

@ user2374329 Możesz użyć 'main .__ dict__', ale będzie zawierał tylko zmienne, które zostały zdefiniowane po zaimportowaniu' main'. Dziedziczenie BTW związane jest z klasami, a nie modułami. –

Powiązane problemy