سؤال

لدي وظيفة التي مدخلات الحجة إما أن يكون عنصرا أو قائمة من العناصر.إذا كانت هذه الحجة هي عنصر واحد ثم وضعه في قائمة لذلك أنا يمكن أن يكرر أكثر من المدخلات بطريقة متسقة.

حاليا لدي هذا:

def my_func(input):
    if not isinstance(input, list): input = [input]
    for e in input:
        ...

أنا أعمل مع القائمة API لذا لا أستطيع تغيير معلمات الإدخال.باستخدام isinstance() يشعر hacky, لذلك ليس هناك السليم طريقة لفعل هذا ؟

هل كانت مفيدة؟

المحلول

وأنا أحب اقتراح اندريه Vajna من hasattr(var,'__iter__'). ملاحظة هذه النتائج من بعض أنواع بيثون نموذجي:

>>> hasattr("abc","__iter__")
False
>>> hasattr((0,),"__iter__")
True
>>> hasattr({},"__iter__")
True
>>> hasattr(set(),"__iter__")
True

وهذا له ميزة إضافية تتمثل في معالجة سلسلة باعتباره غير iterable - سلاسل هي منطقة رمادية، وأحيانا كنت ترغب في التعامل معها باعتبارها عنصرا، وأحيانا أخرى على أنها تسلسل الأحرف

.

لاحظ أنه في بيثون 3 نوع str <م> لا لديك السمة __iter__ وهذا لا يعمل:

>>> hasattr("abc", "__iter__")
True

نصائح أخرى

وعادة، سلاسل (عادي ويونيكود) هي iterables الوحيدة التي ترغب في النظر في ذلك بأنهم "عناصر واحدة" - والمضمن basestring موجود على وجه التحديد لتمكنك من اختبار لأي نوع من السلاسل مع isinstance، لذلك فمن غير الممثلة جدا جروتي لهذه الحالة الخاصة؛ -)

وهكذا توجهي المقترح للقضية الأكثر العامة هو:

  if isinstance(input, basestring): input = [input]
  else:
    try: iter(input)
    except TypeError: input = [input]
    else: input = list(input)

وهذه هي الطريقة لعلاج EVERY iterable باستثناء السلاسل كقائمة مباشرة، السلاسل والأرقام وغيرها من غير iterables-كما سكالارس (يتم تطبيع في قوائم البند واحد).

وأنا صنع صراحة على قائمة من كل نوع من iterable ذلك كنت أعلم أنك يمكن أن تؤدي زيادة على كل نوع من القائمة خدعة - الفرز، بالتكرار أكثر من مرة، إضافة أو إزالة العناصر لتسهيل التكرار، وغيرها، وكل ذلك دون تغيير قائمة المدخلات الفعلية (إن القائمة بالفعل كان ؛-). إذا كان كل ما تحتاجه هو واحد سهل for حلقة ثم أن الخطوة الأخيرة هي غير ضرورية (وغير مفيدة حقا إذا مثل الإدخال ملف مفتوح ضخم) وأنا أقترح مولد مساعد بدلا من ذلك:

def justLoopOn(input):
  if isinstance(input, basestring):
    yield input
  else:
    try:
      for item in input:
        yield item
    except TypeError:
      yield input

والآن في كل واحد من مهامكم التي تحتاج إلى مثل هذا التطبيع حجة، كنت تستخدم فقط:

 for item in justLoopOn(input):

ويمكنك استخدام المساعدة تطبيع وظيفة حتى في حالة أخرى (حيث كنت في حاجة الى قائمة حقيقية لأغراض أخرى شريرة)؛ في الواقع، في مثل هذه (ندرة) الحالات، يمكنك القيام بذلك تماما:

 thelistforme = list(justLoopOn(input))

وبحيث (لا محالة) منطق التطبيع نوعا ما شعر هو فقط في مكان واحد، تماما كما ينبغي أن يكون! -)

أولا لا توجد طريقة عامة يمكن أن أقول "عنصر واحد" من "قائمة عناصر" منذ بالتعريف القائمة يمكن أن تكون عنصرا من عناصر قائمة أخرى.

أود أن أقول أن كنت بحاجة إلى تحديد ما هي أنواع البيانات التي قد تكون لديكم ، بحيث قد يكون لديك:

  • أي سليل list ضد أي شيء آخر
    • اختبار مع isinstance(input, list) (ذلك المثال الخاص بك هو الصحيح)
  • أي تسلسل نوع ما عدا السلاسل (basestring في بيثون 2.x ، str في بيثون 3.x)
    • استخدام تسلسل metaclass: isinstance(myvar, collections.Sequence) and not isinstance(myvar, str)
  • بعض تسلسل نوع ضد الحالات المعروفة مثل int, str, MyClass
    • اختبار مع isinstance(input, (int, str, MyClass))
  • أي iterable باستثناء السلاسل:
    • اختبار مع

.

    try: 
        input = iter(input) if not isinstance(input, str) else [input]
    except TypeError:
        input = [input]

ويمكنك وضع * قبل حجتك، وبهذه الطريقة سوف دائما الحصول على الصفوف (tuple):

def a(*p):
  print type(p)
  print p

a(4)
>>> <type 'tuple'>
>>> (4,)

a(4, 5)
>>> <type 'tuple'>
>>> (4,5,)

ولكن هذا سوف يجبرك على استدعاء الدالة متغير المعالم، وأنا لا أعرف اذا كان هذا مقبولا بالنسبة لك.

ويمكنك القيام مقارنات نوع المباشرة باستخدام type().

def my_func(input):
    if not type(input) is list:
        input = [input]
    for e in input:
        # do something

ومع ذلك، فإن الطريقة يكون لديك انها ستسمح <م> أي نوع مشتق من نوع list لتمريرها من خلال. وبالتالي منع أي نوع من أنواع المستمدة من دون قصد يتم ملفوفة.

وaproach لديك يبدو الحق بالنسبة لي.

وانها مماثلة لكيفية استخدام atom? في اللثغة عند تكرار عبر القوائم والتحقق من هذا البند الحالي لمعرفة ما اذا كان هو القائمة أم لا، لأنه إذا كان هو القائمة التي تريد معالجة بنوده، أيضا.

وهكذا، نعم، لا يرى بأسا في ذلك.

وهذا هو وسيلة موافق للقيام بذلك (لا تنسى أن تشمل الصفوف).

ومع ذلك، قد ترغب أيضا في النظر إذا كانت الوسيطة لديها طريقة __iter__ أو __getitem__ طريقة . (لاحظ أن سلاسل و__getitem__ بدلا من __iter __).

hasattr(arg, '__iter__') or hasattr(arg, '__getitem__')

وربما هذا هو أهم شرط عام لنوع القائمة مثل من مجرد التحقق من نوع.

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

isinstance(input, (list, tuple))

وأو أكثر عموما، مجردة بعيدا عن السؤال التالي:

def iterable(obj):
  try:
    len(obj)
    return True
  except TypeError:
    return False

ولكن مرة أخرى، باختصار، طريقة الخاص بك هو بسيط والصحيح، والذي يبدو جيدا بالنسبة لي!

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