خطوط الأنابيب والتطبيق الجزئي للوظائف ، لماذا يتم ذلك في Python



إحدى المزايا الرئيسية لبايثون هي تعبيرها. تتيح لك وظيفة اللغة أن تصف بإيجاز عمليات التحويل عبر البيانات. في رأيي ، تفتقر Python إلى بعض الأدوات التي من شأنها أن تساعد في وصف تحويلات البيانات بشكل أكثر ملاءمة وتكمل المكون الوظيفي للغة ، على وجه الخصوص ، "خطوط الأنابيب الوظيفية" وتطبيقها الجزئي. لذلك ، في هذا المنشور ، أسكب الماء على إمكانية وضرورة هذه الأموال مع تجارب لتنفيذها. لقد جئت في نواح كثيرة للنقد. استمتع بالقراءة!



باختصار حول FP في Python ولماذا لا توجد خطوط أنابيب كافية على سبيل المثال



تحتوي لغة Python على بعض الأدوات الأساسية سهلة الاستخدام مثل map () وخفض () و filter () ووظائف lambda والمكررات والمولدات. أنصح كل شخص ليس على دراية بهذه المقالة . بشكل عام ، يتيح لك هذا كله وصف التحولات بشكل سريع وطبيعي عبر القوائم ، والمجموعات ، وما إلى ذلك. في كثير من الأحيان (معي وأصدقائي أصحاب الثعابين) ما يحدثخط واحد- مجموعة من التحولات المتسلسلة ، المرشحات ، على سبيل المثال:

Kata with CodeWars : Find



ن[أوب]:ن=0لهن(ن)نأناأناو نأنا - بت رقم i من رقم n



المهمة بسيطة للغاية ، لسوء الحظ (لكن لحسن الحظ لهذا المنشور) ، لا توجد حلول أفضل من وجهاً لوجه.



قراري:



def sum_dig_pow(a, b): # range(a, b + 1) will be studied by the function
    powered_sum = lambda x: sum([v**(i+1) for i,v in enumerate(map(lambda x: int(x), list(str(x))))])
    return [i for i in range(a,b+1) if powered_sum(i)==i]


باستخدام وسائل FP كما هي ، يتم الحصول على قوس الجحيم "من الداخل إلى الخارج". يمكن لخط الأنابيب إصلاح ذلك.



خطوط الأنابيب الوظيفية



أعني بواسطة sim في الحالة المثالية (عامل التشغيل "|" هو التفضيل الشخصي):



# f3(f2(f1(x)))
f1 | f2 | f3 >> x
pipeline = f1 | f2 | f3 
pipeline(x)
pipeline2 = f4 | f5
pipeline3 = pipeline | pipeline2 | f6
...


ثم يمكن أن تصبح powered_sum (الرمز لا يعمل):



powered_sum = str | list | map(lambda x: int(x), *args) | enumerate | [v**(i+1) for i,v in *args] | sum


بالنسبة لي ، هذا الرمز أسهل في الكتابة والقراءة. تبدو args أجنبية بشكل عام. في الواقع ، دون الزحف إلى أحشاء الثعبان ، اتضح أنه يفعل ذلك (بعيدًا عن أي مُثُل):



from copy import deepcopy

class CreatePipeline:
    def __init__(self, data=None):
        self.stack = []
        if data is not None:
            self.args = data

    def __or__(self, f):
        new = deepcopy(self)
        new.stack.append(f)
        return new

    def __rshift__(self, v):
        new = deepcopy(self)
        new.args = v
        return new

    def call_logic(self, *args):
        for f in self.stack:
            if type(args) is tuple:
                args = f(*args)
            else:
                args = f(args)
        return args

    def __call__(self, *args):
        if 'args' in self.__dict__:
            return self.call_logic(self.args)
        else:
            return self.call_logic(*args)


بطبيعة الحال ، هذا هو أحد العكازات الكبيرة ، المصممة من أجل المتعة ، حتى بدون kwargs ، على الرغم من أنها ليست مهمة للغاية في حالات مماثلة.



pipe = CreatePipeline()
powered_sum = pipe | str | list | (lambda l: map(lambda x: int(x), l)) | enumerate | (lambda e: [v**(i+1) for i,v in e]) | sum


, , , , , .





( ):



def f_partitial (x,y,z):
    return x+y+z
v = f_partial(1,2)
# type(v) = -    f_partial,  : ['z']
print(v(3))
# 
print(f_partial(1,2,3))


( ). pipe :



powered_sum = pipe | str | list | map(lambda x: int(x)) | enumerate | (lambda e: [v**(i+1) for i,v in e]) | sum
# map       
# map(lambda x: int(x))()  


map(lambda x: int(x)) .

:



from inspect import getfullargspec
from copy import deepcopy

class CreatePartFunction:
    def __init__(self, f):
        self.f = f
        self.values = []

    def __call__(self, *args):
        args_f = getfullargspec(self.f)[0]
        if len(args) + len(self.values) < len(args_f):
            new = deepcopy(self)
            new.values = new.values + list(args)
            return new
        elif len(self.values) + len(args) == len(args_f):
            return self.f(*tuple(self.values + list(args)))


:



#     inspect   map
m = lambda f, l: map(f, l)
#        
pmap = CreatePartFunction(m)
powered_sum = pipe | str | list | pmap(lambda x: int(x)) | enumerate | (lambda e: [v**(i+1) for i,v in e]) | sum


( ), , , , :



def f (x,y,z):
    return x+y+z
f = CreatePartFunction(f)
# 
print(f(1,2,3))
# 
print(f(1,2)(3))
print(f(1)(2,3))
#  
# 2(3) - int  callable
print(f(1)(2)(3))
# 
print((f(1)(2))(3))




, , , , , , , .




All Articles