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 列举面向对象中带爽下划线的特殊方法,如:newinit

类的特殊成员方法

__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面试题(五)的更多相关文章

  1. python面试题五:Python 编程

    1.B Tree和B+ Tree的区别? 1.B树中同一键值不会出现多次,并且有可能出现在叶结点,也有可能出现在非叶结点中. 而B+树的键一定会出现在叶结点中,并有可能在非叶结点中重复出现,以维持B+ ...

  2. python公司面试题集锦 python面试题大全

    问题一:以下的代码的输出将是什么? 说出你的答案并解释. class Parent(object): x = 1 class Child1(Parent): pass class Child2(Par ...

  3. python 面试题4

    Python面试题 基础篇 分类: Python2014-08-08 13:15 2071人阅读 评论(0) 收藏 举报 最近,整理了一些python常见的面试题目,语言是一种工具,但是多角度的了解工 ...

  4. 最新python面试题

    1.一行代码实现1--100之和 利用sum()函数求和 2.如何在一个函数内部修改全局变量 利用global 修改全局变量 3.列出5个python标准库 os:提供了不少与操作系统相关联的函数 s ...

  5. Python面试题 —— 获取列表中位数

    中位数是一个可将数值集合划分为相等的上下两部分的一个数值.如果列表数据的个数是奇数,则列表中间那个数据就是列表数据的中位数:如果列表数据的个数是偶数,则列表中间那2个数据的算术平均值就是列表数据的中位 ...

  6. 初学 Python(十五)——装饰器

    初学 Python(十五)--装饰器 初学 Python,主要整理一些学习到的知识点,这次是生成器. #-*- coding:utf-8 -*- import functools def curren ...

  7. Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fabric模块

    Python第十五天  datetime模块 time模块   thread模块  threading模块  Queue队列模块  multiprocessing模块  paramiko模块  fab ...

  8. python学习第五次笔记

    python学习第五次笔记 列表的缺点 1.列表可以存储大量的数据类型,但是如果数据量大的话,他的查询速度比较慢. 2.列表只能按照顺序存储,数据与数据之间关联性不强 数据类型划分 数据类型:可变数据 ...

  9. Python学习第五堂课

    Python学习第五堂课推荐电影:华尔街之狼 被拯救的姜哥 阿甘正传 辛德勒的名单 肖申克的救赎 上帝之城 焦土之城 绝美之城 #上节内容: 变量 if else 注释 # ""& ...

  10. 【Python】【面试必看】Python笔试题

    前言 现在面试测试岗位,一般会要求熟悉一门语言(python/java),为了考验求职者的基本功,一般会出 2 个笔试题,这些题目一般不难,主要考察基本功.要是给你一台电脑,在编辑器里面边写边调试,没 ...

随机推荐

  1. Cocos2d-x 3.x版2048游戏开发

    Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍怎样高速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程.从本篇博客你将能够学习到下面内容: 这里注明一下,本教程来自极客学 ...

  2. Hive substr 函数截取字符串

    开发中,经常进行模糊查询或者进行截取字符串进行模糊匹配,常用的就是substr函数或者substring函数. 使用语法: substr(string A, int start),substring( ...

  3. Javascript - demo 与 捷径

    1.页面的后退.刷新.前进 function back(){ history.go(-1); // 后退 } function forward(){ history.go(+1); // 前进 1 页 ...

  4. ddr3调试经验分享(一)——modelsim实现对vivado中的MIG ddr3的仿真

    Vivado中的MIG已经集成了modelsim仿真环境,是不是所有IP 都有这个福利呢,不知道哦,没空去验证. 第一步:使用vivado中的MIG IP生成一堆东西 ,这个过程自己百度.或者是ug5 ...

  5. APACHE KYLIN™ 概览

    APACHE KYLIN™ 概览 Apache Kylin™是一个开源的分布式分析引擎,提供Hadoop之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发 ...

  6. JavaScript之Date对象

    Javascript中的Date类型是在Java.util.Date基础上创建的. 以1970年01月01日至今的毫秒数来保存时间. 要创建一个Date var now = new Date(); 也 ...

  7. Python内置函数之bytes()

    该函数是一个类对象: class bytes([source[,encoding[,errors]]]) 返回值为字节对象,当第一个参数为字符串时,必须提供第二个参数,第二个参数为编码类型的字符串. ...

  8. CentOS环境下yum安装LAMP

    第一步:更新系统内核 yum -y update 如果执行失败报错,可以执行修复命令:rpm –import /etc/pki/rpm-gpg/RPM-GPG-KEY* 第二步: 安装Apahce.M ...

  9. lcd中像素深度bpp和像素格式(比如RGB,YUV)的关系

    像素深度(bits per pixel,简称bpp) 一个像素的颜色在计算机中由多少个字节数据来描述.计算机中用二进制位来表示一个像素的数据,用来表示一个像素的数据位越多,则这个像素的颜色值更加丰富. ...

  10. linux命名空间详解_转

    转自: Linux的命名空间详解--Linux进程的管理与调度(二) Linux Namespaces机制提供一种资源隔离方案. PID,IPC,Network等系统资源不再是全局性的,而是属于特定的 ...