1,面向对象三大特性,各有什么用处,说说你的理解。
继承:解决代码重用问题
多态:多态性,可以在不考虑对象类型的情况下而直接使用对象
封装:明确的区分内外,控制外部对隐藏属性的操作行为,隔离复杂度
2,类的属性和对象的属性有什么区别?
类的属性:数据属性和函数属性,数据属性是所有对象共有的,函数属性是绑定对象使用的
对象的属性:对象是类的实例化
# 举例说明
class Employee(object):
emCount=0
def __init__(self,name,salary):
self.nane=name
self.salary=salary
类属性就是定义类的时候直接定义的属性 emCount,类似于java里面的static修饰的属性,
可以直接通过 类名.属性名访问:Employee.emCount 在程序中对象和类是共用一块内存地址的
实例属性是在__init__()方法中定义的属性,例如name,和salary,self是指向自己的,
类似java的this关键字,实际是通过内置的方法__setattr__()完成的
可以通过重写__setatttr__()进行类属性的增加和获取
3,面向过程编程与面向对象编程的区别与应用场景?
面向过程:复杂的问题流程化,简单化
应用场景:不再需要扩展了,监测脚本,自动部署脚本,软件解压安装
面向对象:特征与技能的结合体 一切皆对象
应用场景:用户需求经常变化,互联网应用,游戏,企业内部应用
4,类和对象在内存中是如何保存的。
类和对象的属性:以字典的形式保存的
cls(*args).__dict__
5,什么是绑定到对象的方法、绑定到类的方法、解除绑定的函数、如何定义,如何调用,给谁用?有什么特性
绑定到对象的方法:就应该由对象来调用,
def tell_info(self):
...
obj.tell_info()
绑定到类的方法:就应该由类来调用,
@classmethod
def from_conf(cls):
...
class.from_conf()
非绑定方法:不与类或对象绑定,谁都可以调用,
@staticmethod
def create_id():
...
obj.create_id()/class.create_id()
6,使用实例进行 获取、设置、删除 数据, 分别会触发类的什么私有方法
class A(object):
pass
a = A()
a["key"] = "val"
a = a["key"]
del a["key"]
解答:
class A:
def __setitem__(self, key, value):
self.__dict__[key] = value
def __getitem__(self, item):
# return self.__dict__[item]
return self.__dict__.get(item)
def __delitem__(self, key):
del self.__dict__[key]
a = A()
a["key"] = "val"
print(a.__dict__)
# a = a["key"]
# print(a)
del a["key"]
print(a.__dict__)
# 将构造方法变成字典形式
# 使用的是内置方法
7,python中经典类和新式类的区别
经典类:py2 没有继承object的类,以及它的子类都称之为经典类 --> 深度优先
新式类:py3 继承object的类,以及它的子类都称之为新式类 -->广度优先
8,如下示例, 请用面向对象的形式优化以下代码
在没有学习类这个概念时,数据与功能是分离的
def exc1(host,port,db,charset,sql):
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:
def __init__(self, host, port, db, charset):
self.host = host
self.port = port
self.db = db
self.charset = charset
def execute(self, sql):
print(sql)
return sql
def call_proc(self, proc_name):
print(proc_name)
return proc_name
# 每次调用都需要重复传入一堆参数
exc = Exc('127.0.0.1', 3306, 'db1', 'utf8')
exc.execute('select * from tb1;')
exc.call_proc('存储过程的名字')
9,示例1, 现有如下代码, 会输出什么:
class People(object):
__name = "luffy"
__age = 18
p1 = People()
print(p1.__name, p1.__age)
解答:
# 执行语句print(p1.__name, p1.__age)会报错
# 报错内容:AttributeError: 'People' object has no attribute '__name'
# 原因
print(p1.__dict__) # {}
print(People.__dict__)
# {'__module__': '__main__', '_People__name': 'luffy',
# '_People__age': 18, '__dict__': <attribute '__dict__' of 'People' objects>,
# '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
# 想要正确的调用方法,不过既然设置成了隐藏变量就不要这样调用
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__
11,请简单解释Python中 staticmethod(静态方法)和 classmethod(类方法), 并分别补充代码执行下列方法。
#静态方法:非绑定方法,类和对象都可以调用
#类方法:绑定给类的方法啊,类调用
class A:
def __init__(self, name):
self.name = name
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('alice')
a.foo('AAA')
A.class_foo('BBB')
a.static_foo('CCC')
A.static_foo('DDD')
# 结果
# executing foo(<__main__.A object at 0x00000000024682E8>, AAA)
# executing class_foo(<class '__main__.A'>, BBB)
# executing static_foo(CCC)
# executing static_foo(DDD)
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()
#报错内容:
"""
Traceback (most recent call last):
File "D:/py.py", line 27, in <module>
d.eat()
TypeError: 'NoneType' object is not callable
"""
# 改正如下:
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
# 错误原因:@property可以将函数属性转化为数据属性
# 因为有了property,用户就可以直接输入得到结果,对于使用者来说,感知不到其属性,这就是使用property的方便之处,此方法必须有一个返回值。return 或者print都可以。
# 为什么要用property?
# 一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式 遵循了统一访问的原则
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,多重继承的执行顺序,请解答以下输出结果是什么?并解释。
super()表示的是 子类的mro()列表中的下一个
print(G.mro())
[<class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
print(F.mro())
[<class '__main__.F'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
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 Animal:
def __init__(self, name):
self.name = name
class People(Animal):
def talk(self):
print('%s is talking' % self.name)
class Dog(Animal):
def talk(self):
print('%s is talking' % self.name)
def func(animal):
animal.talk()
# 函数等同于下面
# p=People('alice')
# d=Dog('wang')
# func(p)
# func(d)
# 结果
'''
alice is talking
wang is talking
'''
# 在python中的多态可以等同于鸭子类型
# 在上面例子中,只要有talk这个方法,不需要关心是Dog还是People
16,很多同学都是学会了面向对象的语法,却依然写不出面向对象的程序,原因是什么呢?原因就是因为你还没掌握一门面向对象设计利器,即领域建模,请解释下什么是领域建模,以及如何通过其设计面向对象的程序? http://www.cnblogs.com/alex3714/articles/5188179.html 此blog最后面有详解
领域模型,顾名思义,就是需求所涉及的领域的一个建模,更通俗的讲法是业务模型。
定义:
需求到面向对象的桥梁
作用:
1.发掘重要的业务领域概念
2.建立业务领域概念之间的关系
方法:
从用例中找名词
领域建模的三字经方法:找名词、加属性、连关系。
参考:http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label15
http://www.cnblogs.com/linhaifeng/articles/7341318.html
17,请写一个小游戏,人狗大站,2个角色,人和狗,游戏开始后,生成2个人,3条狗,互相混战,人被狗咬了会掉血,狗被人打了也掉血,狗和人的攻击力,具备的功能都不一样。注意,请按题14领域建模的方式来设计类。
class Animal:
def __init__(self, name, life_value, aggressivity):
self.name = name
self.life_value = life_value
self.aggressivity = aggressivity
def attack(self, enemy):
enemy.life_value -= self.aggressivity
class People(Animal):
camp = 'home'
def attack(self, enemy):
super().attack(enemy)
print('from people')
class Dog(Animal):
camp = 'wo'
def attack(self, enemy):
super().attack(enemy)
print('from dog')
p1 = People('alice', 80, 30)
p1 = People('alex', 80, 30)
d1 = Dog('w1', 90, 50)
d2 = Dog('w2', 90, 50)
d3 = Dog('w3', 90, 50)
print(p1.life_value)
d1.attack(p1)
print(p1.life_value)
print(d1.life_value)
p1.attack(d1)
print(d1.life_value)
# 结果
# 80
# from dog
# 30
# 90
# from people
# 60
18,编写程序, 在元类中控制把自定义类的数据属性都变成大写.
19,编写程序, 在元类中控制自定义的类无需init方法.
class Mymeta(type):
def __new__(cls,class_name,class_bases,class_dic):
update_dic = {}
for i in class_dic:
if not callable(class_dic[i]) and not i.startswith('__'):
update_dic[i.upper()]=class_dic[i]
else:
update_dic[i]=class_dic[i]
return type.__new__(cls,class_name,class_bases,update_dic)
def __call__(self, *args, **kwargs):
obj=object.__new__(self)
if args:
raise TypeError('must be keyword argument')
for i in kwargs:
obj.__dict__[i]=kwargs[i]
return obj
class Chinese(metaclass=Mymeta):
country='china'
tag='legend of the dragon'
def talk(self):
print('%s is talking'%self.name)
# print(Chinese.__dict__)
# ch=Chinese(name='alice',age=18)
# ch.talk()
# print(ch.__dict__)
20,编写程序, 编写一个学生类, 要求有一个计数器的属性, 统计总共实例化了多少个学生.
class Student:
count = 0
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
Student.count += 1
def learn(self):
print("%s is learning" % self.name)
stu1 = Student('james', 'male', 32)
print(stu1.count)
print(stu1.__dict__)
stu2 = Student('enbede', 'male', 23)
print(stu2.count)
print(stu2.__dict__)
print(Student.count)
print(Student.__dict__)
# 结果
# 1
# {'age': 32, 'name': 'james', 'sex': 'male'}
# 2
# {'age': 23, 'name': 'enbede', 'sex': 'male'}
# 2
# {'__weakref__': <attribute '__weakref__' of 'Student' objects>, 'count': 2, '__dict__': <attribute '__dict__' of 'Student' objects>, 'learn': <function Student.learn at 0x000000000A440C80>, '__init__': <function Student.__init__ at 0x000000000273C598>, '__doc__': None, '__module__': '__main__'}
21,编写程序, A 继承了 B, 俩个类都实现了 handle 方法, 在 A 中的 handle 方法中调用 B 的 handle 方法
class B:
def handle(self):
print('from B handle')
class A(B):
def handle(self):
super().handle()
print('from A handle')
a = A()
a.handle()
22,编写程序, 如下有三点要求:
自定义用户信息数据结构, 写入文件, 然后读取出内容, 利用json模块进行数据的序列化和反序列化
定义用户类,定义方法db,例如 执行obj.db可以拿到用户数据结构
在该类中实现登录、退出方法, 登录成功将状态(status)修改为True, 退出将状态修改为False(退出要判断是否处于登录状态).密码输入错误三次将设置锁定时间(下次登录如果和当前时间比较大于10秒即不允许登录)
import json
import time
class User:
def __init__(self, name, password):
self.name = name
self.password = password
self.status = False
self.timeout = 0
@property
def db(self):
with open(self.name+'.txt', 'r', encoding='utf-8') as f:
data = json.load(f)
return data
def save(self):
obj={}
obj[self.name]={'password':self.password,'status':self.status,'timeout':self.timeout}
with open(self.name+'.txt', 'w', encoding='utf-8') as f:
json.dump(obj,f)
def login(self):
with open(self.name+'.txt', 'r+', encoding='utf-8') as f:
data = json.load(f)
count = 0
while count < 3:
password = input('password>>:').strip()
if password != data[self.name]['password']:
count += 1
continue
else:
if data[self.name]['timeout'] != 0:
if time.time() - data[self.name]['timeout'] > 10:
print('不允许登录了!超时')
break
else:
data[self.name]['status'] = True
f.seek(0)
f.truncate()
json.dump(data, f)
print('----welcome----')
break
else:
data[self.name]['status'] = True
f.seek(0)
f.truncate()
json.dump(data, f)
print('----welcome----')
break
else:
data[self.name]['timeout']=time.time()
f.seek(0)
f.truncate()
json.dump(data,f)
def quit(self):
with open(self.name+'.txt', 'r+', encoding='utf-8') as f:
data = json.load(f)
if data[self.name]['status'] == True:
data[self.name]['status'] = False
f.seek(0)
f.truncate()
json.dump(data, f)
else:
print('您是退出状态!')
# alex=User('alex','123')
# egon=User('egon','456')
# # alex.save()
# # egon.save()
# # print(alex.db)
# # print(egon.db)
# # alex.login()
# alex.quit()
# # egon.quit()
# print(alex.db)
# print(egon.db)
# alex.login()
# egon.login()
23,用面向对象的形式编写一个老师角色, 并实现以下功能, 获取老师列表, 创建老师、删除老师、创建成功之后通过 pickle 序列化保存到文件里,并在下一次重启程序时能读取到创建的老师, 例如程序目录结构如下.
|-- bin/
| |-- main.py 程序运行主体程序(可进行菜单选择等)
|-- config/
| |-- settings.py 程序配置(例如: 配置存储创建老师的路径相关等)
|-- db 数据存储(持久化, 使得每次再重启程序时, 相关数据对应保留)
| |-- teachers/ 存储所有老师的文件
| |-- ... ...
|-- src/ 程序主体模块存放
| |-- __init__.py
| |-- teacher.py 例如: 实现老师相关功能的文件
| |-- group.py 例如: 实现班级相关的功能的文件
|-- manage.py 程序启动文件
|-- README.md 程序说明文件
24,根据23 题, 再编写一个班级类, 实现以下功能, 创建班级, 删除班级, 获取班级列表、创建成功之后通过 pickle 序列化保存到文件里,并在下一次重启程序时能读取到创建的班级.
25,根据 23题, 编写课程类, 实现以下功能, 创建课程(创建要求如上), 删除课程, 获取课程列表
26,根据23 题, 编写学校类, 实现以下功能, 创建学校, 删除学校, 获取学校列表
27,通过23题, 它们雷同的功能, 是否可以通过继承的方式进行一些优化
伪代码
class Behavior(object):
def fetch(self, keyword):
通过 keyword 参数 查询出对应的数据列表
class School(Behavior):
pass
class Teacher(Behavior):
pass
s = School()
t = Teacher()
s.fetch("school")
t.fetch("teacher")
28:编写一个学生类,产生一堆学生对象
要求:有一个计数器(属性),统计总共实例了多少个对象
class Studentclass:
school = 'jiaotong university'
count = 0
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex =sex
Studentclass.count +=1
def learn(self):
print('%s is learning'%self.name)
stu1 = Studentclass('james',23,'male')
stu2 = Studentclass('poal',24,'male')
stu3 = Studentclass('harden',25,'male')
print(Studentclass.count)
print(stu1.__dict__)
print(stu2.__dict__)
print(stu3.__dict__)
print(stu1.count)
print(stu2.count)
print(stu3.count)
29:模仿王者荣耀定义两个英雄类
要求:
英雄需要有昵称、攻击力、生命值等属性;
实例化出两个英雄对象;
英雄之间可以互殴,被殴打的一方掉血,血量小于0则判定为死亡。
class Hero:
def __init__(self,nickname,life_value,aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
def attack(self,enemy):
enemy.life_value -= self.aggresivity
class Garen(Hero):
pass
class Riven(Hero):
pass
g1=Garen('草丛论',100,20)
r1 = Riven('放逐之刃',80,50)
print(r1.life_value)
g1.attack(r1)
print(r1.life_value)