Geçerli bir yanıt verene kadar kullanıcıdan giriş sorma


562

Kullanıcıdan girdi kabul eden bir program yazıyorum.

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Kullanıcı anlamlı veri girdiği sürece program beklendiği gibi çalışır.

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

Ancak kullanıcı geçersiz veriler girerse başarısız olur:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

Çökme yerine, programın girişi tekrar istemesini istiyorum. Bunun gibi:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

Algılayıcı olmayan veriler girildiğinde programın çökme yerine geçerli girişler istemesini nasıl sağlayabilirim?

Bu bağlamda -1geçerli int, ama saçma gibi değerleri nasıl reddedebilirim ?

Yanıtlar:


704

Bunu yapmanın en basit yolu, inputyöntemi bir while döngüsüne koymaktır . continueKötü giriş aldığınızda ve breakmemnun olduğunuzda döngü dışında kullanın .

Girişiniz İstisna Yaratabilirse

Kullanıcının ayrıştırılamayan verileri ne zaman girdiğini tespit etmek için tryveexcept düğmelerini kullanın .

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Kendi Doğrulama Kurallarınızı Uygulama

Python'un başarıyla ayrıştırabileceği değerleri reddetmek isterseniz, kendi doğrulama mantığınızı ekleyebilirsiniz.

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

İstisna İşleme ve Özel Doğrulamayı Birleştirme

Yukarıdaki tekniklerin her ikisi de bir döngü halinde birleştirilebilir.

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0:
        print("Sorry, your response must not be negative.")
        continue
    else:
        #age was successfully parsed, and we're happy with its value.
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Hepsini Bir Fonksiyonda Kapsülleme

Kullanıcıdan birçok farklı değer istemeniz gerekiyorsa, bu kodu bir işleve koymak yararlı olabilir, bu nedenle her seferinde yeniden yazmanız gerekmez.

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

Hepsini bir araya koy

Çok genel bir girdi işlevi yapmak için bu fikri genişletebilirsiniz:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_:
        raise ValueError("min_ must be less than or equal to max_.")
    while True:
        ui = input(prompt)
        if type_ is not None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Input type must be {0}.".format(type_.__name__))
                continue
        if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {0}."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

Kullanım gibi:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))

Yaygın Tuzaklar ve Neden Önlemek

Fazlalık inputİfadelerin Gereksiz Kullanımı

Bu yöntem işe yarar, ancak genellikle zayıf stil olarak kabul edilir:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

Başlangıçta while Trueyönteme göre daha kısa olduğu için çekici görünebilir , ancak Kendinizi Tekrar Etmeyin yazılım geliştirme ilkesini ihlal eder . Bu, sisteminizdeki hata olasılığını artırır. Ne değiştirerek 2.7'ye backport istiyorsanız inputiçin raw_input, ancak yanlışlıkla sadece ilk değiştirmek inputyukarıda? Bu birSyntaxError sadece gerçekleşmeyi bekliyor.

Özyineleme Yığını Darbe Edecek

Özyinelemeyi yeni öğrendiyseniz get_non_negative_int, while döngüsünü elden çıkarabilmeniz için bunu kullanmaya cazip gelebilirsiniz .

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

Bu çoğu zaman iyi çalışıyor gibi görünür, ancak kullanıcı yeterli sayıda geçersiz veri girerse, komut dosyası bir ile sonlanır RuntimeError: maximum recursion depth exceeded. "Hiçbir aptal arka arkaya 1000 hata yapmaz" diye düşünebilirsiniz, ama aptalların yaratıcılığını küçümsüyorsunuz!


53
Birçok örnek, kudos ile okumak eğlenceli. Yetersiz ders: "Aptalların yaratıcılığını hafife alma!"
vpibano

3
Ben sadece hem Q & A hem de, onlar büyük olduğu gibi değil, aynı zamanda "dickety altı" ile anlaşma imzaladı. Aferin @ Kevin.
erekalper

1
Aptalların ve zeki saldırganların yaratıcılığını tahmin etmeyin. Bir DOS saldırısı bu tür şeyler için en kolay olurdu, ancak diğerleri mümkün olabilir.
Solomon Ucko

Yedek girişler yerine yeni "mors" operatörünü kullanabilir miyiz? Aynı zamanda kötü bir tarz mı?
J Arun Mani

1
@JArunMani Kötü bir tarz olacağını düşünmüyorum, ancak biraz daha az okunabilir olabilir. Gerçekten inputdöngü başına sadece bir tane olacak ve döngü çok kısa olacak, ancak durum oldukça uzun olabilir ...
Tomerikoo

39

Neden tek yapmanız gereken while Truebu döngüden kurtulmak isterken, gereksinimlerinizi while deyimine de koyabilirsiniz, çünkü istediğiniz tek şey yaşınız olduğunda durmaktır?

age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
if age >= 18:
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Bu aşağıdakilerle sonuçlanır:

Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

Bu, yaşın asla anlamlı olmayacak bir değere sahip olmayacağı ve kodun "iş sürecinizin" mantığını takip ettiği için işe yarayacaktır.


22

Kabul edilen cevap şaşırtıcı olsa da. Ayrıca bu sorun için hızlı bir kesmek paylaşmak istiyorum. (Bu, negatif yaş problemini de halleder.)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

PS Bu kod python 3.x içindir.


1
Bu kodun özyinelemeli olduğunu unutmayın, ancak burada özyineleme gerekli değildir ve Kevin'in dediği gibi yığınızı patlatabilir.
PM 2Ring

2
@ PM2Ring - haklısın. Ama buradaki amacım sadece "kısa devre" nin uzun kod parçalarını nasıl minimize edebileceğini (güzelleştirebileceğini) göstermekti.
aaveg

11
Neden bir değişkene bir lambda atayabilirsiniz, defbunun yerine kullanın. def f(age):çok daha açıkf = lambda age:
GP89

3
Bazı durumlarda, sadece bir kez yaşa ihtiyacınız olabilir ve o zaman bu işlevi kullanamazsınız. Kişi bir işlevi kullanmak ve iş bittikten sonra atmak isteyebilir. Ayrıca, bu en iyi yol olmayabilir, ama kesinlikle bunu yapmanın farklı bir yoludur (bu benim çözümümün amacı idi).
aaveg

@aaveg aslında kullanıcı tarafından sağlanan yaşı kurtarmak için bu kodu nasıl çevirirsiniz?
Tytire Recubans

12

Yani, son zamanlarda buna benzer bir şeyle uğraşıyordum ve herhangi bir mantıksal şekilde kontrol edilmeden önce, önemsizliği reddeden girdi elde etmenin bir yolunu kullanan aşağıdaki çözümü buldum.

read_single_keypress()nezaket https://stackoverflow.com/a/6599441/4532996

def read_single_keypress() -> str:
    """Waits for a single keypress on stdin.
    -- from :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    try:
        ret = sys.stdin.read(1) # returns a single character
    except KeyboardInterrupt:
        ret = 0
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """read stdin until !(chars)"""
    import sys
    chars = list(chars)
    y = ""
    sys.stdout.flush()
    while True:
        i = read_single_keypress()
        _ = sys.stdout.write(i)
        sys.stdout.flush()
        if i not in chars:
            break
        y += i
    return y

def _can_you_vote() -> str:
    """a practical example:
    test if a user can vote based purely on keypresses"""
    print("can you vote? age : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nsorry, age can only consist of digits.")
        return
    print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")

_can_you_vote()

Tüm modülü burada bulabilirsiniz .

Misal:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _

Bu uygulamanın doğası, rakam olmayan bir şey okunduğu anda stdin'i kapatmasıdır. Sonra enter tuşuna basmadım aama rakamlardan sonra ihtiyacım vardı.

Bunu, thismany()sadece üç basamağa izin vermek için aynı modüldeki işlevle birleştirebilirsiniz .


12

Fonksiyonel yaklaşım veya " anneme bak döngü yok! ":

from itertools import chain, repeat

prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

veya diğer yanıtlarda olduğu gibi bir giriş isteminden ayrılmış bir "hatalı giriş" mesajı almak istiyorsanız:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

O nasıl çalışır?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    Bu kombinasyonu itertools.chainve itertools.repeatdizeleri verecektir bir yineleyici yaratacak "Enter a number: "bir kez ve "Not a number! Try again: "zaman sonsuz sayıda:
    for prompt in prompts:
        print(prompt)
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
  2. replies = map(input, prompts)- burada önceki adımdaki maptüm promptsdizeleri inputişleve uygulayacaktır . Örneğin:
    for reply in replies:
        print(reply)
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
  3. Biz kullanmak filterve str.isdigitsadece parmaklara içeren bu dizeleri filtrelemek için:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    Ve sadece kullandığımız ilk basamak dizesini almak için next.

Diğer doğrulama kuralları:

  1. Dize yöntemleri: Elbette str.isalphayalnızca alfabetik dizeler str.isupperalmak veya yalnızca büyük harf almak gibi diğer dize yöntemlerini kullanabilirsiniz . Tam liste için dokümanlara bakın .

  2. Üyelik testi:
    Bunu gerçekleştirmenin birkaç farklı yolu vardır. Bunlardan biri __contains__yöntemi kullanmaktır :

    from itertools import chain, repeat
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
  3. Sayı karşılaştırması:
    Burada kullanabileceğimiz yararlı karşılaştırma yöntemleri vardır. Örneğin, __lt__( <) için:

    from itertools import chain, repeat
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0

    Veya, dunder yöntemlerini kullanmayı sevmiyorsanız (dunder = çift alt çizgi), her zaman kendi işlevinizi tanımlayabilir veya operatormodülden kullanabilirsiniz.

  4. Yol varlığı:
    Burada pathlibkütüphane ve Path.existsyöntemi kullanılabilir:

    from itertools import chain, repeat
    from pathlib import Path
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt

Deneme sayısını sınırlama:

Bir kullanıcıya sonsuz sayıda şey sorarak işkence etmek istemiyorsanız, çağrısında bir sınır belirleyebilirsiniz itertools.repeat. Bu, nextişleve varsayılan bir değer sağlayarak birleştirilebilir :

from itertools import chain, repeat

prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

Giriş verilerini ön işleme:

Bazen kullanıcı yanlışlıkla CAPS'ta veya dizenin başında veya sonunda bir boşluk sağladıysa bir girişi reddetmek istemeyiz . Bu basit hataları hesaba katmak için giriş verilerini str.lowerve str.stripyöntemlerini kullanarak ön işlem yapabiliriz . Örneğin, üyelik testi durumunda kod şöyle görünecektir:

from itertools import chain, repeat

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

Ön işleme için kullanılacak birçok fonksiyonunuz varsa, bir fonksiyon kompozisyonu gerçekleştiren bir fonksiyon kullanmak daha kolay olabilir . Örneğin, buradan birini kullanarak :

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

Doğrulama kurallarını birleştirme:

Basit bir durum için, örneğin, program 1 ile 120 yaş arasında istediğinde, biri sadece başka bir tane ekleyebilir filter:

from itertools import chain, repeat

prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

Ancak birçok kural olduğunda, mantıksal birleşme gerçekleştiren bir işlevi uygulamak daha iyidir . Aşağıdaki örnekte buradan hazır bir tane kullanacağım :

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


def is_one_letter(string: str) -> bool:
    return len(string) == 1


rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]

prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

Ne yazık ki, birisi başarısız olan her vaka için özel bir mesaja ihtiyaç duyarsa, korkarım, oldukça işlevsel bir yol yoktur . Ya da en azından bir tane bulamadım.


Ne kapsamlı ve harika bir cevap, açıklama dökümü harikaydı.
Locane

Tarzınızı kullanarak, boşlukları sıyırma ve üyelik testi için girişi daha düşük bir kasaya nasıl dökmek gerekir? Hem büyük hem de küçük harf örnekleri içermesi gereken bir küme oluşturmak istemiyorum. Ayrıca boşluk girdi hatalarına izin vermek istiyorum.
Austin

1
@Austin Önişleme ile ilgili yeni bir bölüm ekledim. Bir göz at.
Georgy

Bu bana ReactiveX'i hatırlatıyor. Ama belki de bu ilk etapta işlevsel dillerden ilham aldı?
Mateen Ulhaq

8

Kullanımı tıklayın :

Click , komut satırı arabirimleri için bir kitaplıktır ve bir kullanıcıdan geçerli bir yanıt istemek için işlevsellik sağlar.

Basit örnek:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0

Dize değerini otomatik olarak bir kayan noktaya nasıl dönüştürdüğüne dikkat edin.

Bir değerin aralık dahilinde olup olmadığını kontrol etme:

Sağlanan farklı özel türler vardır . Belirli bir aralıktaki bir sayıyı almak için şunu kullanabiliriz IntRange:

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?: 
 a
Error: a is not a valid integer
What's your age?: 
 0
Error: 0 is not in the valid range of 1 to 120.
What's your age?: 
 5
5

Sınırlardan sadece birini belirtebiliriz minveya max:

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18

Üyelik testi:

click.ChoiceTürü kullanma . Varsayılan olarak bu kontrol büyük / küçük harfe duyarlıdır.

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange

Yollar ve dosyalarla çalışma:

Bir click.Pathtürü kullanarak mevcut yolları kontrol edebilir ve bunları çözebiliriz:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path: 
 nonexistent
Error: Path "nonexistent" does not exist.
Provide path: 
 existing_folder
'/path/to/existing_folder

Dosyaları okuma ve yazma şu şekilde yapılabilir click.File:

file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
In which file to write data?: 
         # <-- provided an empty string, which is an illegal name for a file
In which file to write data?: 
 some_file.txt
Which file you wanna read?: 
 nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?: 
 some_file.txt
Hello!

Diğer örnekler:

Şifre onayı:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password: 
 ······
Repeat for confirmation: 
 ·
Error: the two entered values do not match
Enter password: 
 ······
Repeat for confirmation: 
 ······
qwerty

Varsayılan değerler:

Bu durumda, Enterbir değer girmeden (veya kullandığınız herhangi bir tuşa) basmanız size varsayılan bir değer verir:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]: 
 a
Error: a is not a valid integer
Please enter a number [42]: 

42

3
def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Please enter your age:"))
        if validate_age(age): break
    except ValueError:
        print "Error: Invalid age."

2

Daniel Q's ve Patrick Artner'ın mükemmel önerilerini temel alarak, burada daha genel bir çözüm var.

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

Doğrulama ve sağlamlık sağlamak için doğrulama her zaman açık olmalıdır, çünkü bir yerine yerine açık ifve raiseifadeler için seçti assert.

Bu, farklı validasyon koşullarına sahip farklı girdi türleri elde etmek için kullanılabilir. Örneğin:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

Veya orijinal soruyu cevaplamak için:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

1

Bunu dene:-

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')

0

Bir try/ exceptblok çalışsa da, bu görevi yerine getirmenin çok daha hızlı ve daha temiz bir yolu kullanmak olacaktır str.isdigit().

while True:
    age = input("Please enter your age: ")
    if age.isdigit():
        age = int(age)
        break
    else:
        print("Invalid number '{age}'. Try again.".format(age=age))

if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

0

İyi soru! Bunun için aşağıdaki kodu deneyebilirsiniz. =)

Bu kod, kullanımları ast.literal_eval () için giriş veri yapısını ( age). Ardından aşağıdaki algoritmayı izler:

  1. Kullanıcıdan giriş yapmasını isteyin age.

    1.1. Eğer agebir floatya da intveri türü:

    • Kontrol edin age>=18. Varsa age>=18, uygun çıktıyı yazdırın ve çıkın.

    • Kontrol edin 0<age<18. Varsa 0<age<18, uygun çıktıyı yazdırın ve çıkın.

    • Eğer age<=0, yaş için geçerli bir sayı tekrar girişine kullanıcıya sor, ( yani geri adım 1. gidin)

    1.2. Değilse veya veri türü agedeğilse , kullanıcıdan yaşını tekrar girmesini isteyin ( yani 1. adıma geri dönün).floatint

İşte kod.

from ast import literal_eval

''' This function is used to identify the data type of input data.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Please enter your age: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("You are able to vote in the United States!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("You are not able to vote in the United States.") 
            flag = False
        else: print("Please enter a valid number as your age.")

    else: print("Sorry, I didn't understand that.") 

0

Her zaman basit if-else mantığını uygulayabilir ve ifbir fordöngü ile birlikte kodunuza bir mantık daha ekleyebilirsiniz .

while True:
     age = int(input("Please enter your age: "))
     if (age >= 18)  : 
         print("You are able to vote in the United States!")
     if (age < 18) & (age > 0):
         print("You are not able to vote in the United States.")
     else:
         print("Wrong characters, the input must be numeric")
         continue

Bu sonsuz bir tuvalet olacak ve size süresiz olarak girmeniz istenecek.


Bu soruya gerçekten cevap vermiyor. Soru, belirsiz bir şekilde değil, geçerli bir yanıt verene kadar bir kullanıcı girdisi almakla ilgiliydi .
Georgy

-1

Birçok gerçek dünya uygulamasında aynı kullanım örneği ortaya çıktığından, kullanıcının yalnızca belirli sayıda girmesine izin vermek için daha genel bir mantık yazabilirsiniz.

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.

1
döngüden sonra iCount değerini artırmayı unutuyorsunuz
Hoai-Thu Vuong 8 '

-1

Giriş deyimini bir süre True döngüsü oluşturabilir, böylece kullanıcı girdisini tekrar tekrar isteyebilir ve kullanıcı istediğiniz yanıtı girerse bu döngüyü kırabilir. Geçersiz yanıtları işlemek için try ve hariç bloklarını kullanabilirsiniz.

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

Var değişkeni sadece kullanıcı bir tamsayı yerine bir dize girerse, program "Amerika Birleşik Devletleri'nde oy kullanamazsınız" döndürmez.


-1

Kullanıcı gerçek bir değer girene kadar "while" deyimini kullanın ve giriş değeri bir sayı değilse veya null bir değerse atlayın ve tekrar sormaya çalışın. Mesela sorunuzu gerçekten cevaplamaya çalıştım. Yaşımızın 1 ile 150 arasında olduğunu varsayarsak, giriş değeri kabul edilir, aksi takdirde yanlış bir değerdir. Programı sonlandırmak için kullanıcı 0 tuşunu kullanabilir ve bir değer olarak girebilir.

Not: Kodun üst kısmındaki yorumları okuyun.

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
    Value = None
    while Value == None or Value.isdigit() == False:
        try:        
            Value = str(input(Message)).strip()
        except InputError:
            Value = None
    return Value

# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
    age = int(Input("Please enter your age: "))
    # For terminating program, the user can use 0 key and enter it as an a value.
    if age == 0:
        print("Terminating ...")
        exit(0)

if age >= 18 and age <=150: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

-1

ValidationErrorTamsayı girişleri için özelleştirilmiş ve (isteğe bağlı) aralık doğrulaması kullanarak giriş doğrulamayı kullanmak için bir çözüm daha :

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))

Kullanımı:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)

Çıktı:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2

-1

İşte / else bloke olursa tekrarlayanlardan kaçınan daha temiz ve daha genel bir çözüm: sözlükte (Hata, hata istemi) çiftleri alan bir işlev yazın ve tüm değer kontrollerinizi iddialarla yapın.

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

Kullanımı:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)

-1

Özyinelemeli işlev kullanan kalıcı kullanıcı girişi :

sicim

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

tamsayı

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

ve son olarak, soru şartı:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)

-2

Basit çözüm:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        if age>=18:
            print("You are able to vote in the United States!")
        else:
            print("You are not able to vote in the United States.")
        break

Yukarıdaki kodun açıklaması: Geçerli bir yaş için, pozitif olmalı ve normal fiziksel yaştan daha fazla olmamalıdır, örneğin maksimum yaş 120'dir.

Sonra kullanıcıdan yaş isteyebiliriz ve yaş girişi negatif veya 120'den fazla ise geçersiz girişi düşünür ve kullanıcıdan tekrar denemesini isteriz.

Geçerli giriş girildikten sonra, yaşın> = 18 olup olmadığını kontrol edin (iç içe if-else deyimini kullanarak) veya kullanıcının oy kullanmaya uygun olup olmadığını kontrol edin.


"Lütfen yaşınızı girin: dickety six" ': soruda belirtildiği gibi aynı çarpışma ...
BDL

-2

girdiyi dize olarak al ve girişin yalnızca rakam içermediğini kontrol etmek için isdigit () kullan, boş değil, -ve olamaz

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False


Ayrıca soruya cevap vermez.
Georgy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.