Funktionskern als Pipeline in Python

Das Hauptziel dieses Beitrags ist es, ein in Python wenig nützliches Architekturmuster zu zeigen, das als " funktionaler Kern - imperativer Wrapper " bezeichnet wird, bei dem funktionale Programmierung mit imperativer Programmierung gemischt wird, um die Mängel jedes einzelnen von ihnen zu beseitigen. Es ist bekannt, dass funktionale Sprachen bei der Interaktion mit der "realen Welt" schwach sind, z. B. Benutzereingaben, GUI-Interaktionen oder andere E / A.





Dieser Ansatz nutzt Pythons Fähigkeit, mit Funktionen innerhalb des Funktionsparadigmas zu arbeiten, bei denen Funktionen auf die gleiche Weise wie jedes andere Objekt bearbeitet werden können: als Argumente an andere Funktionen übergeben, von Funktionen zurückgegeben und in Sequenzen als deren Elemente enthalten.





Für diejenigen, die die funktionale Programmierung in Python auffrischen möchten, empfehle ich, dem Link zu meinem Beitrag über die Grundlagen von FP in Python zu folgen .





Datenverarbeitungspipeline
Datenverarbeitungspipeline

Der funktionale Programmierstil kommt dem Denken einer Person bei der Lösung eines Problems sehr nahe. „Lass es gegeben werden x



. Um das Problem mit diesen Daten zu lösen, müssen eine Reihe von Transformationen durchgeführt werden. Wenden Sie sich zuerst an sie an f



und erhalten Sie die resultierenden Daten x'



. Dann auf die neuen Daten anwenden f2



und neue resultierende Daten x''



usw. erhalten.





, . , .. . , . , (), .





, , (1) (2) , debug, (3) , .





, . F#:





 2                            
 |> ( fun x -> x + 5)         
 |> ( fun x -> x * x)         
 |> ( fun x -> x.ToString() ) 
      
      



, 2, -. Python, , , , :





#   
 def pipe(data, *fseq):
    for fn in fseq: 
        data = fn(data)
    return data
      
      



Python:





pipe(2,
     lambda x: x + 5,
     lambda x: x * x,
     lambda x: str(x))
      
      



:





add      = lambda x: lambda y: x + y
square   = lambda x: x * x
tostring = lambda x: str(x)

pipe(2,
     add(5),
     square,
     tostring)
      
      



2 , '49'



. reduce



, , pipe .





pipe



: data



fseq



. for



. , data . .. , . pipe . .





. pipe *



. *



.





, , . ,





def my_sum(*args):  #   
    return sum(args)

my_sum(1, 2, 3, 4, 5)
      
      



. ,





def fun(a, b, c, d):
    print(a, b, c, d)

my_list = [1, 2, 3, 4]
fun(*my_list) #    
      
      



- ( ):





class Factory:
    def process(self, input):
        raise NotImplementedError

class Extract(Factory):
    def process(self, input):
        print(" ...")
        output = {}
        return output

class Parse(Factory):
    def process(self, input):
        print(" ...")
        output = {}
        return output

class Load(Factory):
    def process(self, input):
        print(" ...")
        output = {}
        return output

pipe = {  
    ""   : Extract(),
    "" : Parse(),
    "" : Load(),
}

inputs = {}  
#  
for name, instance in pipe.items():  
    inputs = instance.process(inputs)
      
      



:





 ... 
 ... 
 ...
      
      



for



, . - , . « , , , » - , - Erlang.





, , , .





(factorial



) (factorial_rec



). . , . .





, , - ;-), .. .





#    
#    

def main():
    #  ( c   )
    pipe(int(input('   : ')),    
         lambda n: (n, reduce(lambda x, y: x * y, range(1, n + 1))),    
         lambda tup: 
             print(f'  {tup[0]}  {tup[1]}'))        

#   
main()
      
      



:





   : 4 (Enter)
  4  24
      
      



- , .





, .. - - . . .





#    
#     

def get_int(msg=''):
    return int(input(msg))

def main():
    #  1.     
    def factorial_rec(n): 
        fn = lambda n, acc=1: acc if n == 0 else fn(n - 1, acc * n)
        return n, fn(n) 
  
    #  2.  
    def factorial(n):     
        return n, reduce(lambda x, y: x * y, range(1, n + 1)) 
   
    #  
    def indata():
        def validate(n):  #   
            if not isinstance(n, int):
                raise TypeError("   .")
            if not n >= 0:
                raise ValueError("   >= 0.")
            return n        
        msg = '   : '
        return pipe(get_int(msg), validate)
   
    #  
    def outdata():
        def fn(data):
            n, fact = data
            print(f'  {n}  {fact}') 
        return fn

    #  ( )
    pipe(indata(),     # : -       : int
         factorial,    # : int     : 
         outdata())    # :   : -    

#   
main()
      
      



:





   : 4 (Enter)
  4  24
      
      



:





pipe(indata(), 
     factorial, 
     outdata())
      
      



, .. indata



, factorial



outdata



. indata



, . factorial



, , , . outdata



. , indata , .





. -, - . -, .





:





  • . , factorial



    , factorial_rec



    .





pipe(indata(), factorial_rec, outdata())
      
      



  • , .





, – . debug



:





def debug(data):
    print(data) 
    return data
      
      



, :





pipe(indata(), debug, factorial, debug, outdata())
      
      



, :





:





   : 4 (Enter)
4
(4, 24)
      
      



4 24





, factorial



4



, (4, 24)



. , , . , debug



-, .





.





#    
#     

def main():
    # 
    def fibonacci(n, x=0, y=1):
        #  fib  n-  .
        fib = lambda n, x=0, y=1: x if n <= 0 else fib(n - 1, y, x + y)
        #  reduce     acc
        acc = []
        reduce(lambda _, y: acc.append(fib(y)), range(n + 1))
        return n, acc

    #   
    def validate(n):         
        if not isinstance(n, int):
            raise TypeError("   .")
        if not n >= 0:
            raise ValueError("    .")
        if n > 10:
            raise ValueError("     10.")
        return n

    #  
    def indata():
        msg = '      10: '
        return pipe(get_int(msg), validate)

    #  
    def outdata():
        def fn(data):
            n, seq = data
            msg = f' {n}   :'
            print(msg) 
            [print(el) for el in seq]
        return fn

    #  ( )
    pipe(indata(), fibonacci, outdata()) 

#   .
main()

 
      10: 10 (Enter)
 10   :
1
1
2
3
5
8
13
21
34
55
      
      



#    
#    
#   

def main():
    # 
    def range_sum(data):  
        seq, params = data
        fn = lambda start, end: 0 if start > end \
                                  else seq[start] + fn(start + 1, end)
        return fn(*params)

    #  
    def indata():
        seq = [1, 2, 3, 4, 5, 6, 7, 8, 9]    
        params = (2,5)   # params -   start, end
        return seq, params  

    #  
    def outdata():
        def f(data):
            msg = '   2  5   '
            print(msg, format(data), sep='') 
        return f

    #  ( )
    pipe(indata(), range_sum, outdata()) 

#   .
main()

 
   2  5   18
      
      



Python . : . . , , , , , . , .)





Github. Strating Out with Python. , . ,





  • PyCon .





  • , .





  • Youtube « Python - ».





, , Python , map/filter/reduce/zip functools. . , , , .








All Articles