2017-03-11 35 views
6

Python 3.5 altında çalıştırılmak istediğim Python 3.5 için yazılmış bir kaynak kodum var. Kullanmakta olduğum 3.5’ten gelen tek özellik, 3.4’te mevcut değil, bu yüzden bunları tamamen kaldırmak için bir komut dosyası yazmak istiyorum.Python kaynağındaki tip ipuçlarını programsal olarak kaldırın

Bu ilk bakışta yeterince kolay görünüyordu ve bunu yapmak için bazı düzenli ifadeler yazmaya karar verdim, ancak sonra birkaç kenar durumu hakkında düşündüm ve bu gibi daha karmaşık bir işlev için sorunu nasıl çözeceğinden emin değildim:

def foo(bar: Dict[T, List[T]], 
     baz: Callable[[T], int] = lambda x: (x+3)/7, 
     **kwargs) -> List[T]: 

Temelde, hepsini ayrıştırmak ve tip ek açıklaması olmayan argüman listesi yeniden gerekirdi. Buna nasıl yaklaşabilirim? D kaynak kodunu ayrıştırmak için

için Python'un yerleşik ast modülü ve daha sonra mükemmel astunparse kütüphane yeniden çözümlenen ast kaynak kodu oluşturmak için:

+1

[AST modülü] (https://docs.python.org/3/library/ast.html) esp kaynak dönüşüm görevleri arkadaşın. ['NodeTransformer'] (https://docs.python.org/3/library/ast.html#ast.NodeTransformer). Tersine, 3. parti paketine ihtiyacınız olabilir. –

+0

teşekkürler. wow, bu şeyler karmaşıktır ... Ben bu grameri kullanarak tür ipuçlarını tanımak bile bilmiyordum – Klamann

+1

[gramer] bir göz atın (https://docs.python.org/3/library/ast.html # soyut-dilbilgisi): örneğin 'arg' opsiyonel expr 'ek açıklama 've' FunctionDef' opsiyonel expr 'geri dönüşleri içerir. Transformatörün bunları çıkaracaktı. –

cevap

6

Tamam, buldum. Sonra geriye tüm tip açıklamaları kaldırmaktır: AST

import ast 
import astunparse 

source=""" 
import typing 
from typing import Dict, T, Callable 
from typing import List 

def foo(bar: Dict[T, List[T]], 
     baz: Callable[[T], int] = lambda x: (x+3)/7, 
     **kwargs) -> List[T]: 
    pass 
""" 

class TypeHintRemover(ast.NodeTransformer): 

    def visit_FunctionDef(self, node): 
     # remove the return type defintion 
     node.returns = None 
     # remove all argument annotations 
     if node.args.args: 
      for arg in node.args.args: 
       arg.annotation = None 
     return node 

    def visit_Import(self, node): 
     node.names = [n for n in node.names if n.name != 'typing'] 
     return node if node.names else None 

    def visit_ImportFrom(self, node): 
     return node if node.module != 'typing' else None 

# parse the source code into an AST 
parsed_source = ast.parse(source) 
# remove all type annotations, function return type definitions 
# and import statements from 'typing' 
transformed = TypeHintRemover().visit(parsed_source) 
# convert the AST back to source code 
print(astunparse.unparse(transformed)) 

TypeHintRemover ziyaretleri tüm Düğümleri ve fonksiyon argümanları içinde tüm tip ipuçlarını kaldırır, her işlevin dönüş türü tanımları ve başvuran tüm ithalat ifadeleri 'yazarak' modülü.

sonucudur:

def foo(bar, baz=(lambda x: ((x + 3)/7)), **kwargs): 
    pass 
+0

ne demek istiyorsun? – Klamann

+0

Python 3'te [tür ipuçları] (https://www.python.org/dev/peps/pep-0484/) hakkında bir şeyler okumalısınız, bunların büyük bir hayranıyım. Bu örnekte, giriş ve çıkış, yürütme söz konusu olduğunda eşdeğerdir. Örnek: 'bar'ın, bir tür ipucu olan, bir ['Callable'] olması gerekir (https://docs.python.org/3/library/typing.html#typing.Callable): 've lambda bu argümanın varsayılan değeridir. Tür ipucu tamamen isteğe bağlıdır ve çalışma zamanı sırasında değerlendirilmez. – Klamann

+1

o zaman lütfen tam olarak neyin eksik olduğunu söyle, çünkü görebildiğimden, bir tür ipucu olmayan her şey hala var. – Klamann