Summary
面向对象编程(概念,构造函数 __init__()[创建实例对象并将其初始化],实例对象,实例属性,实例方法,类属性,类方法,静态方法<4>,__del__析构方法,__call__()方法<5>,方法没有重载<6>,方法的动态性<7>,面向对象的三大特征[封装,继承,多态]<8>,私有属性和私有方法(封装)<9>,@property装饰器(get方法),set方法<10>,继承<11>,多重继承<11>,方法重写<12>,查看继承层次结构<12><14>,重写__str__()方法<13>,super()获得父类的定义<15>,多态<16>,特殊方法和特殊属性<17>,变量赋值<18>,对象的浅拷贝和深拷贝<18>,组合<18>,单例模式和工厂模式<19>)
Questions
1.Python支持哪三种编程方式?
2.面向对象(object oriented)和面向过程(procedure oriented)的适用范围是什么?
3.什么是对象?什么是类?类和对象是什么关系?
4.给定以下代码
代码1
class student:
def __init__(self, name, score): #初始化创建的对象
self.name = name #实例属性,初始化指的是给实例属性赋值
self.score = score #实例属性从属于实例对象的属性
def say_score(self):
print("{0}的分数是:{1}".format(self.name, self.score))
s1 = student("santa", 99) #通过类名()调用构造函数
s1.say_score()
s1.age = 25 #可以通过obj.实例属性名的方法添加新属性
s1.salary = 99000
print("santa的薪资是{0}".format(s1.salary))
s2 = student("nanako", 97)
s2.say_score()
class man:
pass #空语句
print(dir(s2)) #获得对象的所有属性和方法
print(s2.__dict__) #获得对象的属性字典
print(isinstance(s2, man)) #判断s2是否属于类对象man
输出结果
santa的分数是:99
santa的薪资是99000
nanako的分数是:97
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'say_score', 'score']
{'name': 'nanako', 'score': 97}
False
(1)Python对象有哪些组成部分;(2)__new__()和 __init__()代表什么?(3)构造函数的写法是什么?通常起到什么作用?有没有返回值?构造函数第一个参数是什么?有什么含义?如何调用构造函数?(4)示例属性如何定义?在其他实例方法中,如何访问实例属性?如何通过实例对象访问实例属性?(5)实例方法的定义和格式是什么?需要给self传参吗?上述代码中s1.say_score()在解释器中是怎样翻译的?
代码2
class student:
company = "santates.corp" #类属性
count = 0 #类属性
def __init__(self, name, score):
self.name = name #实例属性
self.score = score #实例属性
student.count = student.count + 1
def say_score(self): #实例方法
print('我的公司是:', student.company)
print(self.name, '的分数是:', self.score)
s1 = student("santa", 99)
s1.say_score()
print('一共创建{0}个对象'.format(student.count))
(6)什么时候会创建类对象?类属性是从属于什么的属性?可以被实例对象共享吗?类属性的定义方式是什么?通过什么格式来读写?分析上面的代码,画出内存分析图,标注出类属性
代码3
class student:
company = "santates.corp"
def __init__(self, name, score):
self.name = name
self.score = score
@classmethod
def printCompany(cls):
print(cls.company)
student.printCompany()
s1 = student('santa', 99)
s1.printCompany()
输出结果
santates.corp
santates.corp
(7)类方法从属于什么?定义的格式是什么?调用类方法的格式是什么?类方法中访问实例属性和实例方法会怎么样?
代码4
class student2:
def __init__(self, name, score):
self.name = name
self.score = score
@staticmethod
def add(a, b):
print('{0} + {1} = {2}'.format(a, b, a + b))
s2 = student2("nanako", 97)
s2.add(10, 30)
(8)静态方法与普通函数的区别在哪里?格式是什么?静态方法中访问实例属性和实例方法会怎么样?
5.分析下列代码并回答问题
代码1
class person:
def __del__(self):
print('销毁对象:{0}'.format(self))
p1 = person()
p2 = person()
del p2
print('程序结束')
(1)说出代码的输出结果;(2)对象在什么情况下,垃圾回收器会调用__del__方法;(3)可以使用什么语句删除对象,保证调用__del__方法;
代码2
class salary_accout:
def __call__(self, salary):
print("计算工资")
year_salary = salary * 12
return print(year_salary)
s = salary_accout()
s(10000)
(4)说出代码的执行结果?并说明什么是可调用对象?
6.如果定义了多个重名的方法,在python中会怎样?
7.说出下列代码的输出结果
class test:
def test1(self):
print("aaa")
def test2(s):
print("bbb")
def test3(s):
print('ccc')
test.extra = test2
test.test1 = test3
a = test()
#编译器的翻译:test.extra(a),相当于test2(a)
a.extra()
#可以修改原有的方法
a.test1()
8.简要地叙述面向对象三大特征的概念
9.按照要求改写代码
(1)
代码1
class employee:
def __init__(self, name, age):
self.name = name
self.age = age
e = employee('santa', 18)
print(e.name)
print(e.age)
输出结果
santa
18
将代码1中employee方法的age属性改为私有属性并访问
回答问题:通常两个下划线开头的属性是()的,其他是()的;类内部[可以/不可以]访问私有属性;类外部[可以/不可以]直接访问私有属性/方法,可以通过()访问私有属性/方法;方法本质上也是()
(2)
代码2
class employee:
company = 'santates.corp'
def __init__(self, name, age):
self.name = name
self.__age = age
def work(self):
print("aaa")
e = employee('santa', 18)
e.work()
print(e.company)
输出结果
aaa
santates.corp
将上面代码中的类方法和work方法改为私有方法并访问
10.按照要求改写下面的代码
class employee:
def __init__(self, name, salary):
self.__name = name
self.__salary = salary
def get_salary(self):
return self.__salary
def set_salary(self, salary):
if salary >= 0:
self.__salary = salary
else:
print("录入错误")
s1 = employee('santa', 10000)
print(s1.get_salary())
s1.set_salary(20000)
print(s1.get_salary())
s1.set_salary(-100)
输出结果
10000
20000
录入错误
使用@property和@salary.setter方法改写上面的代码
11.按照要求写代码
(1)给定如下代码:
class person:
def __init__(self, name, age):
self.name = name
self.__age = age
def say_score:
print("I don't know")
设定一个子类student,将person作为父类,并得到以下的结果
输出结果
I don't know
santa
25
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_person__age', 'name', 'say_score', 'score']
回答以下问题:python是否支持多重继承,语法格式是什么?如果没有指定父类,默认父类是什么?定义子类时,需要在构造函数中调用父类的构造函数,格式是什么?
(2)多重继承:说出下列代码的结果(ps.应该避免使用多重继承)
class A:
def aa(self):
print('aa')
class B:
def bb(self):
print('bb')
class C(B,A):
def cc(self):
print('cc')
c = C()
c.aa()
c.bb()
c.cc()
12.按照要求修改代码
给定如下代码
class person:
def __init__(self, name, age):
self.name = name
self.__age = age
def say_score:
print("I don't know")
将person作为父类,构造一个名为student的子类,并重写say_score方法,调用student的say_score方法时,输出"my score is 150."最后查看student的继承层次结构和实例对象s1的所有属性
输出结果
my score is 150.
[<class '__main__.student'>, <class '__main__.person'>, <class 'object'>]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_person__age', 'name', 'say_score']
13.说出下列代码的执行结果
代码1
class person:
def __init__(self, name):
self.name = name
p = person('santa')
print(p)
代码2
class person:
def __init__(self, name):
self.name = name
def __str__(self):
return 'my name is {0}'.format(self.name)
p = person('santa')
print(p)
14.说出下列代码的执行结果
代码1
class A:
def aa(self):
print('aa')
def say(self):
print('AAA')
class B:
def bb(self):
print('bb')
def say(self):
print('BBB')
class C(B,A):
def cc(self):
print('cc')
c = C()
c.say()
print(C.mro())
代码2
class A:
def aa(self):
print('aa')
def say(self):
print('AAA')
class B:
def bb(self):
print('bb')
def say(self):
print('BBB')
class C(A, B):
def cc(self):
print('cc')
c = C()
c.say()
print(C.mro())
15.使用super()写出输出结果相同的代码
class A:
def say(self):
print('A:', self)
class B(A):
def say(self):
A.say(self)
print('B:', self)
B().say()
输出结果
A: <__main__.B object at 0x000001FF6E1CE940>
B: <__main__.B object at 0x000001FF6E1CE940>
16.多态是什么?并说出以下代码的结果
class man:
def eat(self):
print("吃饭")
class Chinese(man):
def eat(self):
print("用筷子")
class European(man):
def eat(self):
print("用刀叉")
def maneat(m):
if isinstance(m, man):
m.eat()
else:
print('不能吃饭')
maneat(Chinese())
maneat(European())
17.一些常见的符号,例如"+,-,*,/“实际上是特殊方法,例如”+"就是__add__()方法,观察以下代码,通过改写__add__()实现字符串的相加,并输出对象p1的
class person:
def __init__(self, name):
self.name = name
#此处需要补充代码
p1 = person('santa')
p2 = person('kokoro')
print(p1 + p2) #相当于p1.__add__(p2)
输出结果
santa--kokoro
回答问题:python对象中包含了很多双下划线开始和结束的属性,这些属性叫什么?
18.说出下列代码的输出结果
import copy
class A:
def __init__(self, a, b):
self.a = a
self.b = b
class a:
def printa(self):
print('a', self)
class b:
def printb(self):
print(b, self)
#测试变量赋值
a1 = a()
a2 = a1
print(a1, a2)
#测试浅拷贝
b1 = b()
A1 = A(a1, b1)
A2 = copy.copy(A1)
print(A1, A1.a, A1.b)
print(A2, A2.a, A2.b)
#测试深拷贝
A3 = copy.deepcopy(A1)
print(A1, A1.a, A1.b)
print(A3, A3.a, A3.b)
#测试组合
A3.a.printa()
19.什么是工厂模式?什么是单例模式?
Keys
1.面向过程,面向对象,函数式编程
2.面向过程适合简单不需要协作的事务,将事务分解为各个步骤,例如开车[1.启动2.挂挡3.踩油门];面向对象首先思考事务的设计,例如造车[车由以下部分组成:1.轮胎2.发动机3.外壳等,然后找轮胎厂,找发动机厂等,协同完成事务,具体到微观的操作,例如造轮胎,仍然需要面向过程的思路]
总结:面向对象的思想解决复杂问题和宏观问题,面向过程思想与之相反
3.个人理解:对象就是把不同类型的数据,方法(函数)放到一起,得到的结果;类就是把不同类型的数据,方法放到一起,总体的一个计算过程.如果对象是饼干,类就是饼干的模具;类是对象的模板
(1)对象的组成:id,type,value[属性(attributes),方法(methods)];(2)__new__()方法和 __init__()方法分别代表创建对象和初始化创建好的对象;实际上__init__()叫做***构造函数***,它包含了__new__()方法和 __init__()方法的两个过程.
(3)[1]__init__()写法固定(两个下划线);[2]第一个参数必须是self,指的是创建好的***实例对象***;[3]构造函数通常用来初始化实例对象的实例属性,无返回值;[4]通过类名()调用构造函数;
(4)***实例属性***是从属于实例对象的属性,也称为实例变量;实例属性一般在__new__()方法中通过如下代码定义[self.实例属性名 = 初始值];在本类其他实例方法中,也是通过self访问[self.实例属性名];创建对象后,通过实例对象访问:[obj = 类名();obj.实例属性名 = 值]
(5)
***实例方法***是从属于实例对象的方法,格式如下
def 方法名(self,[形参列表]):
函数体
不需要给self传递参数,self由解释器自动传递
s1.say_score()由解释器翻译为student.say_score(s1)
(6)
解释器执行[class 类名:]的时候就会创建一个***类对象***,类对象是实例对象的模板;***类属性***从属于类对象,可以被所有实例对象共享,类对象的定义方式如下:
class 类名:
类变量名 = 初始值
可以通过[类名.类对象名]来读写,内存分析图如下所示
(7)类方法从属于类对象,格式如下:
@classmethod
def 类方法名(cls[,形参列表]):
函数体
类方法的调用格式[类名.类方法名(参数列表)],不需要也不能给cls传值;类方法中访问实例属性和实例方法会报错
子类继承父类方法时,传入cls是子类对象,不是父类对象(还没有学)
(8)静态方法和普通函数的区别是需要通过类调用,格式如下
@staticmethod
def 静态方法名([形参列表]):
函数体
静态方法中访问实例属性和实例方法会报错
(1)输出结果
销毁对象:<__main__.person object at 0x000001F498155898>
程序结束
销毁对象:<__main__.person object at 0x000001F498155860>
首先销毁了p2,程序结束之后销毁了p1
(2)当对象没有被引用时(对象的引用计数为0,对象被变量引用1次,引用计数就会增加1),由垃圾回收器调用__del__方法;(3)del语句;
(4)输出结果
计算工资
120000
定义了__call__()方法的对象,可以像函数一样被调用,称为可调用对象
6.定义多个重名的方法时,只有最后一个方法有效
7.输出结果
bbb
ccc
8.面向对象的三大特征是***封装,继承,多态***;封装是指隐藏对象的属性和实现细节,只对外提供必需的方法,例如把手机视为对象,手机只显现出摄像头,隐藏了电路板;继承指的是***子类***(也叫***派生类***)具有***父类***(也叫***基类***)的特性;多态是指一个方法调用不同对象产生不同的行为,例如每个人的休息方式不一样
(1)
class employee:
def __init__(self, name, age):
self.name = name
self.__age = age #两个下划线
e = employee('santa', 18)
print(e.name)
print(e._employee__age) #类名前一个下划线,类名后两个下划线
输出结果
santa
18
通常两个下划线开头的属性是私有的,其他是公共的;类内部可以访问私有属性;类外部不可以直接访问私有属性/方法,可以通过[_类名__私有属性/方法名]访问私有属性/方法;方法本质上也是属性
(2)
class employee:
__company = 'santates.corp'
def __init__(self, name, age):
self.name = name
self.__age = age
def __work(self):
print("aaa")
e = employee('santa', 18)
e._employee__work()
print(e._employee__company)
输出结果
aaa
santates.corp
class employee:
def __init__(self, name, salary):
self.__name = name
self.__salary = salary
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self, salary):
if salary >= 0:
self.__salary = salary
else:
print("录入错误")
s1 = employee('santa', 10000)
print(s1.salary) #注意这里的调用方法
s1.salary = 20000 #像调用属性一样调用方法
print(s1.salary)
s1.salary = -200
(1)
class person:
def __init__(self, name, age):
self.name = name
self.__age = age
def say_score(self):
print("I don't know")
class student(person):
def __init__(self, name, age, score):
person.__init__(self, name, age) #必须显式地调用父类的初始化方法
self.score = score
s1 = student('santa', 25, 99)
s1.say_score() #调用父类中的方法
print(s1.name)
print(s1._person__age)
print(dir(s1)) #用来查看对象的属性
key:
python支持多重继承,一个子类可以继承多个父类,语法如下
class 子类类名(父类1[,父类2,...])
类体
如果在类定义中没指定父类,默认父类为***object类***,里面定义了一些所有类共有的默认实现,例如:__new__()
在子类的构造函数中调用父类的构造函数,格式如下
父类名.__init__(self, 参数列表)
(2)
输出结果
aa
bb
cc
class person:
def __init__(self, name, age):
self.name = name
self.__age = age
def say_score(self):
print("I don't know")
class student(person):
def __init__(self, name, age):
person.__init__(self, name, age)
def say_score(self):
print("my score is 150.")
s1 = student('santa', 18)
s1.say_score()
print(student.mro())
代码1输出结果
<__main__.person object at 0x00000200E4146630>
代码2输出结果
my name is santa
object有一个__str__()方法,用于返回一个对于对象的描述,该方法可以重写
代码1输出结果
BBB
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
代码2输出结果
AAA
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
等价代码
class A:
def say(self):
print('A:', self)
class B(A):
def say(self):
super().say()
print('B:', self)
B().say()
16.***多态***指的是同一个方法的调用由于对象的不同产生不同的行为
输出结果
用筷子
用刀叉
class person:
def __init__(self, name):
self.name = name
def __add__(self, other):
if isinstance(other, person):
return '{0}--{1}'.format(self.name, other.name)
else:
return '不能相加'
p1 = person('santa')
p2 = person('kokoro')
print(p1 + p2) #相当于p1.__add__(p2)
python对象中包含了很多双下划线开始和结束的属性,这些属性叫特殊属性
下列特殊属性供参考:
输出结果
<__main__.a object at 0x000002410FCC85C0> <__main__.a object at 0x000002410FCC85C0>
<__main__.A object at 0x000002410FEEE940> <__main__.a object at 0x000002410FCC85C0> <__main__.b object at 0x000002410FF1B048>
<__main__.A object at 0x0000024110F7F5C0> <__main__.a object at 0x000002410FCC85C0> <__main__.b object at 0x000002410FF1B048>
<__main__.A object at 0x000002410FEEE940> <__main__.a object at 0x000002410FCC85C0> <__main__.b object at 0x000002410FF1B048>
<__main__.A object at 0x0000024110F7F550> <__main__.a object at 0x0000024110F7F4E0> <__main__.b object at 0x0000024110F7F940>
a <__main__.a object at 0x0000024110F7F4E0>
对象的浅拷贝和深拷贝:
浅拷贝不拷贝子对象,源对象和拷贝对象引用同一个子对象;深拷贝拷贝源对象所有的子对象,源对象和拷贝对象的所有子对象都不同
继承和组合的用法区分:
狗是动物,狗类继承动物类;手机有cpu,则使用***组合***的方法
工厂模式:使用工厂类实现实例类
单例模式:确保一个类只有一个实例并提供一个访问该实例的全局访问点