وظائف الدكتوراه التي تتلقى وعرض إدخال المستخدم - Python (تمزيق شعري)

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

  •  02-10-2019
  •  | 
  •  

سؤال

أكتب حاليًا تطبيقًا صغيرًا مع Python (3.1) ، ومثل صبي صغير جيد ، فأنا أتجه إلى الدكتوراه كما أذهب. ومع ذلك ، فقد صادفت طريقة لا يمكنني أن أبدو فيها. أنه يحتوي على input(), ، بسبب ذلك ، لست متأكدًا تمامًا مما يجب وضعه في الجزء "المتوقع" من الدكتوراه.

يتبع رمز مثال لتوضيح مشكلتي:

"""
>>> getFiveNums()
Howdy. Please enter five numbers, hit <enter> after each one
Please type in a number:
Please type in a number:
Please type in a number:
Please type in a number:
Please type in a number:
"""

import doctest

numbers = list()

# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
    print("Howdy. Please enter five numbers, hit <enter> after each one")
    for i in range(5):
        newNum = input("Please type in a number:")
        numbers.append(newNum)
    print("Here are your numbers: ", numbers)

if __name__ == "__main__":
    doctest.testmod(verbose=True)

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

doctest results

لا أعرف ماذا ، إذا كان أي شيء ، يمكنني وضع في قسم المتوقع من Doctest ليتمكن من اختبار طريقة تتلقى ثم يعرض إدخال المستخدم. لذا سؤالي (أخيرًا) هو ، هل هذه الوظيفة قابلة للدقيق؟

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

المحلول

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

قد يبدو نهج Unitest:

import unittest

# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
    numbers = []
    print "Howdy. Please enter five numbers, hit <enter> after each one"
    for i in range(5):
        newNum = input("Please type in a number:")
        numbers.append(newNum)
    return numbers

def mock_input(dummy_prompt):
    return 1

class TestGetFiveNums(unittest.TestCase):
    def setUp(self):
        self.saved_input = __builtins__.input
        __builtins__.input = mock_input

    def tearDown(self):
        __builtins__.input = self.saved_input

    def testGetFiveNums(self):
        printed_lines = getFiveNums()
        self.assertEquals(printed_lines, [1, 1, 1, 1, 1])

if __name__ == "__main__":
    unittest.main()

ربما لا يتم اختبار الوظيفة التي طرحتها بشكل دقيق ولكنك تحصل على الفكرة.

نصائح أخرى

أبسط طريقة لجعل هذا القابل للاختبار حقن المعلمة:

def getFiveNums(input_func=input):
    print("Howdy. Please enter five numbers, hit <enter> after each one")
    for i in range(5):
        newNum = input_func("Please type in a number:")
        numbers.append(newNum)
    print("Here are your numbers: ", numbers)

لا يمكن أن يُتوقع من واقعياً وحدة الاختبار/الإخراج من هذا القبيل - لا يمكن أن تشعر بالقلق من أن الدعوة إلى input قد تفشل بطريقة ما. الخيار الأفضل لك هو تمرير طريقة كعب من الطبيعة ؛ شيء مثل

def fake_input(str):
    print(str)
    return 3

لذلك في Doctest ، يمكنك بالفعل الاختبار getFiveNums(fake_input).

علاوة على ذلك ، من خلال كسر الاعتماد المباشر على input حاليا, ، إذا كنت تنقل هذا الرمز إلى شيء آخر لاحقًا لم يكن استخدم سطر الأوامر ، يمكنك فقط إسقاط الكود الجديد لاسترداد الإدخال (سواء كان ذلك سيكون مربع حوار في تطبيق واجهة المستخدم الرسومية ، أو منبثقة JavaScript في تطبيق قائم على الويب ، إلخ).

لقد وجدت طريقة مختلفة.

"""
>>> get_five_nums(testing=True)
Howdy. Please enter five numbers, hit <enter> after each one.
Please type in a number: 1
Please type in a number: 1
Please type in a number: 1
Please type in a number: 1
Please type in a number: 1
Here is a list of the numbers you entered:  [1, 1, 1, 1, 1]
>>>
"""

import doctest

numbers = []

def get_five_nums(testing=False):
    """Stores 5 user-entered numbers (strings, for now) in a list."""

    print("Howdy. Please enter five numbers, hit <enter> after each one.")
    for i in range(5):
        new_num = int(input("Please type in a number: "))
        if testing:
            print(new_num)
        numbers.append(new_num)
    print("Here is a list of the numbers you entered: ", numbers)


if __name__ == "__main__":
    doctest.testmod(verbose=True)  

احفظ الرمز أعلاه في ملف يسمى foo.py. الآن قم بعمل ملف يسمى input.txt.

كل ما يحتاجه فيه.

1
1
1
1
1

خمسة منها. واحد على كل سطر.

لاختبار البرنامج ، قم بما يلي ، في Terminal أو موجه الأوامر (أنا أستخدم Mac):

$ python foo.py <input.txt

يمكن تغيير هذا بسهولة لأي نوع من مدخلات المستخدم في أي برنامج. مع هذا ، يمكنك الآن نسخ إخراج الجلسة الطرفية واستخدامها كدكتوء.

ملاحظة: ستكون دعوة الوظيفة في المحطة get_five_nums (). فيك ، يجب أن يكون get_five_nums (اختبار = صحيح).

على الرغم من أن Doctest لا يبدو أنه من المفترض أن يتم استخدامه بهذه الطريقة ، إلا أنه لا يزال اختراقًا مفيدًا.

إليك عملية عمل توصلت إليها. إنه Kludgy قليلاً ، لكنه يعمل عند الحاجة إلى سطر واحد فقط من المدخلات:

def capitalize_name():
    """
    >>> import io, sys ; sys.stdin = io.StringIO("Bob")  # input
    >>> capitalize_name()
    What is your name?  Your name is BOB!
    """
    name = input('What is your name?  ')
    print('Your name is ' + name.upper() + '!')

لسوء الحظ ، يشكو عندما يحتوي الإدخال على سطر جديد (على سبيل المثال ، "Bob nalice"). أظن أن هذا بسبب doctest يتم إطاحة المحلل (لكن لا يمكنني القول بالتأكيد).

يمكنك الالتفاف حول مشكلة " n" باستخدام chr(10) بدلا من ذلك ، مثل هذا:

# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
    """
    >>> import io, sys ; sys.stdin = io.StringIO(chr(10).join(['1','2','3','4','5']))  # input
    >>> getFiveNums()
    Howdy. Please enter five numbers, hit <enter> after each one
    Please type in a number:Please type in a number:Please type in a number:Please type in a number:Please type in a number:Here are your numbers:  ['1', '2', '3', '4', '5']
    """
    print("Howdy. Please enter five numbers, hit <enter> after each one")
    numbers = []
    for _ in range(5):
        newNum = input("Please type in a number:")
        numbers.append(newNum)
    print("Here are your numbers: ", numbers)

هذا هو أكثر Kludgy ، لكنه يعمل. تحتاج إلى أن تتذكر أنه يتم عرض جميع النص المطالبة (عبر وظيفة الإدخال ()) كإخراج بدون إدخال المستخدم المصاحب. (لهذا السبب "يرجى كتابة رقم:" يظهر خمس مرات متتالية بدون مسافات أو خطوط جديدة بين حالاتها.)

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

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