thắc mắc Làm sao để rút gọn đống if trong python

Chào các bác,

E có đoạn code sau mô phỏng lệnh wc trong linux, mặc định là in ra số dòng, từ, ký tự từ file, nếu nhiều file thì in tương tự từng file một, và chốt là tổng dòng, từ, ký tự.

Tùy theo option truyền vào mà chỉ in ra tương ứng giá trị , ví dụ nếu đưa -w vào thì chỉ in số ký tự, -wc thì chỉ in số từ và ký tự.

Code hiện giờ nhiều if quá, nhìn rối rắm nhưng e ko biết làm sao để rút bớt xuống. Nhờ các bác gợi ý ạ.

Python:
#!/usr/bin/env python

import sys

import argparse

# --------------------------------------------------

def get_args():

    parser = argparse.ArgumentParser(

        description='Emulate wordcount',

        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('file', nargs="*",

                        metavar='FILE',type=argparse.FileType('rt'),default=[sys.stdin],

                        help='Input files(s)')

    parser.add_argument('-c', '--character', help='number of characters', action='store_true')

    parser.add_argument('-l', '--line',help='number of lines',action='store_true')

    parser.add_argument('-w', '--word', help='number of words',action='store_true')

    return parser.parse_args()

# --------------------------------------------------

def main():

    args = get_args()

    file_arg = args.file

    #get each argument

    character_args = args.character

    line_args = args.line

    word_args = args.word

    total_line, total_words, total_byte = 0, 0, 0

    for fh in file_arg:

        line_count, words_count, byte_count = 0, 0, 0

        for line in fh:

            line_count += 1

            byte_count += len(line)

            words_count += len(line.split())

            total_line += 1

            total_words += len(line.split())

            total_byte += len(line)

        if character_args and not line_args and not word_args:

            print(f'{byte_count:8} {fh.name}')

        if line_args and not character_args and not word_args:

            print(f'{line_count:8} {fh.name}')

        if word_args and not character_args and not line_args:

            print(f'{words_count:8} {fh.name}')

        if character_args and line_args and not word_args:

            print(f'{byte_count:8}{line_count:8} {fh.name}')  

        if character_args and word_args and not line_args:

            print(f'{byte_count:8}{words_count:8} {fh.name}')

        if line_args and word_args and not character_args:

            print(f'{line_count:8}{words_count:8} {fh.name}')

        if line_args and word_args and character_args:

            print(f'{line_count:8}{words_count:8}{byte_count:8} {fh.name}')

        if not line_args and not word_args and not character_args:

            print(f'{line_count:8}{words_count:8}{byte_count:8} {fh.name}')

    if len(file_arg) > 1:

        if character_args and not line_args and not word_args:

            print(f'{total_byte:8} total')

        if line_args and not character_args and not word_args:

            print(f'{total_line:8} total')

        if word_args and not character_args and not line_args:

            print(f'{total_words:8} total')

        if character_args and line_args and not word_args:

            print(f'{total_byte:8}{total_line:8} total')  

        if character_args and word_args and not line_args:

            print(f'{total_byte:8}{total_words:8} total')

        if line_args and word_args and not character_args:

            print(f'{total_line:8}{total_words:8} total')

        if line_args and word_args and character_args:

            print(f'{total_line:8}{total_words:8}{total_byte:8} total')

        if not line_args and not word_args and not character_args:

            print(f'{total_line:8}{total_words:8}{total_byte:8} total')

# --------------------------------------------------

if name == 'main':

    main()
 
https://github.com/coreutils/coreutils/blob/master/src/wc.c
Thím xem trong source linux nó cũng if else với switch thôi.
1621658841852.png
 
Chào các bác,

E có đoạn code sau mô phỏng lệnh wc trong linux, mặc định là in ra số dòng, từ, ký tự từ file, nếu nhiều file thì in tương tự từng file một, và chốt là tổng dòng, từ, ký tự.

Tùy theo option truyền vào mà chỉ in ra tương ứng giá trị , ví dụ nếu đưa -w vào thì chỉ in số ký tự, -wc thì chỉ in số từ và ký tự.

Code hiện giờ nhiều if quá, nhìn rối rắm nhưng e ko biết làm sao để rút bớt xuống. Nhờ các bác gợi ý ạ.

Python:
#!/usr/bin/env python

import sys

import argparse

# --------------------------------------------------

def get_args():

    parser = argparse.ArgumentParser(

        description='Emulate wordcount',

        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('file', nargs="*",

                        metavar='FILE',type=argparse.FileType('rt'),default=[sys.stdin],

                        help='Input files(s)')

    parser.add_argument('-c', '--character', help='number of characters', action='store_true')

    parser.add_argument('-l', '--line',help='number of lines',action='store_true')

    parser.add_argument('-w', '--word', help='number of words',action='store_true')

    return parser.parse_args()

# --------------------------------------------------

def main():

    args = get_args()

    file_arg = args.file

    #get each argument

    character_args = args.character

    line_args = args.line

    word_args = args.word

    total_line, total_words, total_byte = 0, 0, 0

    for fh in file_arg:

        line_count, words_count, byte_count = 0, 0, 0

        for line in fh:

            line_count += 1

            byte_count += len(line)

            words_count += len(line.split())

            total_line += 1

            total_words += len(line.split())

            total_byte += len(line)

        if character_args and not line_args and not word_args:

            print(f'{byte_count:8} {fh.name}')

        if line_args and not character_args and not word_args:

            print(f'{line_count:8} {fh.name}')

        if word_args and not character_args and not line_args:

            print(f'{words_count:8} {fh.name}')

        if character_args and line_args and not word_args:

            print(f'{byte_count:8}{line_count:8} {fh.name}') 

        if character_args and word_args and not line_args:

            print(f'{byte_count:8}{words_count:8} {fh.name}')

        if line_args and word_args and not character_args:

            print(f'{line_count:8}{words_count:8} {fh.name}')

        if line_args and word_args and character_args:

            print(f'{line_count:8}{words_count:8}{byte_count:8} {fh.name}')

        if not line_args and not word_args and not character_args:

            print(f'{line_count:8}{words_count:8}{byte_count:8} {fh.name}')

    if len(file_arg) > 1:

        if character_args and not line_args and not word_args:

            print(f'{total_byte:8} total')

        if line_args and not character_args and not word_args:

            print(f'{total_line:8} total')

        if word_args and not character_args and not line_args:

            print(f'{total_words:8} total')

        if character_args and line_args and not word_args:

            print(f'{total_byte:8}{total_line:8} total') 

        if character_args and word_args and not line_args:

            print(f'{total_byte:8}{total_words:8} total')

        if line_args and word_args and not character_args:

            print(f'{total_line:8}{total_words:8} total')

        if line_args and word_args and character_args:

            print(f'{total_line:8}{total_words:8}{total_byte:8} total')

        if not line_args and not word_args and not character_args:

            print(f'{total_line:8}{total_words:8}{total_byte:8} total')

# --------------------------------------------------

if name == 'main':

    main()
Có thể thay thế mấy cái if trên bằng 1 cái map. Cái khó là tổ chức cái map sao cho đưa key (arguments) vào nó ra giá trị tương ứng. Code phức tạp hơn cách hiện tại.
 
Có thể thay thế mấy cái if trên bằng 1 cái map. Cái khó là tổ chức cái map sao cho đưa key (arguments) vào nó ra giá trị tương ứng. Code phức tạp hơn cách hiện tại.

Cùng ý tưởng với anh này lập ra cái map rồi bỏ mấy cái lambda vào value sau đó lúc xài thì get cái key ra rồi call cái function trong value thôi nhưng có vẻ phức tạp hơn cái đống if này.

Sent from Headmaster's room, Hogwarts School of Witchcraft and Wizardry using vozFApp
 
Chào các bác,

E có đoạn code sau mô phỏng lệnh wc trong linux, mặc định là in ra số dòng, từ, ký tự từ file, nếu nhiều file thì in tương tự từng file một, và chốt là tổng dòng, từ, ký tự.

Tùy theo option truyền vào mà chỉ in ra tương ứng giá trị , ví dụ nếu đưa -w vào thì chỉ in số ký tự, -wc thì chỉ in số từ và ký tự.

Code hiện giờ nhiều if quá, nhìn rối rắm nhưng e ko biết làm sao để rút bớt xuống. Nhờ các bác gợi ý ạ.

Python:
#!/usr/bin/env python

import sys

import argparse

# --------------------------------------------------

def get_args():

    parser = argparse.ArgumentParser(

        description='Emulate wordcount',

        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('file', nargs="*",

                        metavar='FILE',type=argparse.FileType('rt'),default=[sys.stdin],

                        help='Input files(s)')

    parser.add_argument('-c', '--character', help='number of characters', action='store_true')

    parser.add_argument('-l', '--line',help='number of lines',action='store_true')

    parser.add_argument('-w', '--word', help='number of words',action='store_true')

    return parser.parse_args()

# --------------------------------------------------

def main():

    args = get_args()

    file_arg = args.file

    #get each argument

    character_args = args.character

    line_args = args.line

    word_args = args.word

    total_line, total_words, total_byte = 0, 0, 0

    for fh in file_arg:

        line_count, words_count, byte_count = 0, 0, 0

        for line in fh:

            line_count += 1

            byte_count += len(line)

            words_count += len(line.split())

            total_line += 1

            total_words += len(line.split())

            total_byte += len(line)

        if character_args and not line_args and not word_args:

            print(f'{byte_count:8} {fh.name}')

        if line_args and not character_args and not word_args:

            print(f'{line_count:8} {fh.name}')

        if word_args and not character_args and not line_args:

            print(f'{words_count:8} {fh.name}')

        if character_args and line_args and not word_args:

            print(f'{byte_count:8}{line_count:8} {fh.name}') 

        if character_args and word_args and not line_args:

            print(f'{byte_count:8}{words_count:8} {fh.name}')

        if line_args and word_args and not character_args:

            print(f'{line_count:8}{words_count:8} {fh.name}')

        if line_args and word_args and character_args:

            print(f'{line_count:8}{words_count:8}{byte_count:8} {fh.name}')

        if not line_args and not word_args and not character_args:

            print(f'{line_count:8}{words_count:8}{byte_count:8} {fh.name}')

    if len(file_arg) > 1:

        if character_args and not line_args and not word_args:

            print(f'{total_byte:8} total')

        if line_args and not character_args and not word_args:

            print(f'{total_line:8} total')

        if word_args and not character_args and not line_args:

            print(f'{total_words:8} total')

        if character_args and line_args and not word_args:

            print(f'{total_byte:8}{total_line:8} total') 

        if character_args and word_args and not line_args:

            print(f'{total_byte:8}{total_words:8} total')

        if line_args and word_args and not character_args:

            print(f'{total_line:8}{total_words:8} total')

        if line_args and word_args and character_args:

            print(f'{total_line:8}{total_words:8}{total_byte:8} total')

        if not line_args and not word_args and not character_args:

            print(f'{total_line:8}{total_words:8}{total_byte:8} total')

# --------------------------------------------------

if name == 'main':

    main()
dùng đại số bolean. vẽ bảng sự thật rồi suy ra công thức thôi
 
Thớt ko thích if thì đây là phiên bản no-if

Python:
#!/usr/bin/env python

import argparse
import sys
from collections import defaultdict
from enum import Enum


# --------------------------------------------------

class MyNamespace(argparse.Namespace):
    class Stat(Enum):
        line = 'l'
        word = 'w'
        character = 'c'

    @staticmethod
    def get_line(_):
        return 1

    @staticmethod
    def get_word(line):
        return len(line.split())

    @staticmethod
    def get_character(line):
        return len(line)

    def get_stats(self):
        all_false = not any(getattr(self, s.name) for s in self.Stat)
        active_keys = list(filter(lambda item: all_false or getattr(self, item.name), self.Stat))
        stats = defaultdict(lambda: defaultdict(int))
        for file_obj in self.file:
            for line in file_obj:
                for k in active_keys:
                    stats[file_obj.name][k] += getattr(self, f'get_{k.name}')(line)
        return stats


def get_args():
    parser = argparse.ArgumentParser(
        description='Emulate wordcount',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    namespace = MyNamespace()

    parser.add_argument(
        'file',
        nargs="*",
        metavar='FILE',
        type=argparse.FileType('rt'),
        default=[sys.stdin],
        help='Input files(s)',
    )

    for stat in namespace.Stat:
        parser.add_argument(f'-{stat.value}', f'--{stat.name}', help=f'number of {stat.name}s', action='store_true')

    parser.parse_args(namespace=namespace)

    return namespace


# --------------------------------------------------

def print_line(stats):
    print(''.join(['{:<8}' for _ in stats]).format(*stats.values()))


def main():
    args = get_args()
    total = defaultdict(int)
    for file, stats in args.get_stats().items():
        for key in stats:
            total[key] += stats[key]
        stats[file] = file
        print_line(stats)
    len(args.file) == 1 or print_line({**total, '_': 'total'})


# --------------------------------------------------

__name__ == '__main__' and main()
 
trong python có thể sử dụng dictionary như một switch case.
trên code của thớt có chủ yếu 3 yếu tố mỗi điều kiện if và khác nhau ở mỗi điều kiện thì có thể set nó là key:
options ={
"101": lambda ...,
"111": lambda ...,
}
Ví dụ: if true and false and true => key = 101
hoặc true and true and true => key = 111

Cho một ví dụ sử dụng dictionary như một switch case:

1621959838573.png
 
if không quá nhiều thì vẫn thích hơn tại rule nó trực quan dễ hiểu
 
trong python có thể sử dụng dictionary như một switch case.
trên code của thớt có chủ yếu 3 yếu tố mỗi điều kiện if và khác nhau ở mỗi điều kiện thì có thể set nó là key:
options ={
"101": lambda ...,
"111": lambda ...,
}
Ví dụ: if true and false and true => key = 101
hoặc true and true and true => key = 111

Cho một ví dụ sử dụng dictionary như một switch case:

Xem tệp đính kèm 565410
switch case kiểu này khá ngon luôn cũng đỡ phải break giữa các case nựa :D
 
Viết kiểu 1 dòng thế này là nên tránh, thật sự code review là failed ngay. Người ta khuyến khích mổi dòng là 1 lệnh. Giờ debug tới dòng đó biết lỗi ở phần nào?
Đúng rồi, nhìn code có vẻ pro, nhưng thực sự ko thấy có lợi lắm! Nên mình chỉ viết 1 dòng với if else và for if thôi. Còn lại thì bỏ qua.
 

Thống kê chủ đề

Ngày tạo
Nghe Si Chu Van Quyenh,
Người trả lời cuối
kienthuclavohan,
Trả lời
16
Lượt xem
2.554
Quay lại
Lên đầu trang