มีวิธีที่ดีกว่าในการเขียนที่ซ้อนกันถ้างบในหลาม? [ปิด]


34

มีวิธี pythonic เพิ่มเติมที่จะทำซ้อนถ้างบอื่นกว่านี้:

def convert_what(numeral_sys_1, numeral_sys_2):

    if numeral_sys_1 == numeral_sys_2:      
        return 0
    elif numeral_sys_1 == "Hexadecimal":
        if numeral_sys_2 == "Decimal":
            return 1
        elif numeral_sys_2 == "Binary":
            return 2
    elif numeral_sys_1 == "Decimal":
        if numeral_sys_2 == "Hexadecimal":
            return 4
        elif numeral_sys_2 == "Binary":
            return 6
    elif numeral_sys_1 == "Binary":
        if numeral_sys_2 == "Hexadecimal":
            return 5
        elif numeral_sys_2 == "Decimal":
            return 3
    else:
        return 0

สคริปต์นี้เป็นส่วนหนึ่งของโปรแกรมแปลงไฟล์อย่างง่าย


หากไม่ใช้โครงสร้างข้อมูลอื่นคุณสามารถย้ายคำสั่ง if-else แบบซ้อนไปยังandเงื่อนไขสำหรับคำสั่ง if-else ระดับบนสุด อย่างน้อยมันก็น่าจะอ่านได้มากกว่านี้ น่าเศร้าที่ไพ ธ อนไม่มีคำสั่งสลับ
adamkgray

นี่คือวิธีการแบบ pythonic Python โดยเจตนาไม่สนับสนุนคำสั่ง switch ดูpython.org/dev/peps/pep-3103
Jongmin Baek

1
ไม่ใช่คำถามเลย แต่ถ้าคุณพยายามทำให้ Pythonic มีความหมายมากขึ้นวิธีกำหนดค่าคงที่หรือค่า enum สำหรับค่าส่งคืน - ดีกว่าสำหรับผู้อ่านมากกว่า "หมายเลขมายากล" ....
Mats Wichmann

คำตอบ:


13

ในขณะที่ @Aryerez และ @ SencerH. ทำงานได้คำตอบค่าที่เป็นไปได้แต่ละค่าnumeral_sys_1จะต้องเขียนซ้ำสำหรับแต่ละค่าที่เป็นไปได้ของnumeral_sys_2เมื่อแสดงรายการคู่ค่าทำให้โครงสร้างข้อมูลยากขึ้นเมื่อจำนวนค่าที่เป็นไปได้เพิ่มขึ้น คุณสามารถใช้คำสั่งที่ซ้อนกันแทนการซ้อนคำสั่งของคุณแทน:

mapping = {
    'Hexadecimal': {'Decimal': 1, 'Binary': 2},
    'Binary': {'Decimal': 3, 'Hexadecimal': 5},
    'Decimal': {'Hexadecimal': 4, 'Binary': 6}
}
def convert_what(numeral_sys_1, numeral_sys_2):
    return mapping.get(numeral_sys_1, {}).get(numeral_sys_2, 0)

อีกวิธีหนึ่งคุณสามารถสร้างคู่ของค่าสำหรับการแมปด้วยitertools.permutationsวิธีการลำดับที่ตามมาของลำดับการป้อนข้อมูล:

mapping = dict(zip(permutations(('Hexadecimal', 'Decimal', 'Binary'), r=2), (1, 2, 4, 6, 3, 5)))
def convert_what(numeral_sys_1, numeral_sys_2):
    return mapping.get((numeral_sys_1, numeral_sys_2), 0)

29

ใส่ทุกชุดที่ถูกต้องไปยังdictionaryของtuples และถ้ารวมกันไม่ได้มีกลับ 0:

def convert_what(numeral_sys_1, numeral_sys_2):
    numeral_dict = {
        ("Hexadecimal", "Decimal"    ) : 1,
        ("Hexadecimal", "Binary"     ) : 2,
        ("Decimal",     "Hexadecimal") : 4, 
        ("Decimal",     "Binary"     ) : 6,
        ("Binary",      "Hexadecimal") : 5,
        ("Binary",      "Decimal"    ) : 3
    }
    return numeral_dict.get((numeral_sys_1, numeral_sys_2), 0)

หากคุณวางแผนที่จะใช้ฟังก์ชั่นในการวนซ้ำมันอาจเป็นความคิดที่ดีกว่าในการกำหนดพจนานุกรมภายนอกฟังก์ชั่นดังนั้นมันจะไม่ถูกสร้างขึ้นใหม่ทุกครั้งที่มีการเรียกใช้ฟังก์ชัน


2
except KeyError:
RomanPerekhrest

@ RomanPerekhrest ฉันได้เพิ่มไว้แล้วแม้ว่าในคำถามเฉพาะนี้ฟังก์ชันเองไม่มีข้อผิดพลาดประเภทอื่นที่จะสร้างผลลัพธ์ที่แตกต่างจากฟังก์ชั่นดั้งเดิมของเขา
Aryerez

1
parens ซ้ำซ้อนภายใน [] ยกเว้น tuple ที่ว่างเปล่ามันคือเครื่องหมายจุลภาคที่ทำให้เป็น tuple ไม่ใช่วงเล็บนั่นเป็นเพียงคำสั่งของการดำเนินการในบางกรณี
gilch

4
คุณสามารถใช้.get()เมธอดdict เป็น0ค่าเริ่มต้นแทนที่จะเป็นtryคำสั่ง
gilch

@ Gilch ฉันลบวงเล็บ แต่ฉันชอบtry:... except:...โครงสร้าง
Aryerez

17

หากคุณแน่ใจว่าไม่มีค่าอื่นใดที่สามารถตั้งค่าเป็นตัวแปร numeral_sys_1 และ numeral_sys_2 นี่เป็นวิธีที่ง่ายและสะอาดที่สุด

ในอีกทางหนึ่งคุณจะต้องขยายพจนานุกรมด้วยการรวมกันของมันพร้อมกับค่าที่มีอยู่หากคุณมีค่าอื่นที่ไม่ใช่ "เลขฐานสิบหก", "ทศนิยม" และ "ไบนารี"

ตรรกะที่นี่คือ; ถ้าตัวแปร tuples ในคีย์พจนานุกรมไม่เท่ากับตัวแปร tuple ที่กำหนดเมธอด. get () จะส่งคืน "0" หากตัวแปร tuple ที่กำหนดตรงกับคีย์ใด ๆ ในพจนานุกรมจึงส่งคืนค่าของคีย์การจับคู่

def convert_what(numeral_sys_1, numeral_sys_2):
    return {
        ("Hexadecimal", "Decimal") : 1, 
        ("Hexadecimal", "Binary") : 2, 
        ("Binary", "Decimal") : 3,
        ("Decimal", "Hexadecimal") : 4,
        ("Binary", "Hexadecimal") : 5, 
        ("Decimal", "Binary") : 6, 
     }.get((numeral_sys_1, numeral_sys_2), 0)

นอกจากนี้ยังมีการใช้เครื่องกำเนิดไฟฟ้าอาจเป็นวิธีแก้ปัญหา ดูฉลาดกว่านี้ แต่ฉันคิดว่าพจนานุกรมที่เขียนโค้ดยากจะเร็วกว่าการใช้ตัวสร้างสำหรับข้อกำหนดที่เรียบง่ายนี้


การตีความของฉันสำหรับ 'else: return 0' ล่าสุดคืออาร์กิวเมนต์ไม่ตรงกันและอาจเป็นอย่างอื่นนอกเหนือจากที่อยู่ในรายการ (เช่นคีย์ dict ของคุณ)
tocode

@tocode ใช่คุณพูดถูก แต่วิธีนี้ก็มีฟังก์ชั่นการใช้งานเหมือนกันด้วย หากมีข้อโต้แย้งอย่างใดอย่างหนึ่งหรือทั้งสองให้กับวิธีการพูดไม่ใช่สตริงแม้จะเป็นค่าประเภทไม่มี; .get () วิธีการคืน "0" เนื่องจากการขาดคีย์ในพจนานุกรม มันไม่ง่ายเหรอ?
Sencer H.

คุณไม่ได้คัดลอกคำตอบ Aryerez?
Martin

@ มาร์ตินไม่ฉันไม่ได้ทำ คุณหายไปอย่างชัดเจนจุด มีหลายวิธีที่จะทำบางสิ่ง แต่การสอนวิธีที่ถูกต้องคือสิ่งที่ฉันยินดีทำที่นี่ จริงๆแล้วมีคำตอบที่ดีกว่าด้านล่าง ลองดูวิธีการแก้ปัญหาของ furkanayd มันไร้ที่ติและต้องได้รับรางวัล
Sencer H.

@ SencerH.The ความแตกต่างเพียงอย่างเดียวคือคุณใช้วิธีการของ dict get () ซึ่งเป็นพื้นฐานที่ลอง / ยกเว้นคำตอบดั้งเดิม คุณไม่สามารถปฏิเสธความจริงที่ว่าคุณคัดลอกความคิดและเล็กน้อยมาก (โดยไม่ต้องปรับปรุง) แก้ไขและเผยแพร่
Martin

3

วิธีอื่นในการใช้รายการซ้อนกัน หวังว่ามันจะช่วย !!

def convert_what(numeral_sys_1, numeral_sys_2):

    l1 = [["Hexadecimal","Decimal"],["Hexadecimal","Binary"],
            ["Decimal","Hexadecimal"],["Decimal","Binary"],
            ["Binary","Hexadecimal"],["Binary","Decimal"]]

    return l1.index([numeral_sys_1, numeral_sys_2]) + 1 if [numeral_sys_1,numeral_sys_2] in l1 else 0

2

ในความคิดของฉันconvert_whatฟังก์ชั่นนี้ไม่ได้เป็น pythonic มาก convert_what()ฉันเดารหัสซึ่งเรียกรหัสนี้มีพวงของถ้างบเกินไปและไม่แปลงขึ้นอยู่กับค่าตอบแทนของ ฉันแนะนำสิ่งนี้:

ขั้นตอนแรกสร้างฟังก์ชั่นเดียวสำหรับทุกชุด:

def hex_dec(inp):
    return 1234  # todo implement
# do the same for hex_bin, bin_dec, dec_hex, bin_hex, dec_bin

ขั้นตอนที่สองวางวัตถุฟังก์ชันใน dict โปรดทราบว่าไม่มี () หลังจากชื่อฟังก์ชั่นเพราะเราต้องการที่จะเก็บวัตถุฟังก์ชั่นและยังไม่เรียกมัน:

converter_funcs = {
    ("Hexadecimal", "Decimal"): hex_dec,
    ("Hexadecimal", "Binary"): hex_bin,
    ("Binary", "Decimal"): bin_dec,
    ("Decimal", "Hexadecimal"): dec_hex,
    ("Binary", "Hexadecimal"): bin_hex,
    ("Decimal", "Binary"): dec_bin,
}

ขั้นตอนที่สามและสุดท้ายใช้ฟังก์ชันแปลง คำสั่ง if ตรวจสอบว่าทั้งสองระบบเหมือนกันหรือไม่ จากนั้นเราจะได้ฟังก์ชันที่ถูกต้องจาก dict ของเราและเรียกมันว่า:

def convert(input_number, from_sys, to_sys):
    if from_sys == to_sys:
        return input_number
    func = converter_funcs[(from_sys, to_sys)]
    return func(input_number)

2

สิ่งนี้ทำได้โดยคำสั่ง switch-case ในภาษาอื่น ๆ ส่วนใหญ่ ในหลามฉันใช้ฟังก์ชั่นง่าย ๆ กับพจนานุกรมการแสดงออก

รหัส:

def convert_what(numeral_sys_1, numeral_sys_2):
    myExpressions = {"Hexadecimal" : {"Decimal" : 1, "Binary" : 2},
                    "Decimal" : {"Hexadecimal" : 4, "Binary" : 6}, 
                    "Binary" : {"Hexadecimal" : 5, "Decimal" : 3}}
    return (myExpressions.get(numeral_sys_1, {})).get(numeral_sys_2, 0)

เอาท์พุท:

> convert_what("Hexadecimal", "Decimal")
> 1
> convert_what("Binary", "Binary")
> 0
> convert_what("Invalid", "Hexadecimal")
> 0

นี่เป็นทางเลือกที่ดีสำหรับคำตอบยอดนิยมและง่ายต่อการขยายไปสู่คุณค่าที่มากขึ้นเช่นกัน
gkhnavarro

นี้สวยคล้ายกับคำตอบก่อนหน้า: stackoverflow.com/a/58985114/1895261 นอกจากนี้ฉันคิดว่าบรรทัดสุดท้ายควรส่งคืน dict ที่ว่างเปล่ามากกว่า 0 ในกรณีที่ numeral_sys_1 ไม่ได้อยู่ใน dict ด้านนอก: return (myExpressions.get (numeral_sys_1, {})) รับ (numeral_sys_2, 0)
Sepia

@Sepia ในคำถาม Module_art ให้ 0 ที่คำสั่ง else ซึ่งหมายความว่าการส่งคืน 0 สิ่งใดไม่สอดคล้องกับนิพจน์ที่กำหนดและสถานการณ์ความเท่าเทียมกัน
furkanayd

1
ลองสั่งพิมพ์ (convert_what ("ไม่ถูกต้อง", "เลขฐานสิบหก")) ด้วยรหัสของคุณ มันจะเพิ่มข้อผิดพลาด: "AttributeError: 'int' วัตถุไม่มีแอตทริบิวต์ 'รับ'" การแทนที่ 0 แรกด้วย dict ที่ว่างเปล่า ({}) จะทำให้ฟังก์ชันส่งคืนค่า 0 อย่างถูกต้องในกรณีที่ numeral_sys_1 ไม่ถูกต้อง
Sepia

1

โดยทั่วไปฉันจะเรียกใช้ด้วยโซลูชันพจนานุกรมสำหรับซ้อนกันถ้างาน บางกรณีอาจนำไปสู่แนวทางอื่น ชอบสิ่งนี้:

def convert_what(numeral_sys_1, numeral_sys_2):

    num = ['Hexadecimal','Decimal','Binary']
    tbl = [[0,1,2],
           [4,0,6],
           [5,3,0]]
    try:
        return tbl[num.index(numeral_sys_1)][num.index(numeral_sys_2)]
    except ValueError:
        return 0

1

เกี่ยวกับสิ่งที่ชอบ:

def convert_what(numeral_sys_1, numeral_sys_2):
    src = numeral_sys_1, numeral_sys_2
    if src == "Hexadecimal", "Decimal":
        return 1
    if src == "Hexadecimal", "Binary"
        return 2
    # You get the gist.... 
    if src == "Decimal", "Binary":
        return 6
    return 0 

1

แนวคิดหนึ่งใช้รายการและรับดัชนีผลลัพธ์เช่น

def convert_what(numeral_sys_1, numeral_sys_2):
    if numeral_sys_1 == numeral_sys_2:      
        return 0
    return ["HexadecimalDecimal", "HexadecimalBinary", "BinaryDecimal", "DecimalHexadecimal", "BinaryHexadecimal", "DecimalBinary" ].index(numeral_sys_1 + numeral_sys_2) + 1

ข้อเสนอแนะที่น่าสนใจ แต่สิ่งนี้ไม่ทำงานเมื่อข้อโต้แย้งคือ ("ทศนิยม", "ไม่") ซึ่งส่งผลให้เกิด ValueError: 'DecimalNot' ไม่อยู่ในรายการ
tocode

1

ตามที่ @Sadap พูด

ในความคิดของฉันconvert_whatฟังก์ชั่นนี้ไม่ได้เป็น pythonic มาก convert_what()ฉันเดารหัสซึ่งเรียกรหัสนี้มีพวงของถ้างบเกินไปและไม่แปลงขึ้นอยู่กับค่าตอบแทนของ ฉันแนะนำสิ่งนี้:

intหากคุณกำลังดำเนินการแปลงฐานจำนวนเต็มคุณอาจจะผ่านการแสดงร่วมกันอยู่แล้ว: ไม่จำเป็นต้องใช้ฟังก์ชั่นแยกต่างหากสำหรับแต่ละคู่เบสและทั้งสองเบสที่เกี่ยวข้องไม่จำเป็นต้องรู้ซึ่งกันและกัน

อินพุต

สร้างการแมปจากชื่อของระบบตัวเลขไปที่ฐาน:

BINARY = "Binary"
DECIMAL = "Decimal"
HEXADECIMAL = "Hexadecimal"

BASES = {
    BINARY: 2,
    DECIMAL: 10,
    HEXADECIMAL: 16,
}

int(text, BASES[numeral_sys_1])ช่วยให้คุณสามารถอ่านปัจจัยการผลิตด้วย

เอาท์พุต

สร้างการแมปจากชื่อของระบบตัวเลขไปยังตัวระบุรูปแบบ :

FORMATTERS = {
    BINARY: "b",
    DECIMAL: "d",
    HEXADECIMAL: "x",
}

format(n, FORMATTERS[numeral_sys_2])ช่วยให้คุณสามารถเขียนผลกับ

ตัวอย่างการใช้

def convert(text, numeral_sys_1, numeral_sys_2):
    n = int(text, BASES[numeral_sys_1])
    return format(n, FORMATTERS[numeral_sys_2])

ทั้ง dict สามารถทำให้เป็นเรื่องทั่วไปได้มากขึ้นด้วยการทำให้ฟังก์ชั่นค่าต่างๆแทนหากคุณต้องการสนับสนุนชุดรูปแบบที่แตกต่างกว่าint(x, base)หรือมากกว่าฐานเอาท์พุทมากกว่าการจัดรูปแบบจำนวนเต็มในตัว


0

ฉันชอบที่จะทำให้รหัสแห้ง:

def convert_what_2(numeral_sys_1, numeral_sys_2):
    num_sys = ["Hexadecimal", "Decimal", "Binary"]
    r_value = {0: {1: 1, 2: 2},
               1: {0: 4, 2: 6},
               2: {0: 5, 1: 3} }
    try:
        value = r_value[num_sys.index(numeral_sys_1)][num_sys.index(numeral_sys_2)]
    except KeyError: # Catches when they are equal or undefined
        value = 0
    return value

0

การใช้เทคนิคบางอย่างที่คำตอบอื่น ๆ นำเสนอและรวมเข้าด้วยกัน:

def convert(key1, key2):
    keys = ["Hexadecimal", "Decimal", "Binary"]
    combinations = {(0, 1): 1, (0, 2): 2, (1, 0): 4, (1, 2): 6, (2, 0): 5, (2, 1): 3} # use keys indexes to map to combinations
    try:
        return combinations[(keys.index(key1), keys.index(key2))]
    except (KeyError, ValueError): # if value is not in list, return as 0
        return 0

-1

แม้ว่าจะไม่แน่ใจว่าวิธีนี้เร็วกว่าหรือไม่ แต่สามารถทำได้โดยใช้ numpy เช่นกัน:

conditions = [
    ("Hexadecimal", "Decimal"), ("Hexadecimal", "Binary"),
    ("Binary", "Decimal"), ("Decimal", "Hexadecimal"), ("Binary", "Hexadecimal"), ("Decimal", "Binary")]
choices = [1,2,3,4,5,6]

และสามารถใช้เป็น:

 np.select(conditions, choices, default=0)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.