Соглашения новичка к питону, мой код на правильном пути? - PullRequest
1 голос
/ 01 августа 2009

Я читал о Python уже неделю и просто подумал, что попробую свои силы, создав калькулятор налоговых скобок. Я не закончил, но я хотел знать, нахожусь ли я на правильном пути или нет, насколько далеко идет программирование на Python. Я только немного занимался программированием на C ++, и кажется, что он показывает (хорошо / плохо?)

#There are six brackets define by the IRS as of 2009
#Schedule X - Single
first_bracket = 8350
second_bracket = 33950
third_bracket = 82250
fourth_bracket = 171550
fifth_bracket = 372950

def b1(a):
    a = a * .10
    return a
def b2(a):
    a = a * .15
    return a
def b3(a):
    a = a * .25
    return a
def b4(a):
    a = a * .28
    return a
def b5(a):
    a = a * .33
    return a
def b6(a):
    a = a * .35
    return a

if __name__ == '__main__': #importing is fun

    #Ask for salary
    salary = float(raw_input("Enter your salary\n"))    

    #First bracket
    if salary >= 0 and salary <= first_bracket:
        taxed = b1(salary)
        #print "You make less than $", float(first_bracket), "so your tax is $", taxed
        print taxed

    #Second bracket
    elif salary > first_bracket and salary <= second_bracket:
        taxed = b1(first_bracket) + b2(salary-first_bracket)
        #print "You make between $", first_bracket+1, "and $", second_bracket, "so your tax is $", taxed
        print taxed

    #Thrid bracket  
    elif salary > second_bracket and salary <= third_bracket:
        taxed = b1(first_bracket) + b2(second_bracket-first_bracket) + b3(salary-second_bracket)
        print taxed

Ответы [ 7 ]

13 голосов
/ 01 августа 2009

Вероятно, есть более эффективный способ сделать это, используя списки и пары вместо отдельных переменных для ограничения и скорости каждой скобки. Например, рассмотрим следующее:

# List of (upper-limit, rate) pairs for brackets.
brackets = [ (8350, .10), (33950, .15), (82250, .25), (171550, .28), (372950, .33) ]

if __name__ == '__main__':

    salary = float(raw_input("Enter your salary\n"))

    accounted_for = 0 # Running total of the portion of salary already taxed
    taxed = 0 # Running total of tax from portion of salary already examined

    for (limit, rate) in brackets:
        if salary < limit:
            taxed += ( (salary - accounted_for) * rate )
            accounted_for = salary
            break # We've found the highest tax bracket we need to bother with
        else:
            taxed += ( (limit - accounted_for) * rate )
            accounted_for = limit

    # If we went over the max defined tax bracket, use the final rate
    if accounted_for < salary:
        taxed += ( (salary - accounted_for) * 0.35 )

    print taxed

Идея состоит в том, что мы не хотим повторять код, который нам не нужен, просто потому что у нас есть несколько элементов схожих данных для работы. Налоговые скобки функционируют одинаково, за исключением разных ставок и ограничений, поэтому мы хотим, чтобы они действовали в качестве входных данных для стандартных вычислений, а не для их собственных индивидуальных функций.

5 голосов
/ 01 августа 2009

В частности, при работе с финансовыми значениями следует рассмотреть возможность использования модуля десятичный , чтобы убедиться, что в ваших выходных данных нет ошибок с плавающей запятой.

Ничего страшного, когда вы просто делаете игрушку для изучения языка, но полезно знать об этом в будущем:)

2 голосов
/ 01 августа 2009

Вы можете изменить строки следующим образом:

if salary >= 0 and salary <= first_bracket:

к этому:

if 0 <= salary <= first_bracket:

как и в математике. Обычно это делает код более читабельным.

2 голосов
/ 01 августа 2009

4 пробела! Проверьте это doc и вывод

import this
, чтобы узнать больше. Выглядит довольно хорошо, хотя, очень легко читается.
1 голос
/ 02 августа 2009

Структурирование данных о доходах и ставках налога в виде таблицы (список кортежей или кортежей кортежей) является огромным улучшением. Как показано в этом примере, он позволяет приблизиться к остальной части задачи с помощью табличного подхода (проследуйте вверх по таблице, чтобы найти максимальную ставку для данной заработной платы, затем проследуйте от этой точки, накапливая налоги вниз и учитывая общую зарплату) .

Чтобы сделать все это моим "Pythonic", мы определим функциональность, а также таблицу налоговых ставок над строкой if __name__==. Это неявно позволило бы нам импортировать наш файл в любой другой код и использовать этот функционал.

Часть под строкой if __name__ == является драйвером, который вызывает функциональность с любым данным вводом (или может использоваться для проведения модульных тестов, так что любой модуль может быть вызван для проверки его собственной функциональности).

Так что наш код может выглядеть примерно так:

#!/usr/bin/env python
tax_table = (
(8350, 0.10),
...
)

def compute(salary):
'''Compute taxes for a given salary'''
result = 0
accounted_for = 0
...
return result

if __name__ == "__main__":
import sys
try:
sal = float(raw_input("Please enter salary: ")
except EnvironmentError, err:
print >> sys.stderr, "Error with your input, aborting"
print >> sys.stderr, "The error was:", err
sys.exit(1)
print compute(sal)

Обратите внимание, что теперь мы отделили многократно используемую функциональность от нашего использования ... что позволяет нам повторно использовать код ... но также облегчает разработку и рефакторинг через тестирование. Мы можем написать неинтерактивные тестовые наборы, используя наш тот же API (пока только вызов функции compute () ), и это позволит нам с уверенностью провести рефакторинг (и не затрагивая наше использование ниже --- что является нашим «приложением» в данном случае).

Не ясно, что этот конкретный код выиграл бы от рефакторинга в один или несколько классов. Конечно, была бы полезна возможность создания экземпляра класса с другой таблицей налогов. Тогда налоговая ставка может быть сохранена в другом месте (считано из файла, извлечено с веб-сервера или запрошено из базы данных; Python делает все это почти одинаково легко).

Однако нам не нужно идти «OO», чтобы добавить эту функцию в нашу compute () функцию.

Мы могли бы добавить необязательный параметр к функции вычисления, чтобы он использовал другую таблицу налоговых ставок, если мы ее предоставили, или по умолчанию ту, которую мы жестко запрограммировали в модуле. Для этого мы просто изменим начальную строку определения функции на: def compute(salary, table=tax_table): ... и исправим некоторую обработку для верхнего предела (с учетом коэффициента 0,35 из функции и в таблицу, используя либо «sys.maxint», как наш лимит или объект "Нет").

За такое простое упражнение не стоит сильно волноваться. Но в целом лучше приложить значительные усилия для определения желаемых API заранее. Если вы можете создать надежный и гибкий API, то любая соответствующая реализация, которая соответствует вашим начальным требованиям (правильность и приемлемая производительность), позволит вам доставить ваше приложение.

Что еще важнее, вы можете заново реализовать его по своему желанию. Возможно, нужно искать действительно сложную таблицу налогов, используя что-то вроде модуля bisect , потому что линейный поиск занимает слишком много времени, чтобы найти максимальную ставку налога, или требуются некоторые виды налоговых льгот и вычетов или количества иждивенцев для передачи в функцию compute () и т. д. В идеале такие изменения могут быть сделаны прозрачно. Ни одно из ваших существующих применений не должно измениться, потому что вы повторно внедрили внутренние компоненты нашего модуля. Даже когда вы добавили функциональность, вам не нужно беспокоиться о существующем использовании (необязательные параметры и аргументы «ключевого слова» (словари, передаваемые после необязательных аргументов), давайте сделаем это для функций, а классы могут добавлять атрибуты и методы без помех любое правильное существующее использование. (Да, возможно, использование подклассов может быть нарушено некоторыми изменениями; но обычно это не должно быть проблемой).

В Python можно написать что-то в виде простого модуля Python, а затем повторно реализовать его как пакет или повторно реализовать его как скомпилированный модуль C или как пакет, содержащий несколько модулей C ... и все это без влияния на использование. С точки зрения пользователя оператор import работает одинаково на модулях, пакетах и ​​скомпилированных модулях Python («общих объектах» или DLL).

Исторически это было огромным преимуществом для Python в его собственной разработке. Они смогли добавить значительную функциональность к существующим библиотекам, и лишь в редких случаях их заставляли использовать искажения «отменить / переименовать». По этой причине в Python 2.7 можно было добавить довольно много функций, запланированных для Python 3.0.

1 голос
/ 01 августа 2009

Поскольку эти функции довольно просты, вы можете сделать что-то вроде:

def b1(a):
    return a * .10

Вы также можете сделать одну единую функцию налогообложения:

def tax_me(salary, rate):
    return salary * rate

Похоже, что Дэв исправился довольно хорошо:)

Веселитесь с Python, это отличный язык.

0 голосов
/ 01 августа 2009

Такие инструменты, как PyLint , могут улавливать множество ошибок и неправильных действий, в том числе соглашения об именах. PyChecker тоже хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...