一、选择题
1、关于python内存管理,下列说法错误的是:(D)
A - 变量不必事先声明
B - 可以使用del释放资源
C - 变量无须指定类型
D - 变量无须先创建和赋值而直接使用
python当中的垃圾回收算法是采用引用计数,
当一个对象的引用计数为0时,
python的垃圾回收机制就会将对象回收:
a = "larry"
b = a
larry这个字符串对下你给,在第一行被贴了a标签后,引用计数为1,
之后第二行,又贴上了b标签,
此时,该字符串对象的引用计数为2
a = 'larry'
b = a
del a
注意:在python语言当中,del语句操作某个对象的时候,并不是直接将该对象在内存当中删除,
而是将该对象的引用计数-1。
a = 'larry'
b = a
del a
>>> id(b)
4572141808
>>> id(a)
>>> NameError: name 'a' is not defined
从以上示例当中可以看出,larry这个字符串对象在第一行被贴上了a标签,
此时字符串的引用计数为1,接着第二行又被贴上了b标签,
此时该字符串对象的引用计数为2,
在第三方中,del语言删除了a变量(标签),
在后续的print中可以看出,内存中实际的字符串对象并没有被删除,
del语句只是删除了一个变量对该字符串对象的引用,
所以,对于larry这个字符串对象来说,效果只是引用计数-1。
魔法函数之__del__
类当中的'del'魔法函数,
支持我们自定义清理对象的逻辑,
当python解释器使用del语言删除类的对象的时候,
会自动调用类中的__del__函数,
我们可以对其进行重载。
class Ref:
def __init__(self,name):
self.name = name
def __del__(self):
print('删除对象')
del self.name
r = Ref(name='larry')
print(r.name)
del r
删除对象。我们可以通过重载__del__魔法函数,
自己灵活控制在del对象的时候执行哪些善后操作。
2 - 可以避免类型错误的函数是(C)
A - type()
B - vars()
C - str()
D - chr()
对于 vars()函数,官方解释是:返回对象object的属性和属性值的字典对象。
class Data(object):
def __init__(self,name,value):
self.name = name
self.value = value
class Value(object):
def __init__(self,age=None,sex=None):
self.age=age
self.sex=sex
var_obj = vars(Value(age='22',sex='man'))
data_obj = vars(Data('大胖喵',val_obj))
print(data_obj)
输出如下:
{'name':'大胖喵','value':{'age':'22','sex':'man'}}
对于chr()函数
chr()用一个范围在range(256)内的整数作参参数,返回一个对应的字符。
# 这是chr()方法的语法:chr(i)
# i 可以是10进制,也可以是16进制形式的数字
# 返回值是当前整数对应的ASCII字符
>>> print(chr(0x30),chr(49),chr(97))
0,1,a
str()函数
在编写python程序时,需要注意字符和数字的区别。
使用数字是不能加引号的,而编写print语句时,则需要str()函数来避免类型错误。
numbers = list(range(1,10))
if number == 1:
print(str(number)+'st')
上面的代码运行结果是:1st。
关于python类继承,下列描述错误的是():
A - 定义子类的实例时,可以通过子类的init()方法,给父类的所有属性赋值。
B - super()是一个特殊的函数,它会把父类和子类关联起来。
C - 对于继承而来的父类方法,如果它不符合子类所期望的行为,那么就必须建立新的类。
D - 子类除了拥有继承父类而来的属性和方法之外,还可以自定义子类自己的属性和方法。
python从设计之初就已经是一门面向对象的语言,
正因为如此,在python中创建一个类和对象,是很容易的。
本章节我们将详细介绍python的面向对象编程。
如果你以前没有接触过面向对象的编程语言,
那么你可能需要先了解一些面向对象语言的一些基本特征,
在头脑当中形成一个基本的面向对象的概念,
这样有助于你更容易的学习python的面向对象编程。
接下来我们先来简单的了解一下面向对象的基本特征
1 - 类(Class)
用来描述,具有相同的属性和方法的对象的集合。
它定义了该集合中每个对象所共有的属性和方法。
对象是类的实例。
2 - 类变量
类变量在整个实例化的对象中,是公用的。
类变量,定义在类中,而且在函数体之外。
类变量,通常不作为实例变量使用。
3 - 数据成员
类变量或者实例变量,用于处理类及其实例对象的相关的数据。
4 - 方法重写
如果从父类继承的方法不能满足子类的需求,
可以对其进行改写,
这个过程叫方法的覆盖(override),
也称之为方法的重写。
5 - 实例变量
定义在方法中的变量,只作用于当前实例的类。
6 - 继承
一个派生类(derived class)继承基类(base class)的字段和方法。
继承也允许把一个派生类的对象,作为一个基类对象对待。
例如,有这样一个设计:
一个Dog类的对象,派生自Animal类,
那么Dog也是一个Animal。
7 - 实例化
创建一个类的实例,类的具体对象
8 - 方法
类中定义的函数
9 - 对象
通过类定义的数据结构实例。
对象包括两个数据成员(类变量和实例变量)和方法。
与其他编程语言相比,python在尽可能不增加新的语法和语义的情况下,加入了类机制。
python3类创建
面向对象编程是一种编程方式,此编程方式的落地需要使用'类'和'对象'来实现。
所以,面向对象编程其实就是对'类'和'对象'的使用。
类就是一个模板,模板里面可以包含多个函数,函数里实现一些功能。
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数:
class Foo:
def bar(self):
print('Bar')
def hello(self,name):
print('I am %s' % name)
obj = Foo()
obj.bar()
obj.hello('chengd')
函数式编程的应用场景:各个函数之间是独立的,而且没有共用的数据。
面向对象编程的应用场景:各个函数之间不是独立的,而且有共用的数据。
面向对象的三大特性
面向对象的三大特性是指:封装、继承和多态。
一、封装
封装,顾名思义就是将内容封装到某个地方,然后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性的时候,需要:
将内容封装到某处
从某处调用被封装的内容
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = Foo('chengd',18)
obj2 = Foo('python',99)
self是一个形式参数,
当执行obj1=Foo('wupeiqi',18)时,self等于obj1
当执行obj2=Foo('alex',78)时,self等于obj2
所以,内容其实被封装到了对象obj1和obj2当中,
每个对象中都有name和age属性。
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
通过对象直接调用
通过self间接调用
1 - 通过对象直接调用被封装的内容
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = Foo('chengd',18)
obj2 = Foo('python',99)
2 - 通过self间接调用被封装的内容
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def detail(self):
print(self.name)
print(self.age)
obj1 = Foo('chengd',18)
obj1.detail()
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象当中,
然后通过对象直接或者self间接获取被封装的内容。
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类当中,
子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,你可能看到过派生类和基类,他们与子类和父类只是叫法不同而已。
那么问题又来了,多继承呢?
是否可以继承多个类?
如果继承的多个类每个类中都定了相同的函数,那么哪一个会被使用呢?
1 - python的类可以继承多个类,java和c#中则只能继承一个类
2 - python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先。
当类是经典类的时候,多继承情况下,会按照深度优先方式查找。
当类是新式类的时候,多继承情况下,会按照广度优先方式查找。
经典类和新式类,从字面上可以看出,一个老一个新,新的必然包含了很多的功能,也是之后推荐的写法。
从写法上区分的话,如果当前类或者父类继承了object类,那么这个类就是新式类,否则就是经典类。
经典类多继承
class D:
def bar(self):
print('D.bar')
class C(D):
def bar(self):
print('C.bar')
class B(D):
def bar(self):
print('B.bar')
class A(B,C):
def bar(self):
print('A.bar')
a = A()
a.bar()
经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,
如果B类中么有,则继续去D类中找,
如果D类中么有,则继续去C类中找,
如果还是未找到,则报错
class D(object):
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
新式类多继承
新式类多继承
新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,
如果B类中么有,则继续去C类中找,
如果C类中么有,则继续去D类中找,
如果还是未找到,则报错
三、多态
python不支持java和C#这一类强类型语言当中多态的写法,但是原生多态。
python崇尚'鸭子类型'。
如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子。