练习题
1.面向对象三大特性,各有什么用处,说说你的理解。
面向对象的三大特性:
1.继承:解决代码的复用性问题
2.封装:对数据属性严格控制,隔离复杂度
3.多态性:增加程序的灵活性与可扩展性
2.类的属性和对象的属性有什么区别?
首先需要理解这样一个概念:
Python中一切皆对象
因而‘类’也是一种对象
所以我们在谈论类的属性和对象的属性的区别时,实际上是在谈论‘类’这样一种特殊的对象与其他对象的区别。
类属性仅是与类相关的数据值,和普通对象属性不同,类属性和实例对象无关。这些值像静态成员那样被引用,即使在多次实例化中调用类,它们的值都保持不变。不管如何,静态成员不会因为实例而改变它们的值,除非实例中显式改变它们的值。
3.面向过程编程与面向对象编程的区别与应用场景?
1.1 面向过程的程序设计
“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。“面向过程”也可称之为“面向记录”编程思想,不支持丰富的“面向对象”特性(比如继承、多态),并且它们不允许混合持久化状态和域逻辑。
•特点:分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了
•优点:复杂的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
•缺点:可扩展性差
•应用场景:面向过程的程序设计思想一般用于那些功能一旦实现之后就很少需要改变的场景, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,著名的例子有Linux內核,git,以及Apache HTTP Server等。但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。
1.2 面向对象的程序设计
“面向对象程序设计”(Object-oriented programming,缩写:OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。 面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。
•优点:可扩展性高
•缺点:编程的复杂度远高于面向过程,不了解面向对象而立即上手并基于它设计程序,极容易出现过度设计的问题,而且在一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本程序就不适合用面向对象去设计,面向过程反而更加适合。
•应用场景:面向对象程序设计推广了程序的灵活性和可维护性,并且在大型项目设计中广为应用。 此外,支持者声称面向对象程序设计要比以往的做法更加便于学习,因为它能够让人们更简单地设计并维护程序,使得程序更加便于分析、设计、理解。
4.类和对象在内存中是如何保存的
类以及类中的方法在内存中只有一份,而根据类创建的每一个对象都在内存中需要存一份
根据类创建对象时,对象中除了封装 name 和 age 的值之外,还会保存一个类对象指针,该值指向当前对象的类。
当通过某对象执行其类中方法时,过程如下:
根据当前对象中的 类对象指针 找到类中的方法
将对象当作参数传给方法的第一个参数 self
5.什么是绑定到对象的方法、绑定到类的方法、解除绑定的函数、如何定义,如何调用,给谁用?有什么特性
8.如下示例, 请用面向对象的形式优化以下代码
def exc1(host,port,db,charset):
conn=connect(host,port,db,charset)
conn.execute(sql)
return xxx
def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
conn.call_proc(sql)
return xxx
# 每次调用都需要重复传入一堆参数
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')
优化代码:
class Exc:
host = '127.0.0.1'
port = 3306
db = 'db1'
charset = 'utf8'
conn = connect(host, port, db, charset)
def __init__(self, proc_name):
self.proc = proc_name
def test(self):
if self.proc =='select * from tb1;':
self.conn.execute(sql)
elif self.proc =='存储过程的名字':
self.conn.call_proc(sql)
return XXX
exc1 = Exc('select * from tb1;')
exc1.test()
exc2 = Exc('存储过程的名字')
exc2.test()
#从这里的优化结果可以看书,需要重复输入的内容变少了,但是类的代码量也不小
9.示例1, 现有如下代码, 会输出什么:
class People(object):
__name = "luffy"
__age = 18
p1 = People()
print(p1.__name, p1.__age)
#程序将会报错,因为隐藏属性不能直接被访问
print(p1._People__name, p1._People__age) #打印结果luffy 18
10.示例2, 现有如下代码, 会输出什么:
class People(object):
def __init__(self):
print("__init__")
def __new__(cls, *args, **kwargs):
print("__new__")
return object.__new__(cls, *args, **kwargs)
People()
__new__
__init__
#__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
11.请简单解释Python中 staticmethod(静态方法)和 classmethod(类方法), 并分别补充代码执行下列方法。
class A(object):
def foo(self, x):
print("executing foo(%s, %s)" % (self,x))
@classmethod
def class_foo(cls, x):
print("executing class_foo(%s, %s)" % (cls,x))
@staticmethod
def static_foo(x):
print("executing static_foo(%s)" % (x))
a = A()
#classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入
#classmethod,绑定到类的方法
a.class_foo('绑定到类') #输出结果:executing class_foo(, 绑定到类)
A.class_foo('绑定到类') #输出结果:executing class_foo(, 绑定到类)
#在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数,statimethod不与类或对象绑定,谁都可以调用,没有自动传值效果
#staticmethod 静态方法
a.static_foo('静态绑定') #输出结果:executing static_foo(静态绑定)
A.static_foo('静态绑定') #输出结果:executing static_foo(静态绑定)
12.请执行以下代码,解释错误原因,并修正错误。
class Dog(object):
def __init__(self,name):
self.name = name
@property
def eat(self):
print(" %s is eating" %self.name)
d = Dog("ChenRonghua")
d.eat()
d.eat()应该改为d.eat
@property使eat的接口发生了改变
13.下面这段代码的输出结果将是什么?请解释。
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
# 1 1 1 继承自父类的类属性x,所以都一样,指向同一块内存地址
# 1 2 1 更改Child1,Child1的x指向了新的内存地址
# 3 2 3 更改Parent,Parent的x指向了新的内存地址
14.多重继承的执行顺序,请解答以下输出结果是什么?并解释。
class A(object):
def __init__(self):
print('A')
super(A, self).__init__()
class B(object):
def __init__(self):
print('B')
super(B, self).__init__()
class C(A):
def __init__(self):
print('C')
super(C, self).__init__()
class D(A):
def __init__(self):
print('D')
super(D, self).__init__()
class E(B, C):
def __init__(self):
print('E')
super(E, self).__init__()
class F(C, B, D):
def __init__(self):
print('F')
super(F, self).__init__()
class G(D, B):
def __init__(self):
print('G')
super(G, self).__init__()
if __name__ == '__main__':
g = G()
f = F()
# G
# D
# A
# B
#
# F
# C
# B
# D
# A
15.请编写一段符合多态特性的代码.
class Cat(Animal): #属于动物的另外一种形态:猫
def talk(self):
print('say miao')
def func(animal): #对于使用者来说,自己的代码根本无需改动
animal.talk()
cat1=Cat() #实例出一只猫
func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
#say miao
17.请写一个小游戏,人狗大站,2个角色,人和狗,游戏开始后,生成2个人,3条狗,互相混战,人被狗咬了会掉血,狗被人打了也掉血,狗和人的攻击力,具备的功能都不一样。注意,请按题14领域建模的方式来设计类。
class Role(object):
def __init__(self,name):
self.name = name
def attack(self,enemy):
enemy.life_value-=self.agressivity
class People(Role):
agressivity = 10
life_value = 100
def __init__(self,name):
super().__init__(name)
class Dogs(Role):
agressivity = 15
life_value = 80
def __init__(self,name):
super().__init__(name)
p1 = People('Tom')
p2 = People('Jack')
d1 = Dogs('niker')
d2 = Dogs('geeker')
d3 = Dogs('chaox')
print(p1.agressivity)
print(p1.life_value)
p1.attack(d1)
print(d1.life_value)
18.编写程序, 在元类中控制把自定义类的数据属性都变成大写.
19.编写程序, 在元类中控制自定义的类无需init方法.
20.编写程序, 编写一个学生类, 要求有一个计数器的属性, 统计总共实例化了多少个学生.
class Student:
count = 0
@classmethod
def __init__(cls):
cls.count += 1
a1 = Student()
a2 = Student()
a3 = Student()
a4 = Student()
print(Student.count)
#输出4
21.编写程序, A 继承了 B, 俩个类都实现了 handle 方法, 在 A 中的 handle 方法中调用 B 的 handle 方法
class B:
def handle(self):
print('from B')
class A(B):
def handle(self):
super().handle()
a = A()
a.handle()
22.编写程序, 如下有三点要求:
- 自定义用户信息数据结构, 写入文件, 然后读取出内容, 利用json模块进行数据的序列化和反序列化
e.g
{
"egon":{"password":"123",'status':False,'timeout':0},
"alex":{"password":"456",'status':False,'timeout':0},
}
import json
eg={
"egon":{"password":"123",'status':False,'timeout':0},
"alex":{"password":"456",'status':False,'timeout':0},
}
with open('uesr_data.json', 'w', encoding='utf-8') as fp1:
json.dump(eg,fp1)
with open('uesr_data.json', 'r', encoding='utf-8') as fp2:
data = json.load(fp2)
print(data)
- 定义用户类,定义方法db,例如 执行obj.db可以拿到用户数据结构
import json
class User:
@property
def db(self):
with open('uesr_data.json', 'r', encoding='utf-8') as fp:
data = json.load(fp)
return data
obj = User()
print(obj.db)
- 在该类中实现登录、退出方法, 登录成功将状态(status)修改为True, 退出将状态修改为False(退出要判断是否处于登录状态).密码输入错误三次将设置锁定时间(下次登录如果和当前时间比较大于10秒即不允许登录).
import json
import time
import pathlib
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)
class User:
def __init__(self):
while True:
self.name = input('请输入用户名\n>>>:')
if not self.file_exist(base_dir):
print('输入的密码有误')
else:
break
self.data = self.db
def file_exist(self,path): # 通过判断指定路径下,以用户名命名的文件是否存在,来判断用户输入的用户正确
global file_path
file_name = 'db/%s.json' % self.name
file_path = os.path.join(path,file_name)
file_is = pathlib.Path(file_path)
file_result = file_is.is_file()
if file_result:
return file_path
else:
return False
@property
def db(self):
with open(file_path, 'r',encoding='utf-8') as file:
data = json.load(file)
return data
def login(self):
count = 0
while count < 3:
if self.data['timeout'] != 0:
if time.time() - self.db['timeout'] > 10:
print('不允许登录,时间超时!')
return False
with open(file_path,'r+',encoding='utf-8') as f:
count += 1
password = input('请输入密码\n>>>:')
if password != self.db['password']:
print('密码输入错误')
if count == 3:
self.data['timeout'] = time.time()
f.seek(0)
f.truncate()
json.dump(self.data, f)
continue
self.data['status'] = True
f.seek(0)
f.truncate()
json.dump(self.data,f)
print("--------welcome--------")
return True
def exit(self):
with open(file_path, 'r+', encoding="utf-8") as f:
data = json.load(f)
if data["status"]:
data["status"] = False
f.seek(0)
f.truncate()
json.dump(data, f)
else:
print("您现在处于退出状态")
user1 = User()
user1.login()
print(user1.__dict__)
user1.exit()