面向对象编程(练习题)

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、

编写程序, 如下有三点要求:

  1. 自定义用户信息数据结构, 写入文件, 然后读取出内容, 利用json模块进行数据的序列化和反序列化
    e.g
    {
        "egon":{"password":"123",'status':False,'timeout':0},
        "alex":{"password":"456",'status':False,'timeout':0},
    }

     

  1. 定义用户类,定义方法db,例如 执行obj.db可以拿到用户数据结构
  2. 在该类中实现登录、退出方法, 登录成功将状态(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: 文件已存在

本章作业

题目:选课系统开发,要求有四种角色:学校、学员、课程、讲师

详细要求:

  1. 创建北京、上海 2 所学校

  2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开

  3. 课程包含,周期,价格,通过学校创建课程

  4. 通过学校创建班级, 班级关联课程、讲师

  5. 创建学员时,选择学校,关联班级

  6. 创建讲师角色时要关联学校

  7. 提供两个角色接口

  8. 为学员、讲师、管理员分别提供用户界面,并提供对应功能: 1 学员视图, 可以注册, 交学费, 选择班级, 2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩 3 管理视图,创建讲师, 创建班级,创建课程

注1:上面的操作产生的数据都通过pickle序列化保存到文件里 注2:此作业必须画流程图,图中标注好不同类或对象之间的调用关系



posted @ 2018-05-10 17:02  SmallNine  阅读(2221)  评论(0编辑  收藏  举报