بيثون: تحديد وظائف جديدة على ذبابة باستخدام "مع"

StackOverflow https://stackoverflow.com/questions/2200026

  •  18-09-2019
  •  | 
  •  

سؤال

أريد تحويل التعليمات البرمجية التالية:

...
urls = [many urls]
links = []
funcs = []
for url in urls:
   func = getFunc(url, links)
   funcs.append(func)
...

def getFunc(url, links):
   def func():
      page = open(url)
      link = searchForLink(page)
      links.append(link)
   return func

في الرمز أكثر ملاءمة:

urls = [many urls]
links = []
funcs = []
for url in urls:
   <STATEMENT>(funcs):
        page = open(url)
        link = searchForLink(page)
        links.append(link)

كنت آمل أن أفعل هذا مع with بيان. كما علقت عاليا، كنت آمل أن تحقق:

def __enter__():
    def func():

..code in the for loop..

def __exit__():
  funcs.append(func)

بالطبع هذا لا يعمل.

قائمة الفهم ليست جيدة للحالات كان العمل searchForLink ليس فقط وظيفة واحدة ولكن العديد من الوظائف. سوف تتحول إلى رمز غير قابل للقراءة للغاية. على سبيل المثال، سيكون هذا مشكلة في الفهم في القائمة:

for url in urls:
  page = open(url)
  link1 = searchForLink(page)
  link2 = searchForLink(page)
  actionOnLink(link1)
  actionOnLink(link2)
  .... many more of these actions...
  links.append(link1)
هل كانت مفيدة؟

المحلول

قليلا غير تقليدية، ولكن يمكنك الحصول على ديكور تسجيل func وربط أي متغيرات حلقة كوسائط افتراضية:

urls = [many urls]
links = []
funcs = []

for url in urls:
    @funcs.append
    def func(url=url):
        page = open(url)
        link = searchForLink(page)
        links.append(link)

نصائح أخرى

لا معنى لها استخدام with هنا. بدلا من ذلك استخدم فهم قائمة:

funcs = [getFunc(url, links) for url in urls]

هناك طريقتان فقط لإنشاء وظائف: def و lambda. وبعد تعني Lambdas لوظائف صغيرة، لذلك قد لا تكون مناسبة للغاية لحالتك. ومع ذلك، إذا كنت ترغب حقا في ذلك، يمكنك إرفاق اثنين من لامدراس داخل بعضها البعض:

urls = [many urls]
links = []
funcs = [(lambda x:
            lambda:
              links.append(searchForLink(open(x))))(u)
         for u in urls]

قليلا جدا من ذوقي.

تفقد الخط <STATEMENT>(funcs):

يحرر:

أعني: لماذا تفعل هذا؟ لماذا تحديد وظيفة جديدة لكل صفحة؟ لماذا لا تفعل هذا فقط؟

urls = [many urls]
links = []
for url in urls:
    page = open(url)
    link = searchForLink(page)
    links.append(link) 

يجب ألا تستخدم "مع" للقيام بذلك (على الرغم من ذلك، بالنظر إلى أنها بيثون، يمكنك بالتأكيد تقريبا، باستخدام بعض التأثير الجانبي الغريب ودينامان بايثون).

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

أعتقد أنك مربكة بيثون "مع" مع جافا سكريبت/البصرية الأساسية "مع"، والتي قد تكون متشابهة مستحضرات التجميل ولكنها غير مرتبطة بفعالية.

جيد قديم itertools..

from itertools import imap
links.extend(imap(searchForLink, imap(open, urls)))

على الرغم من، ربما كنت تفضل وظيفي.

from functional import *
funcs = [partial(compose(compose(links.append, searchForLink), open), url) for url in urls]
for func in funcs: func()

لا أعتقد أنه من المفيد إنشاء فئة with استخدام: إنه أكثر عمل لإنشاء __enter__ و __exit__ مما هو عليه فقط كتابة وظيفة المساعد.

قد تكون أفضل استخدام المولدات لتحقيق الحساب المتأخر الذي بعده.

def MakeLinks(urls):
    for url in urls:
        page = open(url)
        link = searchForLink(page)
        yield link

links = MakeLinks(urls)

عندما تريد الروابط:

for link in links:
    print link

سيتم البحث عن عناوين URL أثناء هذه الحلقة، وليس كل مرة واحدة (التي تبدو وكأنها تتجنبها).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top