1、简述面向对象的三大特性。
继承:如果多个类中有共同的方法,就可以把共同的方法写在基类也就是父类中,可以供其所有的子类也就是派生类使用,这样的话就不用讲这个方法写很多遍了,使得代码更加简洁,提高了代码的编写效率,子类可以继承父类的非私有属性和方法。
在视图、版本、认证、分页中使用过。
封装:把多个相关的方法、属性封装在一个类中。
多态:有多种表现形式。
2、什么是鸭子模型?
鸭子模型:如果一个东西的叫声像鸭子,走路姿势像鸭子,游泳姿势像鸭子,那么就可以看作这个东西是鸭子。
在面向对象中,一个类的有效定义不是由它既成的类或者特定的借口决定的,而是由当前方法和属性决定的。
3、super的作用?
super()函数是用来调用父类的一个方法。在多继承中,为了避免在两个父类由同样的方法时调用出错的问题,就需要super方法了,单继承中,如果子类的方法和父类重名了,也需要super()方法用super也是一个良好的习惯,
会在以后避免很多出错。
4、mro是什么?
当两个父类中出现重名方法的时候,如何处理他们的继承关系,即MRO(method resolution order)方法解析顺序问题。
5、什么是c3算法。
c3算法最早是用于lisp,后来用到python中解决深度优先搜索中不满足本地优先级和单调性的问题。(用来计算类的MRO)
实例:
class A: pass class B(A): pass class C(A): pass class D(B, C): pass class E(C, A): pass class F(D, E): pass class M: pass class N(M): pass class P(E, A): pass class X: pass class Q(P,N,X): pass class G(Q, F): pass class H(G, F): pass
计算H的mro:
L(A) = A L(B) = B + L(A) + BA BA L(C) = C + L(A) + A CA L(D) = D + L(B) +L(C) + BC DBCA L(E) = E + L(C) +L(A) + CA ECA L(F) = F +L(D) + L(E) + DE F + DBCA + ECA = FDBECA L(M) = M L(N) = N + L(M) + M NM L(P) = P + L(E) +L(A) + EA PECA L(X) = X L(Q) = Q + L(P) + L(N) + L(X) + PNX QPECANMX L(G) = G + L(Q) + L(F) + QF G + QPECANMX + FDBECA = GQPFDBECANMX L(H) = H + L(G) + L(F) + GF H + GQPFDBECANMX + FDBECA = HGQPFDBECANMX
6、列举面向对象中带双下划线的特殊方法。
__init__: 构造函数,在生成对象时调用。
__del__: 析构函数,释放对象时使用。
__repr__: 打印,转换。
__new__: 构造类的实例化。
__setitem: 按照索引赋值。
__getitem__: 按照索引获取值。
__len__:获取长度。
__call__:调用。
7、双下划线和单下划线的区别。
单下划线:方法或者属性前面,认为它时该方法或者属性为该类的私有属性或者方法。
双下划线:python设计此的真正目的是为了避免字类覆盖父类的方法。
开头结尾双下划线:一般来说__this__这种开头结尾都加双下划线的方法表示这是python自己调用的,你不要调用。
8、实例变量和类变量的区别。
类变量:定义在类里面,通过类名或对象名引用,如果是通过对象名引用,会先找有没有这个同名的实例变量,如果没有,引用到的才是类变量,类变量的更新,只能通过类名,形如 类名.a = 55 ,不要指望通过实例引用类变量来更
新类变量。
实例变量: 定义在方法里面的变量,一般在__init__里面,只能通过对象名引用,实例变量的增加、更新形式,形如self.a = 55 。
区别在于,类变量属于类,一个方法将其改变,其他方法调用的就是改变之后的了,实例变量是属于方法私有的,方法将其改变之后,对其他方法没有影响。
9、静态方法和类方法的区别。
类方法:定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
静态方法:定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;调用:实例对象和类对象都可以调用。
10、isinstance 和 type 的作用。
isinstance: 判断一个对象是某个类或子类的实例。(isinstance(object,type-or-tuple-or-class) -> bool)
type: 得到传入的object的类型。(type(object)--类型)
11、有用过with statement吗?它的好处是什么。
用过,打来文件的时候,with的作用是在代码执行结束后,自动关闭文件,不论程序是以何种方式结束的,如果执行代码过程中发生异常,with会在外部异常前关闭文件。
12、下列数据哪些是不可迭代的?
object不可迭代
13、实现一个singleton单例类,要求遵循基本语言编程规范。
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
def Singleton(cls): _instance = {} def _singleton(*args, **kargs): if cls not in _instance: _instance[cls] = cls(*args, **kargs) return _instance[cls] return _singleton @Singleton class A(object): a = 1 def __init__(self, x=0): self.x = x a1 = A(2) a2 = A(3)
14、请描述with的用法,如果自己的类需要支持with 语句,需要怎么书写?
with 后面的语句被求值后返回对象的‘__enter__()‘方法被调用,这个方法的返回值将会返回给as后面的变量。
当with后面的代码全部执行完后将调用前面返回对象的‘__exit__()‘方法。
只需要在类里写入__enter__()方法和__exit__()方法即可使用with.
15、如何判断一个对象是可调用对象?
1、使用内置函数callable函数:可以检测对象是否可以调用,返回True,不一定可以调用,但是返回False,一定不可以调用。
2、判断对象是否有__call__方法。
3、判断类型是否是FunctionTypetype(func) is FunctionType 或者 isinstance(func, FunctionType)
能实现类中__call__()方法的就是可调用类。
16、请实现一个栈
class zhan(object): def __init__(self): self.items = [] def panduan(self): return self.items == [] def size(self): return len(self.items) def peek(self): return self.items[len(self.items) - 1] def push(self, item): self.items.append(item) def pop(self): return self.items.pop() obj = zhan() obj.push(‘h‘) obj.push(‘a‘) obj.push(‘s‘) print(obj.size()) print(obj.peek()) print(obj.pop()) print(obj.peek()) print(obj.size()) print(obj.pop()) print(obj.size()) print(obj.panduan())
17、关于python 类的继承不正确的说法是?
python的类无法继承,只能有一个父类,可以继承,但是不能继承父类的构造函数。(以上说法是不正确的)
18、------
19、请用两个队列实现一个栈(给出为代码即可)
class zhan1(object): def __init__(self): self.l1 = [] self.l2 = [] def add(self, a): if len(self.l1) == 0: self.l2.append(a) if len(self.l2) == 0: self.l1.append(a) def pop(self, ): if len(self.l1) == 0: for i in self.l2[:-1]: self.l1.append(i) self.l2.clear() elif len(self.l2) == 0: for i in self.l1[:-1]: self.l2.append(i) self.l1.clear() else: print(‘栈已经为空‘) def check(self): if len(self.l1) == 0: print(self.l2) elif len(self.l2) == 0: print(self.l1) obj = zhan1() obj.add(‘a‘) obj.add(‘b‘) obj.add(‘c‘) obj.check() obj.pop() obj.check() obj.pop() obj.check() obj.add(‘d‘) obj.check() obj.pop() obj.check()
结果:
[‘a‘, ‘b‘, ‘c‘] [‘a‘, ‘b‘] [‘a‘] [‘a‘, ‘d‘] [‘a‘]
20、已知如下链表类,请实现单链表逆置。
class Node: def __init__(self, value=None, next=None): self.value = value self.next = next def nizhuan(link): pre = link cur = link.next pre.next = None while cur: tem = cur.next cur.next = pre pre = cur cur = tem return pre if __name__ == ‘__main__‘: link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9))))))))) root = nizhuan(link) while root: print(root.value) root = root.next
21、类的加载顺序
构造>静态>父类
22、参考下面代码片段
class Context: pass with Context() as ctx: ctx.do_something
结果:
class Context(object):
def __enter__(self):
print(‘enter‘)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print()
def do_something(self):
print(‘a‘)
with Context() as ctx:
ctx.do_something()
23、下面代码输出时什么?请给出答案并解释。
class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x) print(Child1.x) print(Child2.x) Child1.x = 2 print(Parent.x) print(Child1.x) print(Child2.x) Parent.x = 2 print(Parent.x) print(Child1.x) print(Child2.x)
结果:
1 1 1 1 2 1 2 2 2
解释:父类中的变量类似于全局变量,只能在全局作用域里修改,子类中的属于局部变量,局部变量中对全局变量进行修改只能作用于自己类中,无法改变去他作用域的该变量。
24、
25、请给出下面代码片段的输出,请简述上面代码需要改进的地方。
class singlenton: _instance = None def __new__(cls, *args, **kwargs): print(‘new‘) if cls._instance is None: print(‘Create‘) cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance def __init__(self): print(‘initalize‘) self.prop = None s1 = singlenton() s2 = singlenton()
结果:
new
Create
initalize
new
initalize
改进:应该把__init__函数放在最上面,
26、请简单解释python中的静态方法和类方法,并将以下代码填写完整。
类方法:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)
静态方法:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;调用:实例对象和类对象都可以调用。
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() # 调用 foo函数,参数传入 1 a.foo(1) # 调用 class_foo函数,参数传入 1 A.class_foo(1) # 调用 static_foo函数,参数传入 1 A.static_foo(1) / a.ststic_foo(1)
27、
28、编程实现一个先进先出的队列类,能追定初识化时的队列大小。
class Queue(object): def __init__(self, size): self.__size = size self.__queue = [] def enqueue(self, x): if len(self.__queue) < self.__size: self.__queue.insert(0, x) else: return ‘The queue is full!!!‘ def dequeue(self): return None if not len(self.__queue) else self.__queue.pop() def is_empty(self): return not len(self.__queue) def isfull(self): return len(self.__queue) == self.__size s = Queue(2) print(s.is_empty()) s.enqueue(1) s.enqueue(2) print(s.isfull()) print(s.dequeue()) print(s.dequeue()) print(s.is_empty())