سؤال

أريد أن أكتب دالة في بايثون تقوم بإرجاع قيم ثابتة مختلفة بناءً على قيمة فهرس الإدخال.

في اللغات الأخرى سأستخدم a switch أو case عبارة، ولكن لا يبدو أن بايثون تحتوي على switch إفادة.ما هي حلول بايثون الموصى بها في هذا السيناريو؟

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

المحلول

يمكنك استخدام القاموس:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

نصائح أخرى

إذا كنت تريد الإعدادات الافتراضية، فيمكنك استخدام القاموس get(key[, default]) طريقة:

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

لقد أحببت دائمًا القيام بذلك بهذه الطريقة

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

من هنا

بالإضافة إلى طرق القاموس (التي تعجبني حقًا، راجع للشغل)، يمكنك أيضًا استخدام if-elif-else للحصول على وظيفة التبديل/الحالة/الافتراضية:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

هذا بالطبع ليس مطابقًا للتبديل/الحالة - لا يمكنك التراجع بسهولة مثل ترك الفاصل؛بيان، ولكن يمكن أن يكون لديك اختبار أكثر تعقيدا.يعد تنسيقه أجمل من سلسلة ifs المتداخلة، على الرغم من أن هذا هو أقرب إليه من الناحية الوظيفية.

وصفتي المفضلة في بايثون للتبديل/الحالة هي:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

قصيرة وبسيطة لسيناريوهات بسيطة.

قارن مع أكثر من 11 سطرًا من كود C:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

يمكنك أيضًا تعيين متغيرات متعددة باستخدام الصفوف:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))
class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

الاستخدام:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

الاختبارات:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

هناك نمط تعلمته من كود Twisted Python.

class SMTP:
    def lookupMethod(self, command):
        return getattr(self, 'do_' + command.upper(), None)
    def do_HELO(self, rest):
        return 'Howdy ' + rest
    def do_QUIT(self, rest):
        return 'Bye'

SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'

يمكنك استخدامه في أي وقت تحتاج فيه إلى إرسال رمز مميز وتنفيذ جزء ممتد من التعليمات البرمجية.في آلة الدولة سيكون لديك state_ طرق، والإرسال على self.state.يمكن توسيع رمز التبديل هذا بشكل نظيف عن طريق الوراثة من الفئة الأساسية وتحديد الفئة الخاصة بك do_ طُرق.في كثير من الأحيان لن يكون لديك حتى do_ الأساليب في الطبقة الأساسية.

يحرر:كيف يتم استخدام ذلك بالضبط

في حالة SMTP سوف تتلقى HELO من السلك.الكود ذو الصلة (من twisted/mail/smtp.py, ، تم تعديله لحالتنا) يبدو هكذا

class SMTP:
    # ...

    def do_UNKNOWN(self, rest):
        raise NotImplementedError, 'received unknown command'

    def state_COMMAND(self, line):
        line = line.strip()
        parts = line.split(None, 1)
        if parts:
            method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
            if len(parts) == 2:
                return method(parts[1])
            else:
                return method('')
        else:
            raise SyntaxError, 'bad syntax'

SMTP().state_COMMAND('   HELO   foo.bar.com  ') # => Howdy foo.bar.com

سوف تتلقى ' HELO foo.bar.com ' (أو قد تحصل 'QUIT' أو 'RCPT TO: foo').تم ترميز هذا في parts مثل ['HELO', 'foo.bar.com'].اسم البحث عن الطريقة الفعلية مأخوذ من parts[0].

(تسمى الطريقة الأصلية أيضًا state_COMMAND, لأنه يستخدم نفس النمط لتنفيذ آلة الحالة، أي. getattr(self, 'state_' + self.mode))

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

class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

هنا مثال:

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"
class Switch:
    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False # Allows a traceback to occur

    def __call__(self, *values):
        return self.value in values


from datetime import datetime

with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4):
        print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes

لنفترض أنك لا تريد إرجاع قيمة فقط، ولكنك تريد استخدام الأساليب التي تغير شيئًا ما في الكائن.باستخدام النهج المذكور هنا سيكون:

result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

ما يحدث هنا هو أن بايثون تقوم بتقييم جميع الأساليب في القاموس.لذلك، حتى لو كانت القيمة الخاصة بك هي "a"، فسيتم زيادة الكائن و انخفض بمقدار x.

حل:

func, args = {
  'a' : (obj.increment, (x,)),
  'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))

result = func(*args)

حتى تحصل على قائمة تحتوي على وظيفة ووسائطها.بهذه الطريقة، يتم إرجاع مؤشر الوظيفة وقائمة الوسائط فقط، لا تقييمها.تقوم "النتيجة" بعد ذلك بتقييم استدعاء الوظيفة التي تم إرجاعها.

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

if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"

لقد شعرت أن PEP 8 يستحق الإيماءة هنا.من الأشياء الجميلة في بايثون هي بساطتها وأناقتها.وهذا مستمد إلى حد كبير من المبادئ التي وضعناها في PEP 8، بما في ذلك "هناك طريقة واحدة صحيحة لفعل شيء ما"

التوسع في فكرة "الإملاء كمفتاح".إذا كنت تريد استخدام قيمة افتراضية لمفتاحك:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'

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

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

ملحوظة:يفعل لا استخدم "()" داخل البحث عن الحالة/القاموس وإلا فسوف يستدعي كل وظيفة من وظائفك أثناء إنشاء القاموس/كتلة الحالة.تذكر هذا لأنك تريد فقط استدعاء كل وظيفة مرة واحدة باستخدام البحث عن نمط التجزئة.

def first_case():
    print "first"

def second_case():
    print "second"

def third_case():
    print "third"

mycase = {
'first': first_case, #do not use ()
'second': second_case, #do not use ()
'third': third_case #do not use ()
}
myfunc = mycase['first']
myfunc()

إذا كنت تبحث عن عبارة إضافية، مثل "switch"، فقد قمت ببناء وحدة بايثون تعمل على توسيع لغة بايثون.تسمى إسبي باسم "البنية المحسنة لـ Python" وهي متاحة لكل من Python 2.x وPython 3.x.

على سبيل المثال، في هذه الحالة، يمكن تنفيذ عبارة التبديل بواسطة الكود التالي:

macro switch(arg1):
    while True:
        cont=False
        val=%arg1%
        socket case(arg2):
            if val==%arg2% or cont:
                cont=True
                socket
        socket else:
            socket
        break

والتي يمكن استخدامها مثل هذا:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")

لذا espy ترجمتها في بايثون على النحو التالي:

a=3
while True:
    cont=False
    if a==0 or cont:
        cont=True
        print ("Zero")
    if a==1 or cont:
        cont=True
        print ("Smaller than 2")
        break
    print ("greater than 1")
    break

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

l = ['Dog', 'Cat', 'Bird', 'Bigfoot',
     'Dragonfly', 'Snake', 'Bat', 'Loch Ness Monster']

for x in l:
    if x in ('Dog', 'Cat'):
        x += " has four legs"
    elif x in ('Bat', 'Bird', 'Dragonfly'):
        x += " has wings."
    elif x in ('Snake',):
        x += " has a forked tongue."
    else:
        x += " is a big mystery by default."
    print(x)

print()

for x in range(10):
    if x in (0, 1):
        x = "Values 0 and 1 caught here."
    elif x in (2,):
        x = "Value 2 caught here."
    elif x in (3, 7, 8):
        x = "Values 3, 7, 8 caught here."
    elif x in (4, 6):
        x = "Values 4 and 6 caught here"
    else:
        x = "Values 5 and 9 caught in default."
    print(x)

يوفر:

Dog has four legs
Cat has four legs
Bird has wings.
Bigfoot is a big mystery by default.
Dragonfly has wings.
Snake has a forked tongue.
Bat has wings.
Loch Ness Monster is a big mystery by default.

Values 0 and 1 caught here.
Values 0 and 1 caught here.
Value 2 caught here.
Values 3, 7, 8 caught here.
Values 4 and 6 caught here
Values 5 and 9 caught in default.
Values 4 and 6 caught here
Values 3, 7, 8 caught here.
Values 3, 7, 8 caught here.
Values 5 and 9 caught in default.

لقد وجدت أن بنية التبديل المشتركة:

switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;

يمكن التعبير عنها في بايثون على النحو التالي:

(lambda x: v1 if p1(x) else v2 if p2(x) else v3)

أو تنسيقها بطريقة أوضح:

(lambda x:
     v1 if p1(x) else
     v2 if p2(x) else
     v3)

بدلًا من أن تكون عبارة، فإن إصدار بايثون هو تعبير يتم تقييمه إلى قيمة.

الحلول التي أستخدمها:

مزيج من حلين من الحلول المنشورة هنا، وهو سهل القراءة نسبيًا ويدعم الإعدادات الافتراضية.

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)

أين

.get('c', lambda x: x - 22)(23)

انظر لفوق "lambda x: x - 2" في الإملاء ويستخدمه مع x=23

.get('xxx', lambda x: x - 22)(44)

لا يجده في الإملاء ويستخدم الإعداد الافتراضي "lambda x: x - 22" مع x=44.

# simple case alternative

some_value = 5.0

# this while loop block simulates a case block

# case
while True:

    # case 1
    if some_value > 5:
        print ('Greater than five')
        break

    # case 2
    if some_value == 5:
        print ('Equal to five')
        break

    # else case 3
    print ( 'Must be less than 5')
    break

معظم الإجابات هنا قديمة جدًا، وخاصة الإجابات المقبولة، لذا يبدو أنها تستحق التحديث.

أولا، الرسمية الأسئلة الشائعة في بايثون يغطي هذا، ويوصي elif سلسلة للحالات البسيطة و dict للحالات الأكبر أو الأكثر تعقيدًا.كما يقترح مجموعة من visit_ الأساليب (أسلوب يستخدمه العديد من أطر عمل الخادم) في بعض الحالات:

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

تذكر الأسئلة الشائعة أيضًا بيب 275, ، والذي تمت كتابته للحصول على قرار رسمي نهائي بشأن إضافة بيانات التبديل على النمط C.ولكن تم تأجيل PEP فعليًا إلى Python 3، وتم رفضه رسميًا فقط كاقتراح منفصل. بيب 3103.كانت الإجابة بالطبع لا، ولكن لدى الشخصين السياسيين السياسيين روابط لمعلومات إضافية إذا كنت مهتمًا بالأسباب أو التاريخ.


الشيء الوحيد الذي ظهر عدة مرات (ويمكن رؤيته في PEP 275، على الرغم من أنه تم قطعه كتوصية فعلية) هو أنه إذا كنت منزعجًا حقًا من وجود 8 أسطر من التعليمات البرمجية للتعامل مع 4 حالات، مقابل 8 أسطر من التعليمات البرمجية للتعامل مع 4 حالات.الأسطر الستة التي لديك في لغة C أو Bash، يمكنك دائمًا كتابة هذا:

if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')

هذا لا يشجعه PEP 8 تمامًا، ولكنه قابل للقراءة وليس أحادي المفردة.


على مدى أكثر من عقد من الزمان منذ رفض PEP 3103، تم اعتبار مسألة بيانات الحالة على النمط C، أو حتى الإصدار الأقوى قليلاً في Go، ميتة؛عندما يطرح أي شخص الأمر على أفكار python أو -dev، تتم إحالتهم إلى القرار القديم.

ومع ذلك، فإن فكرة المطابقة الكاملة لنمط ML تظهر كل بضع سنوات، خاصة وأن لغات مثل Swift وRust قد تبنتها.المشكلة هي أنه من الصعب الاستفادة كثيرًا من مطابقة الأنماط بدون أنواع البيانات الجبرية.في حين كان جويدو متعاطفًا مع الفكرة، لم يتوصل أحد إلى اقتراح يناسب بايثون جيدًا.(يمكنك أن تقرأ بلدي القش 2014 على سبيل المثال.) يمكن أن يتغير هذا مع dataclass في 3.7 وبعض المقترحات المتفرقة لأكثر قوة enum للتعامل مع أنواع المجموع، أو مع مقترحات مختلفة لأنواع مختلفة من الارتباطات المحلية للبيانات (مثل بيب 3150, ، أو مجموعة المقترحات التي تتم مناقشتها حاليًا حول الأفكار).ولكن حتى الآن، لم يحدث ذلك.

هناك أيضًا في بعض الأحيان مقترحات لمطابقة أنماط Perl 6، والتي تعد في الأساس مزيجًا من كل شيء elif إلى regex لتبديل نوع الإرسال الفردي.

def f(x):
    dictionary = {'a':1, 'b':2, 'c':3}
    return dictionary.get(x,'Not Found') 
##Returns the value for the letter x;returns 'Not Found' if x isn't a key in the dictionary

أحببت إجابة مارك بيس

منذ x يجب استخدام المتغير مرتين، وقمت بتعديل وظائف لامدا إلى بلا معلمات.

لا بد لي من تشغيل مع results[value](value)

In [2]: result = {
    ...:   'a': lambda x: 'A',
    ...:   'b': lambda x: 'B',
    ...:   'c': lambda x: 'C'
    ...: }
    ...: result['a']('a')
    ...: 
Out[2]: 'A'

In [3]: result = {
    ...:   'a': lambda : 'A',
    ...:   'b': lambda : 'B',
    ...:   'c': lambda : 'C',
    ...:   None: lambda : 'Nothing else matters'

    ...: }
    ...: result['a']()
    ...: 
Out[3]: 'A'

يحرر: لقد لاحظت أنه يمكنني استخدامها None اكتب مع القواميس.لذلك هذا من شأنه أن يحاكي switch ; case else

حل لتشغيل الوظائف:

result = {
    'case1':     foo1, 
    'case2':     foo2,
    'case3':     foo3,
    'default':   default,
}.get(option)()

حيث foo1() و foo2() و foo3() و ​​default() هي وظائف

def f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default

قصير وسهل القراءة، وله قيمة افتراضية ويدعم التعبيرات في كل من الشروط وقيم الإرجاع.

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

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

class ChoiceManager:

    def __init__(self):
        self.__choice_table = \
        {
            "CHOICE1" : self.my_func1,
            "CHOICE2" : self.my_func2,
        }

    def my_func1(self, data):
        pass

    def my_func2(self, data):
        pass

    def process(self, case, data):
        return self.__choice_table[case](data)

ChoiceManager().process("CHOICE1", my_data)

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

لنفترض أنه يتعين عليك معالجة الكثير من الرسائل أو الحزم من الشبكة أو من MQ الخاص بك.كل حزمة لها هيكلها الخاص ورمز الإدارة الخاص بها (بطريقة عامة).باستخدام الكود أعلاه من الممكن القيام بشيء مثل هذا:

class PacketManager:

    def __init__(self):
        self.__choice_table = \
        {
            ControlMessage : self.my_func1,
            DiagnosticMessage : self.my_func2,
        }

    def my_func1(self, data):
        # process the control message here
        pass

    def my_func2(self, data):
        # process the diagnostic message here
        pass

    def process(self, pkt):
        return self.__choice_table[pkt.__class__](pkt)

pkt = GetMyPacketFromNet()
PacketManager().process(pkt)


# isolated test or isolated usage example
def test_control_packet():
    p = ControlMessage()
    PacketManager().my_func1(p)

لذا لا ينتشر التعقيد في تدفق التعليمات البرمجية ولكن يتم تقديمه في بنية التعليمات البرمجية.

التوسع في إجابة جريج هيوجيل - يمكننا تغليف حل القاموس باستخدام الديكور:

def case(callable):
    """switch-case decorator"""
    class case_class(object):
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

        def do_call(self):
            return callable(*self.args, **self.kwargs)

return case_class

def switch(key, cases, default=None):
    """switch-statement"""
    ret = None
    try:
        ret = case[key].do_call()
    except KeyError:
        if default:
            ret = default.do_call()
    finally:
        return ret

ويمكن بعد ذلك استخدام هذا مع @case-ديكور

@case
def case_1(arg1):
    print 'case_1: ', arg1

@case
def case_2(arg1, arg2):
    print 'case_2'
    return arg1, arg2

@case
def default_case(arg1, arg2, arg3):
    print 'default_case: ', arg1, arg2, arg3

ret = switch(somearg, {
    1: case_1('somestring'),
    2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))

print ret

والخبر السار هو أن هذا قد تم بالفعل NeoPySwitch-وحدة.ببساطة قم بالتثبيت باستخدام النقطة:

pip install NeoPySwitch

الحل الذي أميل إلى استخدامه والذي يستخدم القواميس أيضًا هو:

def decision_time( key, *args, **kwargs):
    def action1()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action2()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action3()
        """This function is a closure - and has access to all the arguments"""
        pass

   return {1:action1, 2:action2, 3:action3}.get(key,default)()

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

يمكنك استخدام الإملاء المرسل:

#!/usr/bin/env python


def case1():
    print("This is case 1")

def case2():
    print("This is case 2")

def case3():
    print("This is case 3")


token_dict = {
    "case1" : case1,
    "case2" : case2,
    "case3" : case3,
}


def main():
    cases = ("case1", "case3", "case2", "case1")
    for case in cases:
        token_dict[case]()


if __name__ == '__main__':
    main()

انتاج:

This is case 1
This is case 3
This is case 2
This is case 1

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

for case in [expression]:
    if case == 1:
        print(end='Was 1. ')

    if case == 2:
        print(end='Was 2. ')
        break

    if case in (1, 2):
        print(end='Was 1 or 2. ')

    print(end='Was something. ')

مطبوعات Was 1. Was 1 or 2. Was something. (اللعنة!لماذا لا يمكنني الحصول على مسافة بيضاء زائدة في كتل التعليمات البرمجية المضمنة؟) لو expression يقيم ل 1, Was 2. لو expression يقيم ل 2, ، أو Was something. لو expression يقيم لشيء آخر.

تعريف:

def switch1(value, options):
  if value in options:
    options[value]()

يسمح لك باستخدام صيغة واضحة إلى حد ما، مع تجميع الحالات في الخريطة:

def sample1(x):
  local = 'betty'
  switch1(x, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye," + local),
      print("!")),
    })

لقد ظللت أحاول إعادة تعريف التبديل بطريقة تسمح لي بالتخلص من "lambda:"، لكنني استسلمت.تعديل التعريف:

def switch(value, *maps):
  options = {}
  for m in maps:
    options.update(m)
  if value in options:
    options[value]()
  elif None in options:
    options[None]()

سمح لي بتعيين حالات متعددة لنفس الرمز، وتوفير خيار افتراضي:

def sample(x):
  switch(x, {
    _: lambda: print("other") 
    for _ in 'cdef'
    }, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye,"),
      print("!")),
    None: lambda: print("I dunno")
    })

يجب أن تكون كل حالة منسوخة في قاموسها الخاص؛يقوم الدالة Switch()‎ بدمج القواميس قبل البحث عن القيمة.لا يزال الأمر أقبح مما أريد، لكنه يتمتع بالكفاءة الأساسية المتمثلة في استخدام بحث مجزأ في التعبير، بدلاً من إجراء حلقة عبر جميع المفاتيح.

إذا كنت لا تقلق بشأن فقدان تمييز بناء الجملة داخل مجموعات الحالات، فيمكنك القيام بما يلي:

exec {
    1: """
print ('one')
""", 
    2: """
print ('two')
""", 
    3: """
print ('three')
""",
}.get(value, """
print ('None')
""")

أين value هي القيمة.في C، سيكون هذا:

switch (value) {
    case 1:
        printf("one");
        break;
    case 2:
        printf("two");
        break;
    case 3:
        printf("three");
        break;
    default:
        printf("None");
        break;
}

يمكننا أيضًا إنشاء وظيفة مساعدة للقيام بذلك:

def switch(value, cases, default):
    exec cases.get(value, default)

لذلك يمكننا استخدامه مثل هذا للمثال مع واحد واثنين وثلاثة:

switch(value, {
    1: """
print ('one')
    """, 
    2: """
print ('two')
    """, 
    3: """
print ('three')
    """,
}, """
print ('None')
""")
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top