Python 导入类练习题(含答案)
1. 创建模块并用 import 方式导入
题目: 创建两个文件:
dog.py:定义一个Dog类,有属性name(名字)和breed(品种),有方法bark()打印”xx(品种)的 xx 说:汪汪!”main.py:用import dog方式导入,创建一个 Dog 实例并调用bark()
参考答案:
文件:dog.py
"""狗类模块"""
class Dog:
def __init__(self, name, breed):
self.name = name
self.breed = breed
def bark(self):
print(f"{self.breed}的 {self.name} 说:汪汪!")
if __name__ == "__main__":
d = Dog("旺财", "金毛")
d.bark()
文件:main.py
import dog # 导入整个模块
my_dog = dog.Dog("旺财", "金毛") # 使用时加模块名前缀
my_dog.bark()
# 输出:金毛的 旺财 说:汪汪!
关键点: import dog 导入整个模块,使用类时必须写 dog.Dog(...),模块名作为前缀。
2. 用 from…import 方式导入
题目: 继续使用第 1 题的 dog.py,在新的 main2.py 中用 from dog import Dog 方式导入,创建实例并调用 bark()。比较和第 1 题写法的区别。
参考答案:
文件:main2.py
from dog import Dog # 只导入 Dog 这个类
my_dog = Dog("咪咪", "柴犬") # 直接用类名,不需要 dog. 前缀
my_dog.bark()
# 输出:柴犬的 咪咪 说:汪汪!
两种方式的区别:
| 写法 | 使用方式 | 特点 |
|---|---|---|
import dog |
dog.Dog(...) |
能看出类来自哪个模块 |
from dog import Dog |
Dog(...) |
写法更简洁,但看不出来源 |
3. 从一个模块导入多个类
题目: 创建 shapes.py,里面定义两个类:
Circle:属性radius(半径),方法area()返回面积(3.14159 * radius ** 2)Rectangle:属性width和height,方法area()返回面积
在 main.py 中一行导入两个类,各创建一个实例,打印面积。
参考答案:
文件:shapes.py
"""几何图形类"""
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
if __name__ == "__main__":
c = Circle(5)
r = Rectangle(4, 6)
print(f"圆面积:{c.area():.2f}")
print(f"矩形面积:{r.area():.2f}")
文件:main.py
from shapes import Circle, Rectangle # 一行导入两个类,用逗号分隔
c = Circle(5)
r = Rectangle(4, 6)
print(f"圆的面积:{c.area():.2f}") # 圆的面积:78.54
print(f"矩形的面积:{r.area():.2f}") # 矩形的面积:24.00
关键点: from 模块 import 类1, 类2 用逗号分隔,一次导入多个类。
4. 使用别名(as)
题目: 继续使用 shapes.py,在 main.py 中:
- 用
from shapes import Rectangle as Rect给Rectangle起别名Rect - 用
import shapes as sh给整个模块起别名,再用sh.Circle创建实例
参考答案:
文件:main.py
# 给类起别名
from shapes import Rectangle as Rect
r = Rect(3, 8)
print(f"矩形面积:{r.area()}") # 矩形面积:24
# 给模块起别名
import shapes as sh
c = sh.Circle(7)
print(f"圆的面积:{c.area():.2f}") # 圆的面积:153.94
什么时候用别名?
- 类名很长,写起来麻烦
- 两个模块里有同名类,需要区分(如
from moduleA import Car as CarA)
5. if __name__ == "__main__" 的作用
题目: 有如下 greet.py 文件,里面有一行打印代码放在类外面(模拟”忘记用 if name“的情况)。观察导入时的问题,然后修复它。
有问题的 greet.py:
class Greeter:
def __init__(self, name):
self.name = name
def say_hello(self):
print(f"你好,我是 {self.name}!")
# 这行在被导入时也会执行!
print("greet 模块被加载了,正在测试...")
g = Greeter("测试")
g.say_hello()
main.py:
from greet import Greeter
g = Greeter("张三")
g.say_hello()
问题: 运行 main.py 时会额外打印什么?为什么?如何修复?
参考答案:
运行 main.py 的输出:
greet 模块被加载了,正在测试... ← 导入时自动执行了,不想要这行!
你好,我是 测试! ← 导入时自动执行了,不想要这行!
你好,我是 张三! ← 这才是我们想要的
修复后的 greet.py:
class Greeter:
def __init__(self, name):
self.name = name
def say_hello(self):
print(f"你好,我是 {self.name}!")
# 测试代码放在这里,只有直接运行 greet.py 时才执行,被导入时不执行
if __name__ == "__main__":
print("greet 模块被加载了,正在测试...")
g = Greeter("测试")
g.say_hello()
修复后运行 main.py 的输出:
你好,我是 张三! ← 只有我们想要的内容
关键点: 模块里的测试代码必须放在 if __name__ == "__main__": 里面,否则被导入时会自动执行。
6. 跨文件继承(子类和父类在不同文件)
题目:
animal.py:定义父类Animal,有name属性和breathe()方法dog.py:从animal.py导入Animal,定义子类Dog,新增breed属性和bark()方法main.py:从dog.py导入Dog,创建实例,调用breathe()和bark()
参考答案:
文件:animal.py
"""动物基类"""
class Animal:
def __init__(self, name):
self.name = name
def breathe(self):
print(f"{self.name} 在呼吸")
if __name__ == "__main__":
a = Animal("动物")
a.breathe()
文件:dog.py
"""狗类,继承自 Animal"""
from animal import Animal # 导入父类
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # 调用父类 __init__
self.breed = breed
def bark(self):
print(f"{self.breed}的 {self.name} 说:汪汪!")
if __name__ == "__main__":
d = Dog("旺财", "金毛")
d.breathe()
d.bark()
文件:main.py
from dog import Dog # 只需导入 Dog,它内部已经处理了 Animal 的导入
my_dog = Dog("旺财", "拉布拉多")
my_dog.breathe() # 旺财 在呼吸(继承自 Animal)
my_dog.bark() # 拉布拉多的 旺财 说:汪汪!
关键点: main.py 只导入 Dog,不需要显式导入 Animal,因为 dog.py 里已经处理了继承关系。
7. 创建并使用包
题目: 创建以下文件结构:
练习7/
├── tools/
│ ├── __init__.py (空文件)
│ ├── calculator.py (含 Calculator 类)
└── main.py
Calculator 类有方法:
add(a, b)返回 a + bsubtract(a, b)返回 a – bmultiply(a, b)返回 a * b
在 main.py 中用 from tools.calculator import Calculator 方式导入并测试。
参考答案:
文件:tools/__init__.py
# 空文件,让 Python 把 tools 文件夹识别为包
文件:tools/calculator.py
"""计算器类"""
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
def multiply(self, a, b):
return a * b
if __name__ == "__main__":
calc = Calculator()
print(calc.add(3, 4)) # 7
print(calc.subtract(10, 3)) # 7
print(calc.multiply(4, 5)) # 20
文件:main.py
from tools.calculator import Calculator # 包名.模块名.类名
calc = Calculator()
print(calc.add(10, 5)) # 15
print(calc.subtract(10, 5)) # 5
print(calc.multiply(10, 5)) # 50
关键点: 从包中导入时,用 from 包名.模块名 import 类名 的格式。
8. 在 __init__.py 中统一导出
题目: 在第 7 题基础上,给 tools/ 包再添加一个 converter.py:
tools/
├── __init__.py (需要修改)
├── calculator.py
└── converter.py (新增)
Converter 类有方法:
celsius_to_fahrenheit(c)摄氏转华氏:c * 9/5 + 32kg_to_pound(kg)千克转磅:kg * 2.20462
要求: 在 __init__.py 里统一导出 Calculator 和 Converter,让 main.py 能用 from tools import Calculator, Converter 直接导入。
参考答案:
文件:tools/converter.py
"""单位换算类"""
class Converter:
def celsius_to_fahrenheit(self, c):
return c * 9 / 5 + 32
def kg_to_pound(self, kg):
return kg * 2.20462
if __name__ == "__main__":
conv = Converter()
print(conv.celsius_to_fahrenheit(100)) # 212.0
print(conv.kg_to_pound(70)) # 154.3234
文件:tools/__init__.py
from .calculator import Calculator # 相对导入
from .converter import Converter
文件:main.py
from tools import Calculator, Converter # 不需要指定子模块名了!
calc = Calculator()
conv = Converter()
print(calc.multiply(6, 7)) # 42
print(conv.celsius_to_fahrenheit(37)) # 98.6(体温)
print(f"{conv.kg_to_pound(60):.2f} 磅") # 132.28 磅
关键点: __init__.py 中的 from .模块名 import 类名(相对导入)让包的用户可以更简洁地导入,. 代表当前包目录。
9. 避免文件名与标准库冲突
题目: 下面的代码运行后报错,分析原因并修复:
项目目录/
├── random.py ← 自己写的文件
└── main.py
random.py(自己写的):
class RandomHelper:
def pick(self, items):
return items[0]
main.py:
import random
numbers = [1, 2, 3, 4, 5]
print(random.choice(numbers)) # 想用标准库 random 的 choice 函数
报错: AttributeError: module 'random' has no attribute 'choice'
参考答案:
原因: 当前目录下有一个叫 random.py 的文件,Python 导入时优先找当前目录,导入的是你自己写的 random.py(里面只有 RandomHelper 类,没有 choice 函数),而不是标准库里的 random 模块。
修复方案: 把自己的文件改名,不要和标准库重名:
项目目录/
├── random_helper.py ← 改名,避免冲突
└── main.py
random_helper.py:
class RandomHelper:
def pick(self, items):
return items[0]
main.py(修复后):
import random # 现在导入的是标准库的 random
numbers = [1, 2, 3, 4, 5]
print(random.choice(numbers)) # 正常输出,如:3
常见的”雷区”文件名(绝对不要用):
| 禁止使用的文件名 | 对应的标准库 |
|---|---|
random.py |
random(随机数) |
os.py |
os(操作系统接口) |
math.py |
math(数学函数) |
string.py |
string(字符串工具) |
time.py |
time(时间模块) |
json.py |
json(JSON处理) |
10. 找错题:找出并修复所有错误
下面有三处错误,找出来并修复:
文件:phone.py
class Phone:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def info(self):
return f"{self.brand} {self.model}"
print("加载完毕") # 错误1
文件:smartphone.py
class Smartphone(Phone): # 错误2:没有导入 Phone
def __init__(self, brand, model, os):
super().__init__(brand, model)
self.os = os
def info(self):
return super().info() + f"({self.os})"
文件:main.py
from phone import Phone
from smartphone import Smartphone
p = phone("苹果", "14") # 错误3:类名写错了
sp = Smartphone("三星", "S23", "Android")
print(p.info())
print(sp.info())
参考答案:
错误 1:phone.py 里的 print("加载完毕") 没有放在 if __name__ == "__main__": 里
# phone.py 修复版
class Phone:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def info(self):
return f"{self.brand} {self.model}"
if __name__ == "__main__": # 修复:测试代码放在这里
print("加载完毕")
错误 2:smartphone.py 里使用了 Phone 但没有导入它
# smartphone.py 修复版
from phone import Phone # 修复:导入父类 Phone
class Smartphone(Phone):
def __init__(self, brand, model, os):
super().__init__(brand, model)
self.os = os
def info(self):
return super().info() + f"({self.os})"
错误 3:main.py 里 phone("苹果", "14") 应该是 Phone("苹果", "14")(类名首字母大写)
# main.py 修复版
from phone import Phone
from smartphone import Smartphone
p = Phone("苹果", "14") # 修复:类名首字母大写
sp = Smartphone("三星", "S23", "Android")
print(p.info()) # 苹果 14
print(sp.info()) # 三星 S23(Android)
11. 综合题:用户账号系统
题目: 创建以下文件结构:
账号系统/
├── models/
│ ├── __init__.py
│ ├── user.py (User 类)
│ └── admin.py (Admin 类,继承 User)
└── main.py
要求:
User:属性username、email,方法info()返回用户信息,方法login()打印”xx 已登录”Admin(User):新增属性level(管理级别,整数),覆盖info()追加管理级别,新增方法ban_user(target_name)打印”管理员 xx 封禁了用户 xx”__init__.py:统一导出两个类main.py:用from models import User, Admin导入,创建普通用户和管理员各一个,演示各方法
参考答案:
文件:models/user.py
"""用户类"""
class User:
def __init__(self, username, email):
self.username = username
self.email = email
def info(self):
return f"用户:{self.username},邮箱:{self.email}"
def login(self):
print(f"{self.username} 已登录")
if __name__ == "__main__":
u = User("张三", "zhangsan@example.com")
print(u.info())
u.login()
文件:models/admin.py
"""管理员类"""
from .user import User # 相对导入父类
class Admin(User):
def __init__(self, username, email, level):
super().__init__(username, email)
self.level = level
def info(self):
return super().info() + f",管理级别:{self.level}"
def ban_user(self, target_name):
print(f"管理员 {self.username} 封禁了用户 {target_name}")
if __name__ == "__main__":
a = Admin("超级管理员", "admin@example.com", 1)
print(a.info())
a.ban_user("捣乱用户")
文件:models/__init__.py
from .user import User
from .admin import Admin
文件:main.py
from models import User, Admin
# 普通用户
user = User("李四", "lisi@example.com")
user.login()
print(user.info())
print()
# 管理员
admin = Admin("王管理", "wang@example.com", 2)
admin.login()
print(admin.info())
admin.ban_user("捣乱用户123")
print()
# isinstance 验证
print(isinstance(admin, Admin)) # True
print(isinstance(admin, User)) # True(Admin 继承 User)
运行结果:
李四 已登录
用户:李四,邮箱:lisi@example.com
王管理 已登录
用户:王管理,邮箱:wang@example.com,管理级别:2
管理员 王管理 封禁了用户 捣乱用户123
True
True
12. 相对导入练习
题目: 下面的包结构中,b.py 需要用到 a.py 里的 ClassA。有两种写法,请判断哪种是相对导入、哪种是绝对导入,并说明分别在什么情况下使用:
mypackage/
├── __init__.py
├── a.py (定义了 ClassA)
└── b.py (需要导入 ClassA)
写法一(在 b.py 中):
from mypackage.a import ClassA
写法二(在 b.py 中):
from .a import ClassA
参考答案:
| 写法 | 类型 | 说明 |
|---|---|---|
from mypackage.a import ClassA |
绝对导入 | 从项目根目录出发,写完整路径 |
from .a import ClassA |
相对导入 | . 代表当前包(mypackage),只写相对路径 |
使用建议:
- 在包内部文件互相导入时,推荐用相对导入(
from .a import ClassA)- 好处:如果整个包被改名,内部的相对导入不需要修改
- 在主程序(包外部)导入时,必须用绝对导入(
from mypackage.a import ClassA)- 相对导入在顶级脚本里会报
ImportError
- 相对导入在顶级脚本里会报