Chuyển tới nội dung chính

Biến và Kiểu dữ liệu

Biến và kiểu dữ liệu là nền tảng của mọi chương trình. Hiểu rõ phần này giúp bạn tránh được rất nhiều bug khó chịu sau này — đặc biệt với Python, nơi kiểu dữ liệu hoạt động khác so với C/Java.

Biến là gì?

Biến là tên gọi trỏ đến một vùng nhớ lưu giá trị. Trong Python, bạn không cần khai báo kiểu — chỉ cần gán giá trị là xong.

# Khai báo biến — không cần kiểu dữ liệu
student_name = "Nguyễn Văn An"
score = 85
gpa = 8.5
is_passed = True
note = None # Biến chưa có giá trị

print(student_name) # Output: Nguyễn Văn An
print(score) # Output: 85

Quy tắc đặt tên biến

# ĐÚNG — dùng snake_case
student_name = "An"
total_score = 100
is_active = True
max_retries = 3

# ĐÚNG — nhưng ít dùng
_private_var = "internal"
__dunder__ = "special"

# SAI — lỗi cú pháp
2name = "An" # Không bắt đầu bằng số
my-name = "An" # Không dùng dấu gạch ngang
class = "10A" # Không dùng từ khóa của Python

Quy tắc bắt buộc:

  • Chỉ dùng chữ cái, số, và dấu gạch dưới _
  • Không bắt đầu bằng số
  • Phân biệt hoa thường: score khác Score
  • Không dùng từ khóa Python: if, for, class, return, ...

Quy ước (convention):

  • snake_case cho biến và hàm: student_name, total_score
  • UPPER_SNAKE_CASE cho hằng số: MAX_SCORE = 100
  • PascalCase cho class: StudentRecord

Các kiểu dữ liệu cơ bản

int — Số nguyên

age = 20
score = -5
big_number = 1_000_000 # Dấu _ giúp đọc dễ hơn (= 1000000)
hex_value = 0xFF # Hệ 16: 255
binary = 0b1010 # Hệ 2: 10

print(type(age)) # Output: <class 'int'>
print(big_number) # Output: 1000000

# Python không giới hạn kích thước int
huge = 2 ** 100
print(huge) # Output: 1267650600228229401496703205376

float — Số thực

gpa = 8.75
pi = 3.14159
scientific = 1.5e-3 # = 0.0015 (scientific notation)

print(type(gpa)) # Output: <class 'float'>
print(round(gpa, 1)) # Output: 8.8 (làm tròn 1 chữ số)
Cạm bẫy float precision
print(0.1 + 0.2)        # Output: 0.30000000000000004
print(0.1 + 0.2 == 0.3) # Output: False (!!!)

# Cách đúng để so sánh float
import math
print(math.isclose(0.1 + 0.2, 0.3)) # Output: True

# Hoặc dùng round để hiển thị
print(round(0.1 + 0.2, 1)) # Output: 0.3

Lý do: Máy tính lưu số thực theo nhị phân — một số không biểu diễn chính xác được. Đây là vấn đề chung của mọi ngôn ngữ, không riêng Python.

str — Chuỗi ký tự

name = "Đào Trọng Huấn"
city = 'Hà Nội'
multiline = """Dòng 1
Dòng 2
Dòng 3"""

print(type(name)) # Output: <class 'str'>
print(len(name)) # Output: 14 (số ký tự)
print(name[0]) # Output: Đ (ký tự đầu tiên)
print(name[-1]) # Output: n (ký tự cuối)

bool — Giá trị logic

is_passed = True
has_error = False

print(type(is_passed)) # Output: <class 'bool'>

# bool thực ra là subclass của int
print(True + True) # Output: 2
print(True * 5) # Output: 5
print(int(True)) # Output: 1
print(int(False)) # Output: 0

# Truthy và Falsy values
print(bool(0)) # Output: False
print(bool("")) # Output: False
print(bool([])) # Output: False
print(bool(None)) # Output: False

print(bool(1)) # Output: True
print(bool("hello")) # Output: True
print(bool([1, 2])) # Output: True

None — Không có giá trị

result = None
student_grade = None # Chưa có điểm

print(type(result)) # Output: <class 'NoneType'>
print(result is None) # Output: True (dùng "is" để kiểm tra None)

# Dùng None làm giá trị mặc định
def find_student(student_id):
# Nếu không tìm thấy, trả về None
return None
Kiểm tra None đúng cách

Luôn dùng is None hoặc is not None, không dùng == None.

# ĐÚNG
if result is None:
print("Không có kết quả")

# TRÁNH (dù hoạt động được)
if result == None:
print("Không có kết quả")

Hàm type()isinstance()

score = 85
name = "An"
gpa = 8.5
is_active = True

# type() — xem kiểu dữ liệu
print(type(score)) # Output: <class 'int'>
print(type(name)) # Output: <class 'str'>
print(type(gpa)) # Output: <class 'float'>
print(type(is_active)) # Output: <class 'bool'>

# isinstance() — kiểm tra có phải kiểu X không
print(isinstance(score, int)) # Output: True
print(isinstance(score, float)) # Output: False
print(isinstance(score, (int, float))) # Output: True (kiểm tra nhiều kiểu)

# isinstance() tốt hơn type() vì tôn trọng inheritance
print(isinstance(True, int)) # Output: True (bool là subclass của int)
print(type(True) == int) # Output: False

Dynamic Typing — ưu và nhược điểm

Python là ngôn ngữ dynamically typed — một biến có thể thay đổi kiểu dữ liệu.

x = 10          # x là int
print(type(x)) # Output: <class 'int'>

x = "hello" # x giờ là str
print(type(x)) # Output: <class 'str'>

x = [1, 2, 3] # x giờ là list
print(type(x)) # Output: <class 'list'>

Ưu điểm:

  • Code ngắn gọn, không cần khai báo kiểu
  • Linh hoạt, prototype nhanh

Nhược điểm:

  • Dễ bug khi biến bị đổi kiểu ngoài ý muốn
  • IDE khó gợi ý (autocomplete)
  • Khó đọc khi code lớn

Giải pháp — Type Hints (Python 3.5+):

# Không bắt buộc nhưng giúp code rõ ràng hơn
def calculate_grade(score: int, max_score: int = 100) -> float:
return score / max_score * 10

student_name: str = "Nguyễn Văn An"
student_score: int = 85

# Python không enforce type hints — chúng chỉ là "gợi ý"
# Dùng mypy để kiểm tra kiểu tĩnh nếu cần

Bảng so sánh kiểu dữ liệu

KiểuVí dụMutable?Dùng khi nào
int42, -5KhôngSố nguyên, đếm, index
float3.14, -0.5KhôngTính toán thập phân
str"hello"KhôngVăn bản, tên, mã
boolTrue, FalseKhôngĐiều kiện, cờ trạng thái
NoneNoneKhôngGiá trị rỗng, chưa có
list[1, 2, 3]Danh sách thay đổi được
tuple(1, 2, 3)KhôngDữ liệu cố định
dict{"a": 1}Key-value mapping
set{1, 2, 3}Tập hợp unique

Mutable vs Immutable

# Immutable — không thể thay đổi "trong chỗ"
name = "An"
name[0] = "B" # TypeError: 'str' object does not support item assignment

# Bạn phải tạo object mới
name = "B" + name[1:] # Tạo string mới "Bn"

# Mutable — có thể thay đổi trực tiếp
scores = [8, 9, 7]
scores[0] = 10 # OK — sửa trực tiếp phần tử đầu
scores.append(9) # OK — thêm phần tử vào list
print(scores) # Output: [10, 9, 7, 9]
# Pitfall: gán biến KHÔNG tạo bản sao
a = [1, 2, 3]
b = a # b trỏ đến CÙNG object với a

b.append(4)
print(a) # Output: [1, 2, 3, 4] — a cũng bị thay đổi!
print(b) # Output: [1, 2, 3, 4]

# Để tạo bản sao độc lập:
b = a.copy() # Shallow copy
# hoặc
b = a[:] # Slice copy
b = list(a) # List constructor copy

Chuyển đổi kiểu dữ liệu

# String sang số
age_str = "25"
age = int(age_str) # 25
gpa_str = "8.5"
gpa = float(gpa_str) # 8.5

# Số sang string
score = 85
score_str = str(score) # "85"

# Lỗi khi chuyển đổi không hợp lệ
int("hello") # ValueError: invalid literal for int()
int("8.5") # ValueError — phải qua float trước
int(float("8.5")) # 8 — OK

# Input luôn là string — phải chuyển đổi thủ công
score = int(input("Nhập điểm: ")) # Nhớ chuyển sang int
gpa = float(input("Nhập GPA: ")) # Nhớ chuyển sang float

Bài tập

Bài 1. Tạo các biến lưu thông tin học sinh: student_name (str), student_id (int), gpa (float), is_graduated (bool). In ra kiểu dữ liệu của từng biến bằng type().

Bài 2. Viết chương trình nhập điểm 3 môn từ bàn phím, tính điểm trung bình. Xử lý trường hợp user nhập chữ thay vì số (dùng try/except ValueError).

Bài 3. Giải thích tại sao đoạn code sau cho kết quả bất ngờ và sửa lại:

a = [1, 2, 3]
b = a
b.append(4)
print(a) # Tại sao a bị thay đổi?

Bài 4. Viết chương trình kiểm tra một chuỗi nhập từ người dùng có thể chuyển đổi sang số nguyên hay không. In ra True/False tương ứng. (Gợi ý: dùng str.isdigit() hoặc try/except.)