2016-06-12 8 views
0

Ich arbeite mit ANTLR, um einige Sprache in diesen Tagen zu analysieren. Ich entschied mich, mit Python zu arbeiten. Die Parser-Klasse, die ANTLR erzeugt, viele Methoden, mit ähnlichen Namen enthält:Generieren Sie Python-Methoden aus einer Vorlage, die nur Suchen/Ersetzen der Zeichenfolge erfordert

class autogeneratedparser(xxx): 
    def something_enter(self,ctx): 
     pass 
    def something_exit(self,ctx) 
     pass 

I dieses außer Kraft setzen, indem eine Klasse definieren inheriting

class myclass(autogeneratedparser) 
    particularthing = False 
    def particularthing_enter(self,ctx): 
     print(ctx.name) 
     myclass.particularthing = true 
    def particularthing_exit(self,ctx): 
     print(ctx.name) 
     myclass.particularthing = false 

Ich mag würde, um dynamisch und automatisch all diese Methoden zu erzeugen, Ändern ihr jeweiliger Variablenname ist enthalten. In Pseudo-Code:

generate for particularthing in anything: 
     $(particularthing) = False 
     def $(particularthing)_enter(self,ctx): 
      print(ctx.name) 
      myclass.$(particularthing) = true 
     def $(particularthing)_exit(self,ctx): 
      print(ctx.name) 
      myclass.$(particularthing) = false 

Ich kann natürlich nur vim sagen, es zu tun, aber ich bin sicher, dass Python eine Art und Weise zu hat, weiß nur nicht, wie :-)

Vielen Dank für Ihre wertvollen Eingang :)

Antwort

0

Alles, was Sie tun müssen, über die anfängliche Klasse iterieren ist Attribute, wählen Sie nur diejenigen, die es SOMETHING_enter und SOMETHING_exit, dann erstellen Stub Methoden und alle zusammen mit type() (yes, it is used for creating dynamic classes) entsprechen.

Hier ist meine Version:

# the generated class 
class SomeClass(object): 
    def something_enter(self, ctx): 
     pass 
    def something_exit(self, ctx): 
     pass 


def generate_stubbed_class(klass_name, klass): 
    # creates and returns a function that does the generic behavior (print's out ctx.name) 
    # and sets the attribute to the given value 
    def generate_stub(name, value): 
     def stub(self, ctx): 
      print(ctx.name) 
      setattr(self, name, value) 

     return stub 

    attributes = {} 

    for name in dir(klass): # lists all attributes (names only) 
     try: 
      key, oper = name.split('_') 
     except ValueError: 
      # not in the format of SOMETHING_SOMETHING 
      continue 

     attr = getattr(klass, name) 

     # make sure it's a function and name ends in _enter or _exit 
     if callable(attr) and oper in ('enter', 'exit'): 
      value = oper == 'enter' # True for 'enter', False for 'exit' 
      attributes[name] = generate_stub(key, value) 
      attributes[key] = False # set more than once, but no negative effect 

    # this is where the magic happens 
    return type(klass_name, (klass,), attributes) 


MyClass = generate_stubbed_class('MyClass', SomeClass) 
obj = MyClass() 

assert isinstance(obj, SomeClass) 

# need some class with a 'name' attribute, so we create one on the fly 
from collections import namedtuple 
Data = namedtuple('Data', 'name') 

# initially it's False 
assert obj.something is False 

# set to True, prints 'foo' 
obj.something_enter(Data('foo')) 
assert obj.something is True 

# back to False, prints 'bar' 
obj.something_exit(Data('bar')) 
assert obj.something is False