1、面向对象三大特性,各有什么用处,说说你的理解
继承:解决代码重用
多态:不考虑对象类型的情况下直接使用对象
封装:明确的区分内外,控制外部对隐藏属性进行操作,隔离复杂度
2、 类的属性和对象的属性有什么区别?
类的属性:数据属性,和函数属性,函数绑定给对象使用
对象的属性:对象就是实例化的类
3、面向过程编程与面向对象编程的区别与应用场景?
面向过程:复杂的问题简单化,但是可扩展性差,主要用于,脚本,自动部署,监控等等
面向对象:对比之下更为复杂,扩展能力强,一切皆对象,主要用于,程序开发,游戏等等
4、类和对象在内存中是如何保存的。
以 dict的形式保存正在内存中
5、什么是绑定到对象的方法、绑定到类的方法、解除绑定的函数、如何定义,如何调用,给谁用?有什么特性
绑定对象: f1=Foo()#生成对象 foo.func#绑定到对象,绑定到对象之后将会自动传值给func
绑定到类:就是由类来调用,在需要绑定的函数添加装饰器 @classmethod
非绑定方法: 不与类或对象绑定,谁都可以调用 ,需要按正常函数传参,需要在非绑定函数添加装饰器 @staticmethod
6、使用实例进行 获取、设置、删除 数据, 分别会触发类的什么私有方法
# item系列就是为了把对象模拟成像字典一样,就可以像字典一样访问 class A(object): def __getitem__(self, item): return self.__dict__.get(item)#这里用get进行访问,值不存在也不会报错 def __setitem__(self, key, value): self.__dict__[key] = value #其他方法与字典使用相同 def __delitem__(self, key): del self.__dict__[key] a = A() a['key'] = "val" print(a.__dict__) # {'key': 'val'} b = a["key"] print(b) # val del a["key"] print(a.__dict__) # {} #输出 {'key': 'val'} val {}
7、python中经典类和新式类的区别
经典类:在python2中,没有继承object的类,以及子类都称之为经典类,继承查找方式为 深度优先。
#python2 中定义
class A:#经典类 pass class B(object):#新式类 pass
新式类:python3中,全部为新式类,继承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 Sql: host= '127.0.0.1' port=3306 db='db1' charset='utf8' sql='select * from tb1;' proc_name='存储过程的名字' def __init__(self,*args): self.args=args def connect(self): pass def exc(self): if self.args == self.sql: conn = self.connect(self.host,self.port,self.db,self.charset) res=conn.execute(self.sql) return res elif self.args == self.proc_name: conn = self.connect(self.host, self.port, self.db, self.charset, self.proc_name) res = conn.call_proc(self.sql) return res ex=Sql('select * from tb1;') print(ex.__dict__) #输出 {'args': ('select * from tb1;',)}
9、示例1, 现有如下代码, 会输出什么:
class People(object): __name = "luffy" __age = 18 p1 = People() print(p1.__name, p1.__age)
会抛出错误,因为__name及__age,隐藏了所以不能直接调用,__开头在类执行的时候已经将属性名称更改为'_People__name',
10、示例2, 现有如下代码, 会输出什么:
class People(object): def __init__(self): print("__init__") def __new__(cls, *args, **kwargs): print("__new__") return object.__new__(cls, *args, **kwargs)
# __new__
# __init__
因为__new__ 会在__init__前执行
new: 对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
init : 对象的初始化, 是一个实例方法,第一个参数是self。
call : 对象可call,注意不是类,是对象。
先有创建,才有初始化。即先new,而后init。
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()
class A(object): 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('mlliu') a.foo('xiaojiu') A.class_foo('xiaojiu') a.static_foo('xiaojiu') #@classmethod 绑定类,自动传值 #@staticmethod 不绑定类或者对象,普通func,正常传值 #输出 executing foo(<__main__.A object at 0x000001A2DC5375F8>, xiaojiu) executing class_foo(<class '__main__.A'>, xiaojiu) executing static_foo(xiaojiu)
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()
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 #输出 ChenRonghua is eating #因为@property是自动执行函数,所以在最后调用该方法的时候,不需要加后面的()
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)
#111
#121
#323
使用mro()可以看出类的继承顺序,[<class '__main__.Child1'>, <class '__main__.Parent'>, <class 'object'>]
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
新式类广度优先,super不管当前类的继承关系,会按照实例化的类的MRO列表,一直往后找。
[<class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
[<class '__main__.F'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
15、请编写一段符合多态特性的代码
import abc class Student(metaclass=abc.ABCMeta): @abc.abstractmethod #抽象类 def height(self): pass class Xiaoming(Student): @property def height(self): print('185') class Zhangsan(Student): @property def height(self): print('176') p1 =Zhangsan() p1.height p2 =Xiaoming() p2.height #输出 176 185
#多态的好处是你不用管他是什么类型都用同样的方式去调用他
16、很多同学都是学会了面向对象的语法,却依然写不出面向对象的程序,原因是什么呢?原因就是因为你还没掌握一门面向对象设计利器,即领域建模,请解释下什么是领域建模,以及如何通过其设计面向对象的程序?http://www.cnblogs.com/alex3714/articles/5188179.html 此blog最后面有详解
领域建模的三字经方法:找名词、加属性、连关系。
17、请写一个小游戏,人狗大站,2个角色,人和狗,游戏开始后,生成2个人,3条狗,互相混战,人被狗咬了会掉血,狗被人打了也掉血,狗和人的攻击力,具备的功能都不一样。注意,请按题领域建模的方式来设计类。
名词:人、狗、血、攻击力、武器、
加属性:
人:血、攻击力、武器
狗:血、攻击力、武器
class Role: def __init__(self,name,hp,ad): self.name=name self.hp=hp self.ad=ad def attack(self,obj): obj.hp -= self.ad class People(Role): def attack(self,obj): super().attack(obj) print('%s attack %s'%(self.name,obj.name)) class Dog(Role): def attack(self,obj): super().attack(obj) print('%s attack %s'%(self.name,obj.name)) p1=People ('张三',100,20) p2=People('李四',120,25) d1=Dog('二哈',200,10) d2=Dog('三哈',210,9) d3=Dog('三哈',220,8) p1.attack(d1) print(d1.hp) d1.attack(p1) print(p1.hp) d3.attack(p1) print(p1.hp) #输出 张三 attack 二哈 180 二哈 attack 张三 90 三哈 attack 张三 82
18、编写程序, 在元类中控制把自定义类的数据属性都变成大写.
class Mymetaclass(type): def __new__(cls,name,bases,attrs): update_attrs={} for k,v in attrs.items(): if not callable(v) and not k.startswith('__'): update_attrs[k.upper()]=v else: update_attrs[k]=v return type.__new__(cls,name,bases,update_attrs) class Chinese(metaclass=Mymetaclass): country='China' tag='Legend of the Dragon' #龙的传人 def walk(self): print('%s is walking' %self.name) print(Chinese.__dict__) #输出 {'__module__': '__main__', 'COUNTRY': 'China', 'TAG': 'Legend of the Dragon', 'walk': <function Chinese.walk at 0x000001EAF1E25730>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}
19、编写程序, 在元类中控制自定义的类无需init方法.
class Mymetaclass(type): def __call__(self, *args, **kwargs): # if args: # raise TypeError('must use keyword argument for key function') obj = object.__new__(self) #创建对象,self为类Foo for k,v in kwargs.items(): obj.__dict__[k.upper()]=v return obj class Chinese(metaclass=Mymetaclass): country='China' tag='Legend of the Dragon' #龙的传人 def walk(self): print('%s is walking' %self.name) p=Chinese(name='egon',age=18,sex='male') print(p.__dict__) #输出 <__main__.Chinese object at 0x000002E5068A7358> {'NAME': 'egon', 'AGE': 18, 'SEX': 'male'}
20、编写程序, 编写一个学生类, 要求有一个计数器的属性, 统计总共实例化了多少个学生.
class Student: count =0 def __init__(self,name,age): self.name=name self.age=age Student.count +=1 stu1=Student('zhangsan',17) stu2=Student('lisi',17) stu3=Student('xiaohua',17) print(Student.count) #输出 3
21、编写程序, A 继承了 B, 俩个类都实现了 handle 方法, 在 A 中的 handle 方法中调用 B 的 handle 方法
class B: def handle(self): print('form is B') class A(B): @property def handle(self): super().handle() print('form is A') a=A() a.handle #输出 form is B form is A
22、
编写程序, 如下有三点要求:
- 自定义用户信息数据结构, 写入文件, 然后读取出内容, 利用json模块进行数据的序列化和反序列化
e.g { "egon":{"password":"123",'status':False,'timeout':0}, "alex":{"password":"456",'status':False,'timeout':0}, }
- 定义用户类,定义方法db,例如 执行obj.db可以拿到用户数据结构
- 在该类中实现登录、退出方法, 登录成功将状态(status)修改为True, 退出将状态修改为False(退出要判断是否处于登录状态).密码输入错误三次将设置锁定时间(下次登录如果和当前时间比较大于10秒即不允许登录)
#!/usr/bin/env python # -*- coding:utf-8 -*- import json import time info_dic = { "egon":{"password":"123",'status':False,'timeout':0}, "alex":{"password":"456",'status':False,'timeout':0}, } class User: def __init__(self): self.file_name = 'info.json' self.fn_load = open(self.file_name, 'r+', encoding='utf-8') self.read_info = json.load(self.fn_load) count = 0 while count<3: self.name = input('name').strip() self.password = input('password').strip() if self.read_info.get(self.name) and self.read_info[self.name]['password'] == self.password : if time.mktime(time.localtime()) - self.read_info[self.name]['timeout'] > 10: print('登陆成功') self.read_info[self.name]['status'] = 'True' self.read_info[self.name]['timeout'] = (time.mktime(time.localtime())) return else: print('与上一次登陆间隔{}秒,过于频繁禁止登陆'.format(time.mktime(time.localtime()) - self.read_info[self.name]['timeout'])) count =3 else: count += 1 print('用户名或密码不正确,请重新输入') continue else: raise KeyError('登陆失败') @property def db(self): print(self.read_info[self.name]) return self.read_info def exit(self): self.read_info[self.name]['status'] = 'False' self.fn_load.seek(0) json.dump(self.read_info,self.fn_load) self.fn_load.close() p1=User() p1.db p1.exit() # p2=User() # p2.db #输出 nameegon password123 登陆成功 {'password': '123', 'status': 'True', 'timeout': 1526121027.0}
定义MySQL类
要求:
1.对象有id、host、port三个属性
2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一
3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化
4.为对象定制方法,save和get_obj_by_id,save能自动将对象序列化到文件中,文件路径为配置文件中DB_PATH,文件名为id号,保存之前验证对象是否已经存在,若存在则抛出异常,;get_obj_by_id方法用来从文件中反序列化出对象
# -*- coding: utf-8 -*-
import time
import hashlib
import json
import time
import sys
import os
FILE = 'user_info.json'
def user():
return json.load(open(FILE))
user_info = user()
class Mysql:
def __init__(self,host,port):
self.host = host
self.port = port
self.id = Mysql.create_id(self)
def create_id(self):
m = hashlib.md5(str(time.clock()).encode('utf-8'))
self.id = m.hexdigest()
return m.hexdigest()
def save(self):
for root, dirs, files in os.walk(os.path.dirname(__file__)):
if self.id in files:
raise FileNotFoundError('文件已存在')
json.dump(self.__dict__,open(self.id,'w',encoding='utf-8'))
def get_obj_by_id(self,id):
dic1 = json.load(open(id))
print(dic1)
stu1 = Mysql('127.0.0.1',3306)
print(stu1.id,stu1.host,stu1.port)
stu1.get_obj_by_id('f0fbad80768437dfabc5050e0ebd4504')
stu1.save()
stu2 = Mysql(user_info['host'],user_info['port'])#
print(stu2.id,stu2.host,stu2.port)
stu2.save()
#输出
Traceback (most recent call last):
30565a8911a6bb487e3745c0ea3c8224 127.0.0.1 3306
File "G:/python练习/网络编程/class_练习题.py", line 36, in <module>
stu1.save()
{'host': '127.0.0.1', 'port': 3306, 'id': 'f0fbad80768437dfabc5050e0ebd4504'}
File "G:/python练习/网络编程/class_练习题.py", line 26, in save
raise FileNotFoundError('文件已存在')
FileNotFoundError: 文件已存在
本章作业
题目:选课系统开发,要求有四种角色:学校、学员、课程、讲师
详细要求:
-
创建北京、上海 2 所学校
-
创建linux , python , go 3个课程 , linuxpy 在北京开, go 在上海开
-
课程包含,周期,价格,通过学校创建课程
-
通过学校创建班级, 班级关联课程、讲师
-
创建学员时,选择学校,关联班级
-
创建讲师角色时要关联学校
-
提供两个角色接口
-
为学员、讲师、管理员分别提供用户界面,并提供对应功能: 1 学员视图, 可以注册, 交学费, 选择班级, 2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩 3 管理视图,创建讲师, 创建班级,创建课程
注1:上面的操作产生的数据都通过pickle序列化保存到文件里 注2:此作业必须画流程图,图中标注好不同类或对象之间的调用关系