10  Variables

Variables are used to store data in memory during program execution. They hold values that can be manipulated and changed as needed.

In this chapter, you will learn about variables, data types, naming conventions, and scope in Python.

10.1 Assigning Values to Variables

In Python, variables are initialized/created when you assign a value to them. An assignment statement consists of a variable name, an equal sign (=, the assignment operator), and the value to be assigned. For example:

Listing 10.1: Example of a variable assignment in Python. The variables counter, max_temperature, msg, and is_raining are assigned an integer, float, string, and boolean value, respectively.
counter = 0
max_temperature = 25.5
msg = "Hello, World!"
is_raining = True

In Listing 10.1, three assignment statements are shown. In each statement, a value is assigned to a variable. The variable name is on the left side of the assignment operator (=), and the value to be assigned is on the right side. The variable name can be any valid identifier (a name that follows the rules for naming variables in Python).

Internally, the variable names are references to memory locations where the values are stored. You can think of a variable as a label or name that points to a specific location in memory where the value is stored.

Unlike some other languages, in Python you do not need to declare the variable type explicitly; Python is dynamically typed (i.e., the type of a variable is inferred from the value assigned to it). This means you can assign a value of any type to a variable, and Python will automatically determine the type. Therefore, in Listing 10.1, the variable counter is assigned an integer value, so it is inferred to be of type int, the variable max_temperature is assigned a floating-point value, so it is inferred to be of type float, and so on.

10.2 Literals

The values assigned to variables are called literals. A literal is a fixed value (i.e., not a variable) that is directly written in the code. For example, in Listing 10.1, 0, 25.5, and "Hello, World!" are literals. Literals can be of different types, such as integers, floating-point numbers, strings, and more.

10.3 Expressions

An expression is a combination of values, variables, and operators that evaluates to a single value. For example, in Listing 10.2, the expression current_capacity / max_capacity * 100 will be evaluated to a single value before being assigned to the variable occupation_rate. First, the division current_capacity / max_capacity is performed, and then the result is multiplied by 100.

Listing 10.2: Example of an expression in Python. The expression current_capacity / max_capacity * 100 calculates the occupation rate as a percentage based on the current and maximum capacity.
max_capacity = 100
current_capacity = 75
occupation_rate = current_capacity / max_capacity * 100

10.4 Is x equal to x + 1?

Unlike in mathematics, where x = x + 1 is a contradiction, in programming, x = x + 1 is a valid assignment statement.

When you write x = x + 1 in a programming language, you are not stating that x is equal to x + 1. Instead, you are updating the value of x by adding 1 to its current value.

For example:

x = 5
x = x + 1
print(x)  # Output: 6

In this code snippet, the following steps occur:

  1. The value 5 is assigned to the variable x.
  2. The expression x + 1 is evaluated.
    1. The current value of x is 5.
    2. 5 + 1 is 6.
  3. The result 6 is assigned back to the variable x.
  4. The value of x is printed, which is 6.
Figure 10.1: Is x equal to x + 1? In programming, x = x + 1 is a valid assignment statement that updates the value of x by adding 1 to its current value.

10.5 Overwriting Variables

You can change the value of a variable by assigning a new value to it. The new value can be of the same type or a different type. For example, in Listing 10.3, the variable value is first assigned the integer value 10. Then, it is reassigned the string value "Hello". The variable value is overwritten with a new value of a different type.

Listing 10.3: Example of overwriting a variable in Python. The variable value is first assigned the integer value 10, and then it is reassigned the string value "Hello".
value = 10
value = "Hello"

10.6 Swapping Variable Values

In programming languages it is common to swap the values of two variables. For example, in some applications, you may need to swap the values of two variables to rearrange data or perform certain operations. In Listing 10.4, we present two ways to swap the values of two variables a and b in Python. The first method (Listing 10.4 (a)) uses a temporary variable temp to store the value of a before swapping. This is a typical approach used in many programming languages. The second method (Listing 10.4 (b)) is a more Pythonic way to swap variables without using a temporary variable. This method uses tuple unpacking to swap the values of a and b in a single line.

Listing 10.4: Example of swapping variable values in Python. Upon swapping, a will have the value 10 and b will have the value 5.
(a) Typical variable swap using a temporary variable temp. The values of a and b are swapped by storing the value of a in a temporary variable temp.
a = 5
b = 10

# Swap the values
temp = a
a = b
b = temp
(b) Pythonic way to swap variable values without using a temporary variable. The values of a and b are swapped using tuple unpacking in a single line.
a = 5
b = 10

# Swap the values 
# without a temporary 
# variable
a, b = b, a
Pythonic Code

The term Pythonic refers to code that follows the idiomatic style and best practices of the Python language. Python emphasizes readability and simplicity, and Pythonic code is concise, clear, and easy to understand.

10.7 Naming Conventions

Python has the following naming restrictions for variables:

  • Variable names can only contain letters (a-z, A-Z), digits (0-9), and underscores (_). For example, $total, min value, and total-score are not valid variable names.
  • Variable names cannot start with a digit. For example, 1st_place is not a valid variable name.

To make your code more readable and maintainable, it’s important to follow naming conventions. Here are some common naming conventions in Python:

  • Use snake_case for variable names: Start with a lowercase letter and use underscores to separate words. For example:
    • student_name
    • student_age
    • total_score
    • is_passed
    • max_value
  • Use uppercase letters for constants: Use all uppercase letters with underscores to separate words. For example, MAX_VALUE, PI.
  • Use descriptive names: Choose names that describe the purpose of the variable. For example:
    • student_name instead of name
    • student_age instead of age
    • MAX_SCORE instead of max
  • Avoid reserved words: Don’t use reserved words or keywords as variable names. For example:
    • def, class, if, else, return, for, while, etc. are reserved words in Python.
  • Avoid abbreviations: Use full words instead of abbreviations to make the code more readable. For example:
    • student_name instead of std_name
    • student_age instead of s_age
    • calculate_total_lateness instead of calculate_tl
Python Variable Names are Case-Sensitive

In Python, variable names are case-sensitive. For example, studentName and StudentName are considered two different variables. It’s important to be consistent with the naming conventions to avoid confusion.

10.8 Data Types

Python supports various data types that can be used to store different kinds of data. Since Python is dynamically typed, the type of a variable is determined at runtime based on the value assigned.

Some of the basic data types in Python include:

  • Numeric Types:
    • int: Represents integers. Examples: 25, -10, 0.
    • float: Represents floating-point numbers. Examples: 3.14, 2.5, -0.75.
  • Boolean Type:
    • bool: Represents True or False.
  • Sequence Types:
    • str: Represents strings (text). Values are enclosed in quotes (' or "). Examples: "Hello", 'Python'.

Throughout this course, you will encounter other data types:

  • Sequence Types:
    • list: Represents ordered, mutable collections. Examples: [1, 2, 3], ['apple', 'banana', 'cherry'].
    • tuple: Represents ordered, immutable collections. Examples: (1, 2, 3), ('apple', 'banana', 'cherry').
  • None Type:
    • NoneType: Represents the absence of a value, None.
  • Mapping Type:
    • dict: Represents unordered collections of key-value pairs. Examples: {'name': 'Alice', 'age': 25}, {1: 'apple', 2: 'banana'}.
  • Set Types:
    • set: Represents unordered collections of unique elements. Examples: {1, 2, 3}, {'apple', 'banana', 'cherry'}.
    • frozenset: Immutable version of set. Examples: frozenset({1, 2, 3}), frozenset({'apple', 'banana', 'cherry'}).

10.8.1 Numeric Data Types

Typically, numeric data types (in several programming languages) are referred to as:

  • Integer:
    • Whole numbers without any fractional or decimal part (e.g., 0, 1, -10).
    • Can be both positive and negative numbers or zero.
    • Typically used for counting, indexing, and situations where exact whole numbers are required.
  • Floating-Point:
    • Feature a decimal point (e.g., 3.14, 2.5, -0.75).
    • Represents real numbers (integers and numbers with fractional parts).
    • Used when you need to represent a wider range of values with varying degrees of precision.
    • Can represent very large or very small numbers using scientific notation (e.g., 1.23e-4).
Why ‘Floating-Point’ Numbers?

The term “floating-point” refers to the fact that the decimal point can “float” to the left or right, allowing the representation of both very large and very small numbers.

10.8.1.1 Writing Numeric Literals

Numeric literals can be written in different formats:

  • Integer Literals:
    • Can be written in decimal (base 10) format (e.g., 10, 100, -5).
    • Can also be written in binary (base 2) format by prefixing with 0b or 0B (e.g., 0b1010, 0B1101).
    • Can be written in octal (base 8) format by prefixing with 0o or 0O (e.g., 0o12, 0O17).
    • Can be written in hexadecimal (base 16) format by prefixing with 0x or 0X (e.g., 0x1A, 0XFF). Hexadecimal numbers use the digits 0-9 and A-F (or a-f) to represent values 10-15.
    • Can include underscores (_) to improve readability (e.g., 1_000_000, 0b1101_1010, 0x1A_BF).Underscores are ignored by the Python interpreter and are used to separate groups of digits for better readability.
  • Floating-Point Literals:
    • Can be written in decimal format with a decimal point (e.g., 3.14, 2.5, -0.75).
    • Can use scientific notation to represent very large or very small numbers (e.g., 1.23e-4, 2.5e6).
    • Can include underscores (_) for better readability (e.g., 3.14_159, 1.23e-4, 300_000.0).
    • Can also be written as integers with a decimal point (e.g., 10.0, -5.0). These are still considered floating-point numbers.

Here’s the revised section with corrections, clarifications, and the use of an appropriate table to illustrate numeric literals and their behavior:


10.8.2 Dealing with Very Large or Very Small Numbers

Floating-point numbers can represent very large or very small numbers using the scientific notation. For instance:

  • 1.23e-4 represents \(1.23 \times 10^{-4}\), or 0.000123.
  • 2.5e6 represents \(2.5 \times 10^6\), or 2,500,000.

However, floating-point numbers have limitations due to how they are represented in memory. They allocate a fixed number of bits for the mantissa and exponent, which can result in:

  1. Rounding errors when precision exceeds the allocated bits.
  2. Overflow when values exceed the representable range.
  3. Underflow when values are too close to zero to be represented accurately.

For precise calculations involving extremely large or small numbers, consider using libraries such as decimal (for arbitrary precision) and numpy (for numerical computing). In Table 10.1, we illustrate the behavior of floating-point literals in Python.

Table 10.1: Floating-point literals and their expected values in Python.
Literal Expected Value Python Evaluation
1.79e308 \(1.79 \times 10^{308}\) 1.79e+308
1.8e308 \(1.8 \times 10^{308}\) inf (overflow)
5.0e-324 \(5.0 \times 10^{-324}\) 5e-324
1.0e-325 \(1.0 \times 10^{-325}\) 0.0 (underflow)

10.8.3 String Data Type

A string literal, or str, is a sequence of characters (i.e., letters, numbers, symbols) enclosed either in single quotes (') or double quotes ("). It is how text data is represented in Python. They are referred to as “strings” because they are a sequence of characters strung together. In Python, strings are immutable, meaning they cannot be changed after they are created (you can create a new string based on an existing string, but you cannot modify the original string). In Listing 10.5, some examples of string literals are shown.

Listing 10.5: Examples of string literals in Python.
name1 = "Alice" # Enclosed in double quotes
name2 = 'Alice' # Enclosed in single quotes
hello1 = "Hello, 'Alice'!" # Double quotes with single quotes inside
hello2 = 'Hello, "Alice"!' # Single quotes with double quotes inside
result = "" # An empty string
smiley = "😊" # A string with an emoji

In Listing 10.5, the variables name1 and name2 store the string "Alice", hello1 and hello2 store strings with quotes inside them, result stores an empty string, and smiley stores a string with an emoji. Strings can contain letters, numbers, symbols, whitespace, and special characters. They can also be empty (i.e., contain no characters). Notice that you can use either single or double quotes to create a string, but the opening and closing quotes must match. You can also use single quotes inside double quotes and vice versa.

10.8.3.1 Multiline Strings

A string can also be created using triple quotes (''' or """) to span multiple lines:

multiline_str1 = """This is a
multi-line string"""

multiline_str2 = '''This is also a
multi-line string'''

print("""
The
quick brown fox
jumps over the lazy dog.
""")

If you need to include single or double quotes within a string, you can use an escape character (\) before the quote:

quote1 = "She said, \"Hello!\""
quote2 = 'He said, \'Hi!\''

When no text is present in the string, it is referred to as an empty string. An empty string is represented by two quotes with no space between them ("" or '').

10.8.3.2 Scaping Characters

Strings sometimes contain special characters, that are not easily visible or printable. These characters are represented using escape sequences. For example, the newline character (\n) is used to create a new line in a string. In Python, you can use the backslash (\) as an escape character to include special characters in a string. A scape character is a character that is not normally interpreted by the program but has a special meaning when preceded by a backslash. Some common escape sequences in Python strings are shown in Table 29.10.

Table 10.2: Common escape sequences in Python strings.
Escape Sequence Description Example Result
\\ Backslash "C:\\Users\\Alice" C:\Users\Alice
\' Single quote 'It\'s raining' It's raining
\" Double quote "She said, \"Hello!\"" She said, "Hello!"
\n Newline "First line\nSecond line"
\t Tab "First\tSecond" First Second
\b Backspace "Hello\bWorld" HellWorld

If you don’t use the escape character, Python will interpret the character literally (e.g., a newline character will be displayed as \n instead of creating a new line).

10.8.3.3 Multiline Comments

In Python, you can use triple quotes (''' or """) to create multiline comments. While Python does not have a built-in syntax for multiline comments, you can use triple quotes to create multiline strings that are not assigned to a variable. These strings are treated as comments and are ignored by the Python interpreter. For example:

'''
This is a multiline comment.

It spans multiple lines and is enclosed in triple quotes.
'''

It is common to use multiline comments to provide detailed explanations of code, document functions, or add notes to the code. For example, in Listing 10.6, a multiline comment is used to describe the purpose of a function. This is called a docstring (documentation string) and is a common practice in Python to document functions and modules.

Listing 10.6: Example of a multiline comment in Python using triple quotes. The comment provides a detailed description of the function convert_to_imperial using a docstring (documentation string) based on the Numpy Python library style (see Numpy docstring guide).

def convert_to_imperial(height_cm):
    '''
    Convert height from centimeters to feet and inches.

    This function takes the height in centimeters as 
    input and converts it to feet and inches.

    The conversion is based on the following:
    1 foot = 30.48 centimeters
    1 inch = 2.54 centimeters

    The height is converted to feet and inches and
    returned as a string in the format "<feet>'<inches>".

    Parameters:
    ----------
    height_cm : float
        Height in centimeters.

    Returns:
    -------
    str
        Height in feet and inches.
    
    Example:
    --------
    >>> convert_to_imperial(175)
    "5'9\""
    ''' 

10.8.3.4 Concatenating Strings

You can concatenate strings using the + operator. Concatenation is the process of combining two or more strings into a single string. For example:

first_name = "Alice"
last_name = "Smith"
full_name = first_name + " " + last_name
print(full_name)  # Output: Alice Smith

In this example, the strings first_name and last_name are concatenated with a space in between to create the full_name string.

10.8.3.5 String Interpolation (f-strings)

Python 3.6 introduced f-strings (formatted string literals) as a new way to format strings. F-strings allow you to embed expressions inside string literals, using curly braces ({}) to evaluate the expressions and insert their values into the string. In Listing 10.7, an example of using f-strings to format a time string is shown.

Listing 10.7: Example of using f-strings for string interpolation in Python. The variables hours, minutes, and seconds are embedded inside the string time_str using curly braces {}.
hours = 8
minutes = 30
seconds = 45

time_str = f"{hours}:{minutes}:{seconds}"
print(time_str)  # Output: 8:30:45

The f before the opening quote indicates that the string is an f-string. Inside the f-string, you can include variables, expressions, and even function calls (i.e., any valid Python expression). The expressions inside the curly braces are evaluated and replaced with their values in the resulting string. Numbers are automatically converted to strings when embedded in an f-string and other objects can be converted to strings using the str() function. In Table 10.3, we provide examples of using f-strings for string interpolation.

Table 10.3: Examples of using f-strings for string interpolation in Python.
Expression Description Input Result
f"Hello, {name}!" Embedding a variable name = "Alice" "Hello, Alice!"
f"Total: {price * quantity}" Embedding an expression price = 20, quantity = 5 "Total: 100"
f"Today is {datetime.now():%A, %B %d, %Y}" Embedding a function call datetime.now() = datetime(2022, 1, 1) "Today is Saturday, January 01, 2022"
f"Value: {value:.2f}" Formatting a floating-point number value = 10.5 "Value: 10.50"
f"Count: {count:04d}" Formatting an integer with leading zeros count = 10 "Count: 0010"
f"Name: {name.upper()}" Calling a method on a string name = "Alice" "Name: ALICE"
f"Title: {title:^20}" Centering a string within a width of 20 title = "My Title" " My Title "
f"Items: {', '.join(items):<20}" Joining a list and left-justifying within a width of 20 items = ["item1", "item2"] "Items: item1, item2 "
f"Total: {total:,.2f}" Formatting a number with commas as thousands separators total = 1000 "Total: 1,000.00"
f"Percentage: {percentage:.2%}" Formatting a number as a percentage percentage = 0.5 "Percentage: 50.00%"
f"Binary: {num:b}" Formatting an integer as binary num = 10 "Binary: 1010"
f"Right-aligned: {value:>10}" Right-aligning a string within a width of 10 value = "value" "Right-aligned: value"

10.8.3.6 Useful String Methods

Python provides several built-in methods to manipulate strings. In Table 29.11, some common string methods are listed. These methods can be used to convert strings to uppercase or lowercase, strip whitespace, split strings, find substrings, replace text, and more.

Table 10.4: Common string methods in Python.
Method Description Example Result
upper() Converts the string to uppercase "hello".upper() "HELLO"
lower() Converts the string to lowercase "Hello".lower() "hello"
capitalize() Converts the first character to uppercase "hello".capitalize() "Hello"
title() Converts the first character of each word to uppercase "hello world".title() "Hello World"
strip() Removes leading and trailing whitespace " hello ".strip() "hello"
lstrip() Removes leading whitespace " hello ".lstrip() "hello "
rstrip() Removes trailing whitespace " hello ".rstrip() " hello"
center() Centers the string within a specified width "hello".center(10) " hello "
ljust() Left-justifies the string within a specified width "hello".ljust(10) "hello "
rjust() Right-justifies the string within a specified width "hello".rjust(10) " hello"
ord() Returns the Unicode code point of a character ord("A") 65
chr() Returns the character from a Unicode code point chr(65) "A"
split() Splits the string into a list of substrings "hello world".split() ["hello", "world"]
partition() Splits the string at the first occurrence of a separator "hello world".partition(" ") ("hello", " ", "world")
join() Joins a list of strings into a single string " ".join(["hello", "world"]) "hello world"
startswith() Checks if the string starts with a specified substring "hello".startswith("he") True
endswith() Checks if the string ends with a specified substring "hello".endswith("lo") True
find() Searches for a substring and returns its index "hello".find("l") 2
replace() Replaces a substring with another string "hello".replace("e", "a") "hallo"
index() Searches for a substring and returns its index "hello".index("l") 2
count() Counts the occurrences of a substring "hello".count("l") 2
len() Returns the length of the string len("hello") 5
isalpha() Checks if all characters are alphabetic "hello".isalpha() True
isdigit() Checks if all characters are digits "123".isdigit() True
isalnum() Checks if all characters are alphanumeric "hello123".isalnum() True
isspace() Checks if all characters are whitespace " ".isspace() True
istitle() Checks if the string is titlecased "Hello World".istitle() True
isupper() Checks if all characters are uppercase "HELLO".isupper() True
islower() Checks if all characters are lowercase "hello".islower() True
Unicode Characters

In Python, strings are represented using Unicode characters. Unicode is a standard for encoding characters from different writing systems. Each character is assigned a unique code point, which is an integer value that represents the character. The ord() function returns the Unicode code point of a character, and the chr() function returns the character from a Unicode code point.

Even emojis and special characters can be represented using Unicode characters. For example, the Unicode code point for the heart emoji ❤️ is U+2764. In Listing 10.8, the heart emoji is represented using its Unicode code point.

Listing 10.8: Example of representing the heart emoji ❤️ using its Unicode code point in Python. The Unicode code point for the heart emoji is U+2764.
heart_emoji = "\u2764\ufe0f"
print(heart_emoji)  # Output: ❤️
❤️

10.8.4 String Indexing and Slicing

Strings can be broken down into individual characters using indexing. In Python, strings are zero-indexed, meaning the first character is at index 0, the second character is at index 1, and so on. You can access individual characters in a string using square brackets ([]) with the index of the character you want to access. For example, in Table 10.5, the string "Python" is indexed using different positive and negative indices.

Table 10.5: Indexing of the string “Python” using positive and negative indices.
String P y t h o n
Positive Index 0 1 2 3 4 5
Negative Index -6 -5 -4 -3 -2 -1

To access a character at a specific index, you can use the index inside square brackets. In Table 29.8, we provide examples of accessing characters in a string variable named s whose value is "Python".

Table 10.6: Examples of string indexing in Python considering s = "Python".
Expression Description Result
s[0] Access the first character "P"
s[3] Access the fourth character "h"
s[-1] Access the last character "n"
s[-3] Access the third character from the end "h"
s[6] Accessing an out-of-range index Raises an IndexError
s[-1] Accessing an out-of-range negative index Raises an IndexError

You can also extract a substring from a string using slicing. Slicing allows you to create a substring by specifying a range of indices. The syntax for slicing is s[start:end], where start is the starting index (inclusive) and end is the ending index (exclusive). If start is not specified, it defaults to 0, and if end is not specified, it defaults to the end of the string. A third parameter, called the step, can also be specified as s[start:end:step] to extract every step-th character. In Table 29.9, we provide examples of slicing the string "Python" to extract substrings.

Table 10.7: Examples of string slicing in Python considering s = "Python".
Expression Description Result
s[:] Slicing to get the entire string "Python"
s[0:2] Slicing to get a substring "Py"
s[2:5] Slicing to get a substring "tho"
s[:4] Slicing from the beginning "Pyth"
s[3:] Slicing to the end "hon"
s[-4:-1] Slicing with negative indices "tho"
s[::-1] Reverse the string "nohtyP"
s[::2] Get every second character "Pto"
s[1::2] Get every second character starting from the second character "yhn"
s[1:4:2] Get every second character from the second to the fourth character "yh"
s[4:1:-1] Reverse a substring "oht"

10.8.5 Breaking Long String Lines

When writing long strings that span multiple lines, you can use parentheses () to break the string into multiple lines. This is useful for improving code readability and maintaining a consistent line length. For example, in Listing 10.9, a long string is broken into multiple lines using parentheses.

Listing 10.9: Example of breaking a long string into multiple lines using parentheses in Python. The long string is enclosed in parentheses to span multiple lines.
long_str = ("This is a long string that spans multiple lines. "
            "It is enclosed in parentheses to break it into "
            "multiple lines for better readability.")

print(long_str)
This is a long string that spans multiple lines. It is enclosed in parentheses to break it into multiple lines for better readability.

In Listing 10.9, the long string is enclosed in parentheses, and each line is separated by a space. When the code is executed, the long string is printed as a single line, even though it is written across multiple lines in the code.

10.8.6 Boolean Data Type

Boolean data types represent logical values: True or False.

is_passed = True  # type: bool

10.9 Type Conversion

Sometimes, you may need to convert a value from one data type to another. This can be done using built-in functions.

For example:

# Convert string to integer
age_str = "25"
age_int = int(age_str)  # Now age_int is an integer 25

# Convert integer to string
score = 95
score_str = str(score)  # Now score_str is the string "95"

# Convert string to float
height_str = "1.75"
height_float = float(height_str)  # Now height_float is 1.75

# Convert integer to float
count = 10
count_float = float(count)  # Now count_float is 10.0

If you try to convert incompatible types, Python will raise a ValueError:

invalid_int = int("abc")  # Raises ValueError

10.10 Constants

Python does not have built-in constant types or keywords to declare constants. However, by convention, variables that should not change are written in uppercase letters. This is a way to signal to other developers that the value should be treated as a constant.

For example:

NUM_QUARTERS = 4
RATE = 0.0725
MOD_NAME = "Budget Macros"
APP_NAME = "Budget Application"

While Python does not enforce immutability of these variables, using uppercase names helps indicate that they are intended to be constants.

Using constants in your Python code has several advantages:

  1. Improved Code Readability: Constants make your code more readable by providing meaningful names for values that are used multiple times.
  2. Higher Flexibility: If the value of a constant changes, you only need to modify it in one place, rather than searching for and updating multiple occurrences of the value throughout your code. This makes your code easier to maintain and less error-prone.

10.10.1 Example: Converting Measurements Using Constants

Here’s an example of using constants to convert measurements from metric to imperial units:

FEET_TO_CENTIMETERS = 30.48
FEET_TO_INCHES = 12

def convert_to_imperial():
    height_in_centimeters = float(input("Enter height in centimeters: "))

    feet = int(height_in_centimeters / FEET_TO_CENTIMETERS)
    inches = ((height_in_centimeters / FEET_TO_CENTIMETERS) - feet) * FEET_TO_INCHES

    height_in_feet_and_inches = f"{feet}'{round(inches)}\""

    print("Height in feet and inches:", height_in_feet_and_inches)

# Example usage
convert_to_imperial()

In this example, the user is prompted to enter a height in centimeters, which is then converted to feet and inches using the constants FEET_TO_CENTIMETERS and FEET_TO_INCHES. The result is displayed in the format <feet>'<inches>".