أي ما يعادل بيثون "مع" في روبي
-
28-09-2019 - |
سؤال
في بيثون ، with
يتم استخدام العبارة للتأكد من أن رمز التنظيف يتم استدعاؤه دائمًا ، بغض النظر عن الاستثناءات التي يتم طرحها أو عودة الوظائف. فمثلا:
with open("temp.txt", "w") as f:
f.write("hi")
raise ValueError("spitespite")
هنا ، تم إغلاق الملف ، على الرغم من استثناء. تفسير أفضل هنا.
هل هناك ما يعادل هذا البناء في روبي؟ أو هل يمكنك رمز واحد ، لأن روبي لديه استمرار؟
المحلول
Ruby لديه دعم خفيف الوزن بشكل حيوي للإجراءات الحرفية المجهولة (تسمى كتل في روبي). لذلك ، لا يحتاج إلى ميزة لغة جديدة لهذا الغرض.
(بشكل عام ، إنها علامة سيئة ، إذا كنت بحاجة إلى إضافة ميزات لغة. يجب أن تكون قادرًا على تنفيذ كل شيء في المكتبة ، وإلا فإنها علامة على تصميم اللغة السيئة.)
لذلك ، ما تفعله عادة ، هو كتابة طريقة تأخذ كتلة من التعليمات البرمجية ، وتخصص المورد ، وتنفيذ كتلة الكود في سياق هذا المورد ثم يغلق المورد.
شيء من هذا القبيل:
def with(klass, *args)
yield r = klass.open(*args)
ensure
r.close
end
يمكنك استخدامه مثل هذا:
with File, 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
ومع ذلك ، هذه طريقة إجرائية للغاية للقيام بذلك. روبي هي لغة موجهة نحو الكائن ، مما يعني أن مسؤولية تنفيذ كتلة من الكود بشكل صحيح في سياق أ File
يجب أن ينتمي إلى File
صف دراسي:
File.open 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
يمكن تنفيذ هذا شيء من هذا القبيل:
def File.open(*args)
f = new(*args)
return f unless block_given?
yield f
ensure
f.close if block_given?
end
هذا نمط عام يتم تنفيذه من قبل الكثير من الفصول في مكتبة Ruby Core والمكتبات القياسية ومكتبات الطرف الثالث.
ستكون المراسلات الأكثر قربًا لبروتوكول مدير سياق بيثون العام:
def with(ctx)
yield ctx.setup
ensure
ctx.teardown
end
class File
def setup; self end
alias_method :teardown, :close
end
with File.open('temp.txt', 'w') do |f|
f.write 'hi'
raise 'spitespite'
end
لاحظ أن هذا لا يمكن تمييزه تقريبًا عن مثال Python ، لكنه لم يتطلب إضافة بناء جملة جديد إلى اللغة.
نصائح أخرى
ما يعادلها في Ruby هي تمرير كتلة إلى طريقة file.Open.
File.open(...) do |file|
#do stuff with file
end #file is closed
هذا هو المصطلح الذي يستخدمه روبي وواحد يجب أن تشعر بالراحة معه.
يمكنك استخدام حجج الكتلة للقيام بذلك في روبي:
class Object
def with(obj)
obj.__enter__
yield
obj.__exit__
end
end
الآن ، يمكنك إضافة __enter__
و __exit__
طرق لفئة أخرى واستخدامها مثل هذا:
with GetSomeObject("somefile.text") do |foo|
do_something_with(foo)
end
سأضيف فقط بعض التفسيرات للآخرين ؛ يجب أن يذهب الائتمان إليهم.
في الواقع ، في روبي ، رمز التنظيف كما قال آخرون ، في ensure
بند؛ لكن لف الأشياء في الكتل في كل مكان في روبي ، وهكذا يتم ذلك بشكل أكثر كفاءة وأكثر بروح روبي. عند الترجمة ، لا تترجم مباشرة كلمة مقابل كلمة ، ستحصل على بعض الجمل الغريبة للغاية. وبالمثل ، لا تتوقع كل شيء من بيثون إلى مراسلات فردية إلى روبي.
من الرابط الذي نشرته:
class controlled_execution:
def __enter__(self):
set things up
return thing
def __exit__(self, type, value, traceback):
tear things down
with controlled_execution() as thing:
some code
Ruby Way ، شيء من هذا القبيل (رجل ، ربما أفعل كل هذا خطأ: D):
def controlled_executor
begin
do_setup
yield
ensure
do_cleanup
end
end
controlled_executor do ...
some_code
end
من الواضح أنه يمكنك إضافة حجج إلى كليهما controlled executor
(ليتم استدعاؤها بطريقة معتادة) ، وللتجمد (في هذه الحالة تحتاج إلى إضافة حجج إلى الكتلة أيضًا). وبالتالي ، لتنفيذ ما نقلت أعلاه ،
class File
def my_open(file, mode="r")
handle = open(file, mode)
begin
yield handle
ensure
handle.close
end
end
end
File.my_open("temp.txt", "w") do |f|
f.write("hi")
raise Exception.new("spitesprite")
end
من الممكن الكتابة إلى ملف ذري في روبي ، مثل ذلك:
File.write("temp.txt", "hi")
raise ValueError("spitespite")
يعني كتابة كود مثل هذا أنه من المستحيل ترك ملف مفتوح.
يمكنك دائما استخدام أ try..catch..finally
كتلة ، حيث finally
يحتوي القسم على رمز للتنظيف.
تحرير: آسف ، أخطاء إملائية: تريد begin..rescue..ensure
.
أعتقد أنك تبحث عن يضمن.