python面试题(五)
1 谈谈你对面向对象的理解?
面向对象的编程---object oriented programming,简称:OOP,是一种编程的思想。OOP把对象当成一个程序的基本单元,一个对象包含了数据和操作数据的函数。面向对象的出现极大的提高了编程的效率,使其编程的重用性增高。
python面向对象的重要术语:
多态(polymorphism):一个函数有多种表现形式,调用一个方法有多种形式,但是表现出的方法是不一样的。
继承(inheritance)子项继承父项的某些功能,在程序中表现某种联系
封装(encapsulation)把需要重用的函数或者功能封装,方便其他程序直接调用
类:对具有相同数据或者方法的一组对象的集合
对象:对象是一个类的具体事例
实例化:是一个对象事例话的实现
标识:每个对象的事例都需要一个可以唯一标识这个事例的标记
python中的类与对象
class Person(object):
def __init__(self,name): #————————>初始化函数
self.name = name
print "------>create:",name
def say_name(self):
print "my name is %s" %self.name
p1 = Person("gf1") # --------->类的实例化
p2 = Person("gf2")
p1.say_name()
p2.say_name()
复制代码
以上程序是类的一个基本写法,理解如下:
person就是一个类,在这个类中是很多的方法集合。例如类中包含sayname等,还可以按照程序要求灵活添加各种类的方法。
类中self其实就是类的对象,是一个具体的实例。多种的实例通过类中的self表现出来。
程序中的p1、p2是具体的实例,实体。(学名叫:对象。)。一个对象就是一个实体。实体通过调用属性、方法在类中体现相应的功能。
python中的继承
承就是子类继承了父类相应的功能和方法。
如下代码说明了子类继承父类:
class firsttest:
def __init__(self,name):
self._name = name
def sayfirst(self):
print("hello {0}".format(self._name))
class secondtest(firsttest): #子类继承父类(firsttest)的方法
def __init__(self,name):
firsttest.__init__(self,name)
def saysecond(self):
print("good {0}").format(self._name)
s = secondtest("gf1") #类的具体实例。
s.sayfirst()
s.saysecond()
复制代码
函数和面向对象编程的区别
相同点:都是把程序进行封装、方便重复利用,提高效率。 不同点:函数重点是用于整体调用,一般用于一段不可更改的程序。仅仅是解决代码重用性的问题。 而面向对象出来代码重用性。还包括继承、多态等。使用上更加灵活。
2 面向对象中super的作用?
Python中对象方法的定义很怪异,第一个参数一般都命名为self(相当于其它语言的this,比如:C#),用于传递对象本身,而在调用的时候则不
必显式传递,系统会自动传递。
今天我们介绍的主角是super(), 在类的继承里面super()非常常用, 它解决了子类调用父类方法的一些问题, 父类多次被调用时只执行一次, 优化了执行逻辑,下面我们就来详细看一下。
举一个例子:
class Foo:
def bar(self, message):
print(message)
>>> Foo().bar("Hello, Python.")
Hello, Python
复制代码
当存在继承关系的时候,有时候需要在子类中调用父类的方法,此时最简单的方法是把对象调用转换成类调用,需要注意的是这时self参数需要显式传递,例如:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
FooParent.bar(self, message)
>>> FooChild().bar("Hello, Python.")
Hello, Python.
复制代码
这样做有一些缺点,比如说如果修改了父类名称,那么在子类中会涉及多处修改,另外,Python是允许多继承的语言,如上所示的方法在多继承时就需要重复写多次,显得累赘。为了解决这些问题,Python引入了super()机制,例子代码如下:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
super(FooChild, self).bar(message)
>>> FooChild().bar("Hello, Python.")
Hello, Python
复制代码
表面上看 super(FooChild, self).bar(message)方法和FooParent.bar(self, message)方法的结果是一致的,实际上这两种方法的内部处理机制大大不同,当涉及多继承情况时,就会表现出明显的差异来,直接给例子: 代码一:
class A:
def __init__(self):
print("Enter A")
print("Leave A")
class B(A):
def __init__(self):
print("Enter B")
A.__init__(self)
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
A.__init__(self)
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
A.__init__(self)
print("Leave D")
class E(B, C, D):
def __init__(self):
print("Enter E")
B.__init__(self)
C.__init__(self)
D.__init__(self)
print("Leave E")
E()
结果:
Enter E
Enter B
Enter A
Leave A
Leave B
Enter C
Enter A
Leave A
Leave C
Enter D
Enter A
Leave A
Leave D
Leave E
复制代码
执行顺序很好理解,唯一需要注意的是公共父类A被执行了多次。
代码二:
class A:
def __init__(self):
print("Enter A")
print("Leave A")
class B(A):
def __init__(self):
print("Enter B")
super(B, self).__init__()
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
super(C, self).__init__()
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
super(D, self).__init__()
print("Leave D")
class E(B, C, D):
def __init__(self):
print("Enter E")
super(E, self).__init__()
print("Leave E")
E()
print("MRO:", [x.__name__ for x in E.__mro__])
Enter E
Enter B
Enter C
Enter D
Enter A
Leave A
Leave D
Leave C
Leave B
Leave E
MRO: ['E', 'B', 'C', 'D', 'A', 'object']
复制代码
在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照MRO(Method Resolution Order):方法解析顺序 进行的。
3 MRO 多继承属性查找机制
最近在写代码的时候遇到了一个问题,直接实例上代码
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, arg):
print "C","arg=",arg
super(C, self).__init__()
class D(B):
def __init__(self, arg):
print "D", "arg=",arg
super(D, self).__init__()
class E(C,D):
def __init__(self, arg):
print "E", "arg=",arg
super(E, self).__init__(arg)
#print "MRO:", [x.__name__ for x in E.__mro__]
E(10)
复制代码
对于这段代码,我们可能期望输出像这样:
E arg= 10
C arg= 10
A
D arg= 10
B
复制代码
但事实上,这段代码会引发错误,因为python没有像我们想的那样调用正确的函数。
E arg= 10
C arg= 10
A
Traceback (most recent call last):
File "C:/Users/Administrator/Desktop/example1-2.py", line 27, in <module>
E(10)
File "C:/Users/Administrator/Desktop/example1-2.py", line 24, in __init__
super(E, self).__init__(arg)
File "C:/Users/Administrator/Desktop/example1-2.py", line 14, in __init__
super(C, self).__init__()
File "C:/Users/Administrator/Desktop/example1-2.py", line 4, in __init__
super(A, self).__init__()
TypeError: __init__() takes exactly 2 arguments (1 given)
复制代码
我们先给出上面的代码中注释掉的输出mro的语句的输出:
MRO: ['E', 'C', 'A', 'D', 'B', 'object'] 出错的原因是因为调用继续到A.__init__时,我们调用了super(A,self).init。记得上面我们说过super类似于next函数,是调用mro中下一个类型的方法。
这里我们给出的类型是A,那么mro中下一个类型就是D,很显然,super将会调用D.init(self)。可是,D.__init__却接受一个额外的参数arg,所以调用错误。
super并不像它的名字那样,只调用父类的方法,而是调用MRO中,下一个类型的方法。
4 是否使用过functools中的函数?其作用是什么?
partial
首先是partial函数,它可以重新绑定函数的可选参数,生成一个callable的partial对象:
>>> int('10') # 实际上等同于int('10', base=10)和int('10', 10)
10
>>> int('10', 2) # 实际上是int('10', base=2)的缩写
2
>>> from functools import partial
>>> int2 = partial(int, 2) # 这里我没写base,结果就出错了
>>> int2('10')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: an integer is required
>>> int2 = partial(int, base=2) # 把base参数绑定在int2这个函数里
>>> int2('10') # 现在缺省参数base被设为2了
2
>>> int2('10', 3) # 没加base,结果又出错了
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword parameter 'base' was given by position and by name
>>> int2('10', base=3)
3
>>> type(int2)
<type 'functools.partial'>
从中可以看出,唯一要注意的是可选参数必须写出参数名。
复制代码
update_wrapper
接着是update_wrapper函数,它可以把被封装函数的__name__、module、__doc__和 __dict__都复制到封装函数去:
def thisIsliving(fun):
def living(*args, **kw):
return fun(*args, **kw) + '活着就是吃嘛。'
return living
@thisIsliving
def whatIsLiving():
"什么是活着"
return '对啊,怎样才算活着呢?'
print(whatIsLiving() )
print(whatIsLiving.__doc__ )
from functools import update_wrapper
def thisIsliving(fun):
def living(*args, **kw):
return fun(*args, **kw) + '活着就是吃嘛。'
return update_wrapper(living, fun)
@thisIsliving
def whatIsLiving():
"什么是活着"
return '对啊,怎样才算活着呢?'
print(whatIsLiving() )
print(whatIsLiving.__doc__ )
结果:
对啊,怎样才算活着呢?活着就是吃嘛。
None
对啊,怎样才算活着呢?活着就是吃嘛。
什么是活着
复制代码
不过也没多大用处,毕竟只是少写了4行赋值语句而已。
wraps
再有是wraps函数,它将update_wrapper也封装了进来:
from functools import wraps
def thisIsliving(fun):
@wraps(fun)
def living(*args, **kw):
return fun(*args, **kw) + '活着就是吃嘛。'
return living
@thisIsliving
def whatIsLiving():
"什么是活着"
return '对啊,怎样才算活着呢?'
print(whatIsLiving() )
print(whatIsLiving.__doc__ )
复制代码
结果还是一样的:
对啊,怎样才算活着呢?活着就是吃嘛。 什么是活着
total_ordering
最后至于total_ordering函数则给予类丰富的排序方法,使用装饰器简化了操作。如果使用必须在类里面定义一个__lt__(),le(), gt(), 或__ge__()。应该给类添加一个__eq__() 方法。
from functools import total_ordering
@total_ordering
class Student(object):
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name.lower() == other.name.lower()
def __lt__(self, other):
return self.name.lower() < other.name.lower()
a = Student('dan')
b = Student('mink')
print(a > b)
print (a)
print (sorted([b, a]))
打印结果
False
<__main__.Student object at 0x7f16ecb194d0>
[<__main__.Student object at 0x7f16ecb194d0>, <__main__.Student object at 0x7f16ecb195d0>]
复制代码
5 列举面向对象中带爽下划线的特殊方法,如:new、init
类的特殊成员方法
__doc__ :打印类的描述信息
class Foo:
""" 描述类信息,这是用于看片的神奇 """
def func(self):
pass
print(Foo.__doc__)
#输出:类的描述信息
复制代码
__module__:表示当前操作的对象在那个模块
复制代码
__class__:表示当前操作的对象的类是什么
from lib.aa import C
obj = C()
print(obj.__module__) # 输出 lib.aa,即:输出模块
print(obj.__class__) # 输出 lib.aa.C,即:输出类
复制代码
__init__ :构造方法,通过类创建对象时,自动触发执行
class Role(object):
#初始化函数,在生成一个角色时要 初始化的一些属性就填写在这里
def __init__(self,name,role,weapon,life_value=100,money=15000):
#__init__中的第一个参数self,和这里的self都 是什么意思? 看下面解释
self.name = name
self.role = role
复制代码
__del__:析构方法,当对象在内存中被释放时,自动触发执行
class Role(object):
def __init__(self,name,role,weapon:
self.name = name
self.role = role
self.weapon = weapon
def __del__(self): #析构函数
print("del.....run...")
r1 = Role('A','police','AK47') #生成一个角色
复制代码
__call__:对象后面加括号,触发执行
#注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
复制代码
__dict__:查看类或对象中的所有成员
print(类.__dict__) # 打印类里所有属性,不包括实例属性
print(实例.__dict__) #打印实例所有属性,不包括类属性
复制代码
__str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值
class Foo:
def __str__(self):
return 'a li'
obj = Foo()
print(obj)
# 输出:a li
复制代码
识别图中二维码,领取python全套视频资料
python面试题(五)的更多相关文章
- python面试题五:Python 编程
1.B Tree和B+ Tree的区别? 1.B树中同一键值不会出现多次,并且有可能出现在叶结点,也有可能出现在非叶结点中. 而B+树的键一定会出现在叶结点中,并有可能在非叶结点中重复出现,以维持B+ ...
- python公司面试题集锦 python面试题大全
问题一:以下的代码的输出将是什么? 说出你的答案并解释. class Parent(object): x = 1 class Child1(Parent): pass class Child2(Par ...
- python 面试题4
Python面试题 基础篇 分类: Python2014-08-08 13:15 2071人阅读 评论(0) 收藏 举报 最近,整理了一些python常见的面试题目,语言是一种工具,但是多角度的了解工 ...
- 最新python面试题
1.一行代码实现1--100之和 利用sum()函数求和 2.如何在一个函数内部修改全局变量 利用global 修改全局变量 3.列出5个python标准库 os:提供了不少与操作系统相关联的函数 s ...
- Python面试题 —— 获取列表中位数
中位数是一个可将数值集合划分为相等的上下两部分的一个数值.如果列表数据的个数是奇数,则列表中间那个数据就是列表数据的中位数:如果列表数据的个数是偶数,则列表中间那2个数据的算术平均值就是列表数据的中位 ...
- 初学 Python(十五)——装饰器
初学 Python(十五)--装饰器 初学 Python,主要整理一些学习到的知识点,这次是生成器. #-*- coding:utf-8 -*- import functools def curren ...
- Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fabric模块
Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fab ...
- python学习第五次笔记
python学习第五次笔记 列表的缺点 1.列表可以存储大量的数据类型,但是如果数据量大的话,他的查询速度比较慢. 2.列表只能按照顺序存储,数据与数据之间关联性不强 数据类型划分 数据类型:可变数据 ...
- Python学习第五堂课
Python学习第五堂课推荐电影:华尔街之狼 被拯救的姜哥 阿甘正传 辛德勒的名单 肖申克的救赎 上帝之城 焦土之城 绝美之城 #上节内容: 变量 if else 注释 # ""& ...
- 【Python】【面试必看】Python笔试题
前言 现在面试测试岗位,一般会要求熟悉一门语言(python/java),为了考验求职者的基本功,一般会出 2 个笔试题,这些题目一般不难,主要考察基本功.要是给你一台电脑,在编辑器里面边写边调试,没 ...
随机推荐
- mac下安装python pip、pyspider
如果mac下没有安装wget,还需要安装wget,见http://www.cnblogs.com/cocowool/archive/2012/06/24/2560574.html 使用 pip 安装 ...
- Docker 安装docker-compose多容器管理服务
原文地址:https://github.com/eacdy/spring-cloud-book/blob/master/3%20%E4%BD%BF%E7%94%A8Docker%E6%9E%84%E5 ...
- IOC容器Autofac
//类ContainerBuilder中的方法: RegisterType<T>()//注册类型T AsImplementedInterfaces()//表示注册的类型,以接口的方式注册 ...
- unity, 对于Debug.Log输出的log,可以双击定位到代码
unity, 对于Debug.Log输出的log,可以双击定位到代码
- gitlab 把或名改成IP
[root@GitLab assets]# cat /etc/gitlab/gitlab.rb # Change the external_url to the address your users ...
- html之全局属性
html全局属性有很多,下面说说常用的几个: 1.class 这个就不用多说了!规定类名. 2.contenteditable 规定元素是否可以编辑 语法: <element contented ...
- iOS swift cookie创建存储移除
保存网络请求的cookies,并存储到UserDefaults中 //保存COOKIES static func saveCookies(for urlStr: String){ if let url ...
- Spring Java-based容器配置(二)
组装Java-based的配置 使用@Import注解 跟在Spring XML文件里使用<import>元素加入模块化的配置相似,@Import注解同意你载入其它配置类中的@Bean定义 ...
- Sphinx 安装与使用(1)-- 安装Coreseek
Coreseek就是Sphinx的中文版 官方网站 http://www.coreseek.cn/ 一.安装 1.修改LANG 永久修改: vim /etc/locale.conf LANG=&quo ...
- BitMap、Geo、HyperLogLog
前言 Reids 在 Web 应用的开发中使用非常广泛,几乎所有的后端技术都会有涉及到 Redis 的使用.Redis 种除了常见的字符串 String.字典 Hash.列表 List.集合 Set. ...