
إحدى المزايا الرئيسية لبايثون هي تعبيرها. تتيح لك وظيفة اللغة أن تصف بإيجاز عمليات التحويل عبر البيانات. في رأيي ، تفتقر Python إلى بعض الأدوات التي من شأنها أن تساعد في وصف تحويلات البيانات بشكل أكثر ملاءمة وتكمل المكون الوظيفي للغة ، على وجه الخصوص ، "خطوط الأنابيب الوظيفية" وتطبيقها الجزئي. لذلك ، في هذا المنشور ، أسكب الماء على إمكانية وضرورة هذه الأموال مع تجارب لتنفيذها. لقد جئت في نواح كثيرة للنقد. استمتع بالقراءة!
باختصار حول FP في Python ولماذا لا توجد خطوط أنابيب كافية على سبيل المثال
تحتوي لغة Python على بعض الأدوات الأساسية سهلة الاستخدام مثل map () وخفض () و filter () ووظائف lambda والمكررات والمولدات. أنصح كل شخص ليس على دراية بهذه المقالة . بشكل عام ، يتيح لك هذا كله وصف التحولات بشكل سريع وطبيعي عبر القوائم ، والمجموعات ، وما إلى ذلك. في كثير من الأحيان (معي وأصدقائي أصحاب الثعابين) ما يحدثخط واحد- مجموعة من التحولات المتسلسلة ، المرشحات ، على سبيل المثال:
Kata with CodeWars : Find
المهمة بسيطة للغاية ، لسوء الحظ (لكن لحسن الحظ لهذا المنشور) ، لا توجد حلول أفضل من وجهاً لوجه.
قراري:
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))
, , , , , , , .