Unused variable python как исправить

Ответили на вопрос 1 человек. Оцените лучшие ответы! И подпишитесь на вопрос, чтобы узнавать о появлении новых ответов.

Пишу код вроде правильно но, выдает ошибку:
Unused variable ‘callback_worker’
Вот код:

import telebot
bot1 = telebot.TeleBot ('token')
name = ''
surname = ''
age = 0
from telebot import types
@bot1.message_handler(content_types=['text'])
def start(message):
    if message.text == '/reg':
        bot1.send_message(message.from_user.id, "Как тебя зовут?")
        bot1.register_next_step_handler(message, get_name) #следующий шаг – функция get_name
    else:
        bot1.send_message(message.from_user.id, 'Напиши /reg')

def get_name(message): #получаем фамилию
    global name
    name = message.text
    bot1.send_message(message.from_user.id, 'Какая у тебя фамилия?')
    bot1.register_next_step_handler(message, get_surname)

def get_surname(message):
    global surname
    surname = message.text
    bot1.send_message(message.from_user.id,'Сколько тебе лет?')
    bot1.register_next_step_handler(message, get_age)

def get_age(message):
 global age
 while age == 0: #проверяем что возраст изменился
   try:
    age = int(message.text) #проверяем, что возраст введен корректно
   except Exception:
             bot1.send_message(message.from_user.id, 'Цифрами, пожалуйста')
             keyboard = types.InlineKeyboardMarkup() #наша клавиатура
             key_yes = types.InlineKeyboardButton(text='Да', callback_data='yes') #кнопка «Да»
             keyboard.add(key_yes) #добавляем кнопку в клавиатуру
             key_no= types.InlineKeyboardButton(text='Нет', callback_data='no')
             keyboard.add(key_no)
             question = ('Тебе '+str(age)+' лет, тебя зовут '+name+' '+surname+'?')
             bot1.send_message(message.from_user.id, text=question, reply_markup=keyboard)
             @bot1.callback_query_handler(func=lambda call: True)
             def callback_worker(call):
                if call.data == "yes": #call.data это callback_data, которую мы указали при объявлении кнопки
                 ... #код сохранения данных, или их обработки
                 bot1.send_message(call.message.chat.id, 'Запомню : )')
                elif call.data == "no":
                 ... #переспрашиваем

A variable defined inside a function block or a looping block loses its scope outside that block is called ad local variable to that block.  A local variable cannot be accessed outside the block it is defined.

Example:

Python3

def func(num):

    a = num

    print("The number is :", str(a))

func(10)

print(a)

Output:

NameError: name 'a' is not defined

Here we get an error because ‘a’ is local to the function func() and it loses its scope outside that block. Here the local variable ‘a’ is used to hold the number passed and it is utilized in the printing statement. But in some cases, the local variables wl be declared by assigning some value and left utilized for any process. Just assigning some value is not utilizing the variable, the value in it must be read and used for some computation. 

Garbage collection is automatic in Python and when the reference count of an object comes to zero the object will be cleared. We all know that a variable local to a certain block of code loses its scope outside the block. The garbage collection is automatically invoked when the difference between the allocation of objects and the deallocation of objects crosses a certain threshold value. If the script is a few lines of code, then memory management is not a tedious process. If the script is very long with complex tasks and there are many unused local variables, it has a considerable effect on the code execution time and memory management. However, issues with memory management are very less.

The main issue that arises due to these unused variables is it decreases readability. When the code is thousands of lines, when another programmer is required to work with it, he may have to spend a long time analyzing what for the variable is used which is actually left unused. One may forget the unused variable declared and may use it in the later part which can result in undesirable output. It is always good practice to remove the unused local variables.

A code with many unused local variables, unused imports, or unused line of codes is considered to be dead code. When there are situations where you are ambiguous that a local variable may have a role later in the code, then there are some naming conventions that can be used to distinguish it from the rest of the variables. Naming the variable as ‘dummy’, ‘unused’ or any name that conveys that this variable is currently not used anywhere.

How to suppress the warning ‘unused variable’?

Some editors like VScode, PyCharm, Eclipse, PyDev will raise warnings sometimes regarding these unused variables. The warnings won’t interrupt the program execution. To suppress the warning, one can simply name the variable with an underscore (‘_‘) alone. Python treats it as an unused variable and ignores it without giving the warning message.

Python

def my_func():

    _ = 5

    b=2

    c=b+10

    print(b,c)

for i in range(0, 5):

    print(i)

Vulture package

There are packages that can be used to find the dead code in the scripts. One such package is Vulture. The vulture package finds the unused local variables, unused imports, and unused cord parts and gives out the report. To install this package, type the following command in the anaconda prompt.

pip install vulture

Now type a python script and save it with .py extension. The file shall be stored either in the directory that opens by default in the anaconda prompt or in some specific location. In case of storing the file in some other location, one has to then move to that directory.  Now consider the following script as an example. It is saved as trial1.py

Python

def my_func():

    a = 5

    b=2

    c=b+10

    print(b,c)

for i in range(0, 5):

    print(i)

Once the file is saved in the desired directory, then type the following command in the anaconda prompt to find the dead code.

C:user>>vulture trial1.py

Output:

The vulture package understands the naming convention explained below to avoid warning. Thus, when an underscore alone is used as a variable name, the warning message is suppressed.  Consider the trial1.py, where the name of the unused local variable is changed to underscore(‘_’).

Python3

def my_func():

    _ = 5

    b=2

    c=b+10

    print(b,c)

for i in range(0, 5):

    print(i)

somik159478

-1 / 1 / 0

Регистрация: 29.12.2016

Сообщений: 51

1

14.11.2019, 08:42. Показов 3887. Ответов 4

Метки нет (Все метки)


Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import socket
 
def main():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    s.bind(("127.0.0.1", 24000))
    s.listen(1)
    conn, addr = s.accept()
    data = conn.recv(1024,socket.MSG_WAITALL)
    print(data)
    s.close
 
    if __name__ == '__main__':
        main()

а вот и ошибка:
{
«resource»: «/d:/Phyton/TestTcpReceiver.py»,
«owner»: «python»,
«code»: «unused-variable»,
«severity»: 4,
«message»: «Unused variable ‘addr'»,
«source»: «pylint»,
«startLineNumber»: 7,
«startColumn»: 11,
«endLineNumber»: 7,
«endColumn»: 11
}

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Автоматизируй это!

Эксперт Python

6481 / 4174 / 1140

Регистрация: 30.03.2015

Сообщений: 12,325

Записей в блоге: 29

14.11.2019, 08:49

2

Цитата
Сообщение от somik159478
Посмотреть сообщение

Unused variable ‘addr’

перевести за тебя?



0



-1 / 1 / 0

Регистрация: 29.12.2016

Сообщений: 51

14.11.2019, 08:51

 [ТС]

3

Спасибо, это очень мило, я бы никогда не догадался, как исправить? Версия питона такая же как и в учебнике…



0



Автоматизируй это!

Эксперт Python

6481 / 4174 / 1140

Регистрация: 30.03.2015

Сообщений: 12,325

Записей в блоге: 29

14.11.2019, 09:00

4

somik159478, откуда вообще такая ошибка? может вырубить пилинт(это его проверка)?
вариант решения, вместо аддр назвать переменную _ (нижнее подчеркивание -распространенный вариант для неиспользуемых переменных). Второй вариант — получать тапл, не распаковывая на конн и аддр, потом recv вызывать на тапл[0]



0



1302 / 842 / 409

Регистрация: 12.03.2018

Сообщений: 2,305

14.11.2019, 09:29

5

Это точно ошибка, а не предупреждение?



0



Author:
Thomas Wouters <thomas at python.org>
Status:
Rejected
Type:
Standards Track
Created:
04-Oct-2020
Python-Version:
3.10
Post-History:
19-Oct-2020
Resolution:
Python-Dev message

Table of Contents

  • Rejection Note
  • Abstract
  • Motivation
  • Rationale
  • Specification
  • Backwards Compatibility
  • How to Teach This
  • Reference Implementation
  • Rejected Ideas
  • Open Issues
  • Copyright

Rejection Note

Rejected by the Steering Council:
https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/

Abstract

This PEP proposes new syntax for unused variables, providing a pseudo-name
that can be assigned to but not otherwise used. The assignment doesn’t
actually happen, and the value is discarded instead.

Motivation

In Python it is somewhat common to need to do an assignment without actually
needing the result. Conventionally, people use either "_" or a name such
as "unused" (or with "unused" as a prefix) for this. It’s most
common in unpacking assignments:

x, unused, z = range(3)
x, *unused, z = range(10)

It’s also used in for loops and comprehensions:

for unused in range(10): ...
[ SpamObject() for unused in range(10) ]

The use of "_" in these cases is probably the most common, but it
potentially conflicts with the use of "_" in internationalization, where
a call like gettext.gettext() is bound to "_" and used to mark strings
for translation.

In the proposal to add Pattern Matching to Python (originally PEP 622, now
split into PEP 634, PEP 635 and PEP 636), "_" has an additional
special meaning. It is a wildcard pattern, used in places where variables
could be assigned to, to indicate anything should be matched but not
assigned to anything. The choice of "_" there matches the use of "_"
in other languages, but the semantic difference with "_" elsewhere in
Python is significant.

This PEP proposes to allow a special token, "?", to be used instead of
any valid name in assignment. This has most of the benefits of "_"
without affecting other uses of that otherwise regular variable. Allowing
the use of the same wildcard pattern would make pattern matching and
unpacking assignment more consistent with each other.

Rationale

Marking certain variables as unused is a useful tool, as it helps clarity of
purpose of the code. It makes it obvious to readers of the code as well as
automated linters, that a particular variable is intentionally unused.

However, despite the convention, "_" is not a special variable. The
value is still assigned to, the object it refers to is still kept alive
until the end of the scope, and it can still be used. Nor is the use of
"_" for unused variables entirely ubiquitous, since it conflicts with
conventional internationalization, it isn’t obvious that it is a regular
variable, and it isn’t as obviously unused like a variable named
"unused".

In the Pattern Matching proposal, the use of "_" for wildcard patterns
side-steps the problems of "_" for unused variables by virtue of it
being in a separate scope. The only conflict it has with
internationalization is one of potential confusion, it will not actually
interact with uses of a global variable called "_". However, the
special-casing of "_" for this wildcard pattern purpose is still
problematic: the different semantics and meaning of "_" inside pattern
matching and outside of it means a break in consistency in Python.

Introducing "?" as special syntax for unused variables both inside and
outside pattern matching
allows us to retain that consistency. It avoids
the conflict with internationalization or any other uses of _ as a
variable
. It makes unpacking assignment align more closely with pattern
matching, making it easier to explain pattern matching as an extension of
unpacking assignment.

In terms of code readability, using a special token makes it easier to find
out what it means ("what does question mark in Python do" versus "why
is my _ variable not getting assigned to"
), and makes it more obvious that
the actual intent is for the value to be unused – since it is entirely
impossible to use it.

Specification

A new token is introduced, "?", or token.QMARK.

The grammar is modified to allow "?" in assignment contexts
(star_atom and t_atom in the current grammar), creating a Name
AST node with identifier set to NULL.

The AST is modified to allow the Name expression’s identifier to be
optional (it is currently required). The identifier being empty would only
be allowed in a STORE context.

In CPython, the bytecode compiler is modified to emit POP_TOP instead of
STORE_NAME for Name nodes with no identifier. Other uses of the
Name node are updated to handle the identifier being empty, as
appropriate.

The uses of the modified grammar nodes encompass at least the following
forms of assignment:

? = ...
x, ?, z = ...
x, *?, z = ...
for ? in range(3): ...  # including comprehension forms
for x, ?, z in matrix: ...  # including comprehension forms
with open(f) as ?: ...
with func() as (x, ?, z): ...

The use of a single "?", not in an unpacking context, is allowed in
normal assignment and the with statement. It doesn’t really make sense
on its own, and it is possible to disallow those specific cases. However,
for ? in range(3) clearly has its uses, so for consistency reasons if
nothing else it seems more sensible to allow the use of the single "?"
in other cases.

Using "?" in augmented assignment (? *= 2) is not allowed, since
"?" can only be used for assignment. Having multiple occurrences of
"?" is valid, just like when assigning to names, and the assignments do
not interfere with each other.

Backwards Compatibility

Introducing a new token means there are no backward compatibility concerns.
No valid syntax changes meaning.

"?" is not considered an identifier, so str.isidentifier() does not
change.

The AST does change in an incompatible way, as the identifier of a Name
token can now be empty. Code using the AST will have to be adjusted
accordingly.

How to Teach This

"?" can be introduced along with unpacking assignment, explaining it is
special syntax for ‘unused’ and mentioning that it can also be used in other
places. Alternatively, it could be introduced as part of an explanation on
assignment in for loops, showing an example where the loop variable is
unused.

PEP 636 discusses how to teach "_", and can simply replace "_" with
"?", perhaps noting that "?" is similarly usable in other contexts.

Reference Implementation

A prototype implementation exists at
<https://github.com/Yhg1s/cpython/tree/nonassign>.

Rejected Ideas

Open Issues

Should "?" be allowed in the following contexts:

# imports done for side-effect only.
import os as ?
from os import path as ?

# Function defined for side-effects only (e.g. decorators)
@register_my_func
def ?(...): ...

# Class defined for side-effects only (e.g. decorators, __init_subclass__)
class ?(...): ...

# Parameters defined for unused positional-only arguments:
def f(a, ?, ?): ...
lambda a, ?, ?: ...

# Unused variables with type annotations:
?: int = f()

# Exception handling:
try: ...
except Exception as ?: ...

# With blocks:
with open(f) as ?: ...

Some of these may seem to make sense from a consistency point of view, but
practical uses are limited and dubious. Type annotations on "?" and
using it with except and with do not seem to make any sense. In the
reference implementation, except is not supported (the existing syntax
only allows a name) but with is (by virtue of the existing syntax
supporting unpacking assignment).

Should this PEP be accepted even if pattern matching is rejected?

Copyright

This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.

#База знаний

  • 25 май 2021

  • 15

Чтобы код оставался понятным, в нём регулярно надо убираться. Рассказываем, что и где прибирать.

Марина Демидова

Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.

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

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

Важно! Рефакторинг более эффективен и безопасен, когда пошаговые изменения проверяются запусками тестов.

Если вы только-только столкнулись с рефакторингом — сперва прочтите эту статью.

В языке Python есть много приёмов улучшения кода. Однако перед тем, как применять более сложные, нужно почистить код от накопившегося мусора.

Удаляйте закомментированные куски кода. Они сбивают с толку разработчиков, которые работают с исходниками после вас.

Например, вы попробовали вариант решения задачи, но потом решили сделать всё по-другому. Промежуточные куски кода вы закомментировали — а вдруг пригодятся. Не стоит так делать. Если понадобится, лучше посмотреть предыдущую версию кода в системе контроля версий.

Это тоже мусор. Если они всего лишь помогали вам увидеть промежуточные результаты, то их следует удалить сразу после того, как вы разобрались в работе программы.

Допустим, вы попробовали вариант решения с использованием каких-то модулей, потом пошли по другому пути и модули более не нужны.

Не забудьте удалить из кода соответствующие команды импорта — обычно редакторы их подсвечивают. Так, в IDE PyCharm текст команды становится бледным и при компиляции выдаётся предупреждение «Unused import statement…».

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

Найти эти переменные легко — редакторы их подсвечивают, а при компиляции выдаётся предупреждение: «Variable is not used».

Например:

Здесь PyCharm выделяет серым и ненужный модуль os, и неиспользуемые переменные unused1 и unused2.

Проводя рефакторинг, важно оформить код так, чтобы его было удобно читать.

Создатель языка Python Гвидо ван Россум сказал: «Код читают гораздо чаще, чем пишут».

Действительно, вы написали кусок кода за раз, но, когда он станет частью проекта, его придётся перечитывать снова и снова — вспоминая, что он делает и почему так написан. Это придётся делать не только вам, но и вашим коллегам. Поэтому важно сделать код удобочитаемым — для всех.

Гвидо ван Россум считал удобочитаемость одним из важнейших принципов языка Python. Поэтому вместе с соратниками разработал свод рекомендаций по оформлению кода — PEP 8. Рассмотрим некоторые из них подробнее.

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

Например, имя переменной в выражении sc += 1 нам мало о чём говорит.

А если изменить его на score, то станет ясно, что речь идёт о счёте.

Есть два важнейших правила именования сущностей в Python — их нарушение вызывает ошибку:

  • имена могут состоять только из цифр, букв и знаков подчёркивания;
  • имя не может начинаться с цифры.

PEP 8 предписывает задавать имена определённым образом:

  • Имена функций и модулей пишутся строчными буквами. Они могут состоять из одного или нескольких слов, которые разделяются подчёркиванием (например: function, my_function).
  • Имена переменных тоже задаются в нижнем регистре. Они могут состоять из одной буквы, слова или нескольких слов. Слова в составе имени тоже разделяются подчёркиванием: x, variable, my_var.
  • Название константы задаётся символом, словом или несколькими словами в верхнем регистре. Слова в составе имени разделяются знаком подчёркивания.

    Например:

    C, CONST, MY_CONST.

  • Имена классов состоят из одного (Class) или нескольких слов (MyClass) без разделителей.

    Во втором случае, как вы заметили, каждое слово начинается с прописной буквы. Такой стиль называется CamelCase («верблюжий стиль»).

  • Имена модулей задаются в нижнем регистре. Они не должны быть длинными. Знак подчёркивания уместен, если с ним имя модуля читабельнее, а его назначение понятнее.

    Например:

    pyclbr, py_compile.

    PEP 8 описывает и принципы оформления кода:

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

    Обнаружить ошибки форматирования помогают специальные программы — линтеры. Они анализируют код и выдают предупреждения, например:

    Здесь линтер flake8 в PyCham выдаёт предупреждения о лишних пробелах внутри скобок и перед ними.

    Для разных языков программирования есть свои линтеры. Например, для HTML — Beautify, для JavaScript — JSLint и так далее.

    Популярные линтеры для Python:

    • Pycodestyle,
    • Pyflakes,
    • Pylint,
    • Flake8.

    Все они легко интегрируются в среды разработки. А самым умным считается pylint. Он проверяет:

    • все ли подключённые модули используются в программе;
    • есть ли лишние переменные;
    • не превышает ли длина строк 79 символов;
    • правильно ли заданы имена;
    • верно ли используются аргументы;
    • есть ли синтаксические ошибки;
    • как используются типы данных
    • и многое другое.

    Обнаруженные ошибки можно исправить вручную или с помощью утилит для форматирования кода — форматтеров, которые совместимы с IDE PyCharm или Visual Studio.

    Популярные форматтеры:

    • Autopep8,
    • YAPF,
    • Black.

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

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

    А ещё повторами часто грешат начинающие программисты. Они видят в проекте почти такой же код, как нужен им, и копируют его в другое место, немного изменив. Это приводит к проблемам:

    • Возникают куски одинакового текста, различающиеся лишь некоторыми строками или символами — и не сразу понятно какими. Это затрудняет понимание программы.
    • Текст программы раздувается, в нём труднее разобраться.
    • Когда нужно менять функциональность, за которую отвечает дублирующийся код, изменения приходится вносить сразу во много мест программы. Это чревато ошибками.

    Чтобы избавиться от дублирования, применяют приём рефакторинга «извлечение метода»: дублирующийся участок выносят в отдельный метод или функцию и везде заменяют вызовом этого метода/функции.

    Рассмотрим на примере:

    while True :
     a1 = int(input( "Введите цену товара: "))
     if a1 < 0 :
       print ("Значение не должно быть отрицательным!")
     else :
       break
    
    while True :
     a2 = int(input("Введите количество товара: "))
     if a2 < 0 :
       print ("Значение не должно быть отрицательным!")
     else :
       break
    
    a3 = a1 * a2
    print("Стоимость товара: ", a3)

    Этот код явно нуждается в рефакторинге. И вот почему:

    • два блока выполняют практически одинаковые действия;
    • названия переменных a1, a2, a3 не говорят об их предназначении.

    Мы видим в коде два блока, которые отличаются только сообщениями пользователю: «Введите цену товара: » и «Введите количество товара: ».

    Такое дублирование — это плохо:

    • Например, поменялись бизнес-правила: нас больше не интересуют товары с нулевой стоимостью. И нужно поставить условие: количество и цена должны быть больше нуля. Нам придётся вносить изменения в оба блока кода.
    • Или мы захотим, скажем, добавить в расчёт стоимости скидку/наценку. Тогда нам придётся создать ещё один похожий блок с новым сообщением: «Введите процент скидки (или наценки) на товар: ». А потом ещё один и ещё. Код быстро разрастётся.

    Чтобы упростить код, преобразуем цикл while в функцию, а сообщения для пользователя будем передавать в неё как аргументы. Назовём функцию input_value() («ввод значения»), добавим в неё команду return a1 и уберём break.

    Вот что у нас выйдет:

    def input_value() :
      while True :
         a1 = int (input("Введите цену товара: "))
         if a1 < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return a1

    Чтобы сообщать пользователю, что вводить (цену, количество товара и так далее), вместо приглашения «Введите цену товара: » добавим параметр функции и назовём его prompt («подсказка»).

    Вот что получится:

    def input_value(prompt):
      while True:
         a1 = int(input(prompt))
         if a1 < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return a1

    Теперь заменим одинаковые блоки кода вызовами функции с соответствующими значениями параметра. Сразу же дадим переменным новые, осмысленные имена: value, price, quantity, cost.

    Исправленный код будет выглядеть так:

    def input_value(prompt):
      while True:
         value = int( input( prompt ) )
         if value < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return value
    
    price = input_value("Введите цену товара: ")
    quantity = input_value("Введите количество товара: ")
    cost = price * quantity
    print("Стоимость товара: ", cost)

    Переменная cost не используется в дальнейших вычислениях: она всего лишь хранит результат подсчёта стоимости товара для передачи его в качестве аргумента функции print().

    Поэтому переменную cost можно смело убирать, а в print () передавать выражение price * quantity. Это сократит код, улучшит читабельность и уменьшит используемые ресурсы:

    def input_value(prompt):
      while True:
         value = int( input( prompt ) )
         if value < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return value
    
    price = input_value ("Введите цену товара: ")
    quantity = input_value ("Введите количество товара: ")
    print ("Стоимость товара: ", price * quantity)

    Важно! Иногда временные переменные вовсе не бесполезны. Например, когда они служат для кэширования — хранят результат затратной, ресурсоёмкой или длительной операции, который при работе программы используется несколько раз.

    Проверьте, что переменная, которую вы собираетесь удалить, не из таких.

    В результате рефакторинга:

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

    Программа стала короче, нагляднее и вдобавок универсальнее. Например, теперь легко добавить скидку в расчёт стоимости товара:

    def input_value(prompt):
      while True:
         value = int( input( prompt ) )
         if value < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return value
    
    price = input_value ("Введите цену товара: ")
    quantity = input_value ("Введите количество товара: ")
    discount = input_value ("Введите процент скидки: ")
    print ("Стоимость товара: ", price * quantity * (1 - discount/100))

    Рефакторинг не ограничивается чисткой кода и улучшением его структуры. Python — язык гибкий, одну и ту же операцию позволяет реализовать по-разному.

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

    Рассмотрим несколько простых приёмов рефакторинга, которые позволяют уменьшить объём кода.

    Для создания списков, словарей и множеств в языке Python часто применяют генераторы. Один из практикуемых приёмов рефакторинга — заменить таким генератором цикл for. Код сокращается, становится нагляднее, к тому же работает быстрее.

    Пример первый

    Есть список из нескольких чисел. Нам нужно получить список квадратов этих чисел.

    Реализация с использованием цикла:

    spisok = [1, 25, 44, 213, 14, 27, 56, 8]
    square_spisok = []
    for item in spisok:
       square_spisok.append(item**2)
    print(square_spisok)
    
    --OUTPUT>
    [1, 625, 1936, 45369, 196, 729, 3136, 64]
    

    После рефакторинга с переходом к генератору:

    spisok = [1, 25, 44, 213, 14, 27, 56, 8]
    square_spisok = [item**2 for item in spisok]
    print(square_spisok)
    
    --OUTPUT>
    [1, 625, 1936, 45369, 196, 729, 3136, 64]
    

    Пример второй

    Вычисление суммы двух матриц. С циклами реализация выглядит так:

    a = [[1, 2, 3], [11,12,13], [21,22,23], [31,32,33]]
    b = [[41, 42, 43], [51,52,53], [61,62,63], [71,72,73]]
    summa_a_b = [[0,0,0], [0,0,0], [0,0,0], [0,0,0]]
    for i in range(len(a)):
       for j in range(len(a[0])):
           summa_a_b[i][j] = a[i][j] + b[i][j]
    
    print(summa_a_b)
    
    --OUTPUT>
    [[42, 44, 46], [62, 64, 66], [82, 84, 86], [102, 104, 106]]
    

    Заменим цикл генератором списка:

    a = [[1, 2, 3], [11,12,13], [21,22,23], [31,32,33]]
    b = [[41, 42, 43], [51,52,53], [61,62,63], [71,72,73]]
    summa_a_b = [[a[i][j] + b[i][j] for j in range(len(a[0]))]
                for i in range(len(a))]
    
    print(summa_a_b)
    
    --OUTPUT>
    [[42, 44, 46], [62, 64, 66], [82, 84, 86], [102, 104, 106]]
    

    После рефакторинга код стал короче.

    Почти в каждой программе приходится совершать операции над всеми элементами контейнерных типов данных: списков, словарей, кортежей.

    Иногда для этого создают переменную-счётчик и с её помощью перебирают элементы в цикле for, например:

    spisok = [154,127,98,89,77,55,32,14]
    for i in range(len(spisok)):
       print(i + 1, spisok[i])
    
    --OUTPUT>
    1 154
    2 127
    3 98
    4 89
    5 77
    6 55
    7 32
    8 14
    

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

    Можно улучшить код — использовать функцию enumerate(), которая перебирает элементы контейнера без промежуточной переменной. У этой функции два аргумента: переменная контейнерного типа (spisok) и начальное значение счёта (переменная i). Зададим второму аргументу значение 1, чтобы счёт начинался с единицы.

    После рефакторинга код будет выглядеть так:

    spisok = [154,127,98,89,77]
    for i, spisok in enumerate(spisok, 1):
       print(i, spisok)
    
    --OUTPUT>
    1 154
    2 127
    3 98
    4 89
    5 77
    

    Если переменная принимает разные значения в зависимости от того, выполняется или нет какое-то условие, то условный оператор if…else можно заменить тернарным выражением.

    Рассмотрим пример:

    def even_odd(number):
       if number % 2 == 0:
           state = "Even"
       else:
           state = "Odd"
       return state
    print(even_odd(128))

    Заменим условие тернарным выражением:

    def even_odd(number):
       return "Even" if number % 2 == 0 else "Odd"

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

    Например:

    def f_if_else(x,y):
       if (x==1):
           if(y==2):
               return 1
           else:
               return 2
       else:
           if(y==3):
                return 3
           else:
                return 4

    Если в функции выше заменить условное выражение тернарным оператором, то в результате получим:

    def f_nested_if_else(x,y):
       return ((1) if (y == 2) else (2)) if (x == 1) else ((3) if (y == 3) else (4))

    Код стал короче, но разобраться в нём теперь намного сложнее.

    Присвоить значение сразу нескольким переменным в Python можно одной строкой.

    Пользоваться этой возможностью надо аккуратно — не усложнять понимание программы. Чтобы не запутаться, в одну строку объявляют переменные, которые связаны по смыслу.

    Пример первый

    name1 = 'Аня'
    name2 = 'Катя'
    name3 = 'Антон'
    name4 = 'Света'

    Эти переменные можно объявить в одной строке. И код станет короче:

    name1,name2,name3,name4 = 'Аня', 'Катя', 'Антон', 'Света'
    
    

    Пример второй

    Иногда переменным нужно присвоить диапазон значений:

    one = 1
    two = 2
    three = 3
    four = 4
    print(' one is',one,'n', 'two is', two, 'n', 'three is', three, 'n', 'four is', four)
    
    --OUTPUT>
    one is 1 
    two is 2 
    three is 3 
    four is 4
    

    В этом случае Python позволяет использовать множественное присваивание совместно с функцией range():

    one, two, three, four = range(1,5)
    print(' one is',one,'n', 'two is', two, 'n', 'three is', three, 'n', 'four is', four)

    Предположим, у нас есть два списка: первый — с именами друзей, а второй — это города, где они живут. Нужно объединить элементы списков в словарь вида «имя: город».

    Это можно сделать с помощью цикла for:

    friends = ["Катя", "Лена", "Даша", "Костя", "Дима"]
    cities = ["Москва", "Пенза", "Екатеринбург", "Минск"]
    friends_cities = {}
    for i in range(min(len(friends), len(cities))):
       friends_cities[friends[i]] = cities[i]
    print(friends_cities)
    
    --OUTPUT>
    {'Катя': 'Москва', 'Лена': 'Пенза', 'Даша': 'Екатеринбург', 'Костя': 'Минск'}
    

    Однако в Python встроена функция zip, которая делает то же самое — короче и проще.

    Её аргументами могут быть списки, кортежи, множества и словари. Функция zip возвращает итератор, объединяющий элементы из объектов-источников.

    Например, передадим в zip аргументами строку, список и множество:

    arg1 = 'абвгдеж'
    arg2 = ['1','2','3','4','5']
    arg3 = {'!','@','#','$','%','^'}
    
    zip_obj = zip(arg1, arg2, arg3)
    print(zip_obj)
    
    for i in zip_obj:
       print(i)
    
    --OUTPUT>
    <zip object at 0x000001D228F06BC0>
    ('а', '1', '!')
    ('б', '2', '@')
    ('в', '3', '#')
    ('г', '4', '$')
    ('д', '5', '%')
    

    В результате получим массив кортежей, каждый из которых содержит по одному элементу из каждого аргумента.

    Теперь создадим словарь «имя: город» с использованием zip. Код будет выглядеть так:

    friends = ["Катя", "Лена", "Даша", "Костя", "Дима"]
    cities = ["Москва", "Пенза", "Екатеринбург", "Минск"]
    friends_cities = dict(zip(friends, cities))
    print(friends_cities)
    
    --OUTPUT>
    {'Катя': 'Москва', 'Лена': 'Пенза', 'Даша': 'Екатеринбург', 'Костя': 'Минск'}
    

    Функция zip работает до тех пор, пока не закончатся элементы в самом коротком из итерируемых объектов-аргументов.

    Если нужно ориентироваться на самый длинный список, то используют функцию zip_longest из модуля itertools:

    from itertools import zip_longest
    
    friends = ["Катя", "Лена", "Даша", "Костя", "Дима"]
    cities = ["Москва", "Пенза", "Екатеринбург", "Минск"]
    friends_cities = dict(zip_longest(friends, cities))
    print(friends_cities)
    
    --OUTPUT>
    {'Катя': 'Москва', 'Лена': 'Пенза', 'Даша': 'Екатеринбург', 'Костя': 'Минск', 'Дима': None}
    

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

    Открываем IDE и устанавливаем параметры рефакторинга в настройках редактора (File | Settings | Editor | Code Editing) в разделе Refactorings.

    Если мы выберем режим In modal dialogs (во всплывающих окнах), то при использовании инструментов Extract/Introduce редактирование имён параметров, констант, полей и переменных будет происходить в открывающихся модальных окнах:

    Если же мы предпочтём режим In the editor (в редакторе), то имена параметров, констант, полей и переменных будем редактировать прямо в редакторе:

    Для примера установим In modal dialogs.

    Теперь создадим в окне редактора новый проект (File | New Project) с именем refactorProject. Добавим в него новый файл (File | New | Python File), а назовём его, скажем, refactor.py.

    Разберём извлечение метода в PyCharm на одном из наших примеров:

    while True :
     a1 = int(input( "Введите цену товара: "))
     if a1 < 0 :
       print ("Значение не должно быть отрицательным!")
     else :
       break
    
    while True :
     a2 = int(input("Введите количество товара: "))
     if a2 < 0 :
       print ("Значение не должно быть отрицательным!")
     else :
       break
    
    a3 = a1 * a2
    print("Стоимость товара: ", a3)

    Копируем этот код в окно редактора:

    Выделим первый цикл while и используем инструмент Refactor | Extract/Introduce | Method из главного или контекстного меню (горячие клавиши Ctrl + Alt + M).

    В нужное поле открывшегося окна вводим название функции — input_value ():

    Чтобы добавить параметр функции, выделим подсказку «Введите стоимость товара: » и выберем в главном/контекстном меню инструмент Refactor | Introduce Parameter (Ctrl + Alt + P):

    В появившемся модальном окне введём название параметра — prompt (в переводе с английского — «подсказка»):

    У нас получилось:

    def input_value(prompt):
      while True:
         a1 = int(input(prompt))
         if a1 < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return a1

    Заменим название переменной a1 на value с помощью инструмента рефакторинга «Переименование». Выделим a1 и выберем Refactor | Rename (Shift + F6):

    Дадим новым переменным осмысленные имена: price, quantity, cost.

    Теперь заменим дубли в нашем коде на вызовы функции с соответствующими значениями параметров. Исправленный код будет выглядеть так:

    def input_value(prompt):
      while True:
         value = int( input( prompt ) )
         if value < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return value
    
    price = input_value("Введите цену товара: ")
    quantity = input_value("Введите количество товара: ")
    cost = price * quantity
    print("Стоимость товара: ", cost)

    Как мы помним, переменной cost присваивается результат простого выражения (price * quantity) и больше с ней ничего не делается.

    Поэтому нам можно от неё избавиться — заменить обращения к этой переменной выражением price * quantity. Сделаем это с помощью инструментов рефакторинга.

    Выделим переменную cost и выберем в меню Refactor инструмент Inline («Встраивание») или вызовем его горячими клавишами Ctrl + Alt + N.

    PyCharm определит число вхождений и попросит подтвердить действие:

    Нажимаем OK. Программа убирает выражение, в котором создаётся переменная cost, и везде подставляет вместо неё price * quantity:

    def input_value(prompt):
      while True:
         value = int( input( prompt ) )
         if value < 0 :
             print ("Значение не должно быть отрицательным!")
         else :
             return value
    
    price = input_value ("Введите цену товара: ")
    quantity = input_value ("Введите количество товара: ")
    print ("Стоимость товара: ", price * quantity)

    Чем объёмнее код, тем выгоднее применять инструменты рефакторинга. С ними уборка в коде ускоряется и ошибки сводятся к минимуму.

    Мы рассмотрели лишь несколько приёмов рефакторинга — в Python их намного больше. Будучи быстрыми и несложными, вместе они здорово повышают качество проекта. Главное — проводить рефакторинг регулярно и не забывать затем тестировать приложение.

    Учись бесплатно:
    вебинары по программированию, маркетингу и дизайну.

    Участвовать

    Школа дронов для всех
    Учим программировать беспилотники и управлять ими.

    Узнать больше

    Понравилась статья? Поделить с друзьями:
  • Unturned как изменить вид
  • Untrusted system file c windows system32 opengl32 dll как исправить
  • Untrusted system file c windows system32 normaliz dll как исправить
  • Untrusted system file c program files rockstar games social club libcef dll ошибка
  • Untracked files prevent checkout как исправить