难度指数: ★★
重要指数: ★★★
__new__ 是构造函数,用于创建新的对象,而__init__ 是初始化函数,__new__ 函数创建对象后,会调用__init__函数初始化对象的属性
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意;__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
难度指数: ★★
重要指数: ★★★
这是一道简单的编程题,目的是要考察你对异常的理解,对继承的理解,以及你的编码习惯
class MyException(Exception):
pass
raise MyException("测试异常")
这是最简单的自定义异常的方法,使用raise关键字可以抛出该异常,通过传入一个字符串,可以向外传递关键信息。
如果有需要,可以重载__str__方法,来更好的输出异常信息
class MyException(Exception):
def __init__(self, value):
super(MyException).__init__() # 调用父类的__init__方法,可加可不加
self.value = value
self.min_value = 5
def __str__(self):
return f'规定的最小值是{self.min_value}, 实际结果值是{self.value}'
raise MyException(4)
难度指数: ★★★★
重要指数: ★★★
单例模式是最常使用的一种设计模式,该模式的目的是确保在一个系统中,一个类只有一个实例。python中最简单的实现方式当属借助模块,由于模块只会加载一次,因此如果你期望一个对象在系统中只存在一个,那么在某个模块中创建这个对象即可,此后其他模块对它进行引用,即使是多线程环境,也是安全的。
回答出基于模块编写一个单例模式,这个题目基本就算合格了,但如果想展示出更高的实力,就必须说出剩余的4种方法,并至少能手写其中一种。
剩余4种实现单例模式的方法,参见文章python实现单例模式的5种方法
难度指数: ★★
重要指数: ★★★
python有许多魔法方法,最常见的几个:
这个题目,你至少能回答出以上3个魔法方法,接下来,就是加分的回答了
魔法方法中还有__lt__, __le__, __eq__ 等可以重载比较运算符的方法。
和属性相关的方法包括
回答到这里,基本也就可以了,如果想更进一步展示你对python的深入理解,还有两对魔法方法需要回答
难度指数: ★★★
重要指数: ★★★
self是指对象方法里的第一个参数,self是调用方法的实例对象,谁调用方法,self就是谁
class T:
def run(self):
print(id(self))
t = T()
print(id(t))
t.run()
使用print输出实例t 和 self的内存地址,他们完全相同
难度指数: ★★★
重要指数: ★★★
这三个概念都是面向对象里的概念,类里的方法有3种,这3种方法有各自的定义方式和权限
名称 | 定义方法 | 权限 | 调用方法 |
---|---|---|---|
实例方法 | 第一个参数必须是示例,一般命名为self | 可以访问实例的属性和方法,也可以访问类的实例和方法 | 一般通过示例调用,类也可以调用 |
类方法 | 使用装饰器@classmethod修饰,第一个参数必须是当前的类对象,一般命名为cls | 可以访问类的实例和方法 | 类实例和类都可以调用 |
静态方法 | 使用装饰器@staticmethod修饰,参数随意,没有self和cls | 不可以访问类和实例的属性和方法 | 实例对象和类对象都可以调用 |
难度指数: ★★★★
重要指数: ★★★
首先要回答python中一切皆对象,我们所定义的类,也是对象实例。那么我们所定义的类,是哪个类的实例呢?答案正是元类。
你平时所定义的类,并没有特殊说明其元类是什么,这个时候默认元类是type,这个type就是所谓的内置函数,但它其实是一个类。
一个类,如果继承了type,那么这个类就是元类,你可以自己定义一个元类。
class MyMeta(type):
def __new__(cls, *args, **kwargs):
_class = super().__new__(cls, *args, **kwargs)
print(_class.__name__)
return _class
class Animal(metaclass=MyMeta):
def __init__(self, name):
self.name = name
我这里定义了类MyMeta, 它继承了type,因此是一个元类,在定义Animal这个类时,指定MyMeta 作为它的元类。Animal这个类,是元类MyMeta的实例对象。执行上面的代码,MyMeta类的__new__会被执行,因为它需要实例化一个对象,这个对象正是Animal。实例化一个Animal的对象时,则会执行MyMeta类的__call__方法。
要点总结:
难度指数: ★★★★
重要指数: ★★★
我们所定义的类,是元类的实例对象,从这个角度看,类可以有自己的属性。而所谓的实例属性,指的是我们所定义的类的实例对象的属性。
当访问的实例对象的属性不存在时,会去类里寻找是否有与之同名的类属性,如果有则返回该属性。
所有实例对象都可以访问类属性,但不能通过实例对象来修改类的属性,一旦进行修改,本质上就是创建是对象自己的属性。
class T:
name = '类T'
t1 = T()
t2 = T()
print(t1.name, t2.name) # 类T
t1.name = 't1' # 创建了属于t1 的name属性
print(t1.name, t2.name) # t1 类T
难度指数: ★★★
重要指数: ★★★
封装,继承,多态是面向对象的三大特性,与其他编程语言不通,python中没有重载,但有重写。
重载是在一个类里一系列参数不同名字相同的方法,重写是继承后重新实现父类的方法。重写,是实现多态的基础。
class Base():
def print(self):
print("base")
class A(Base):
def print(self):
print("A")
a = A()
a.print()
A 重写了父类Base的print方法,a.print()执行的是A 自己的print方法,如果没有重写,则会执行Base的print方法。
难度指数: ★★★
重要指数: ★★★★★
为了解决python菱形继承导致基类方法重复调用的问题,引入了super()
何为菱形继承,A 是基类,B 和 C 都继承了A, 最后D 继承B和C, 这样就形成了菱形继承。
如果D的初始化函数(__init__)里调用了B和C的初始化函数,而B和C的初始化里又分别调用了A的初始化函数,那么最终A的初始化函数会被执行两次,这显然是非常危险的。
下面的例子就向你演示这种情况
class A:
def __init__(self):
self.attr_a = 1
print('执行A的初始化函数')
class B(A):
def __init__(self):
A.__init__(self)
self.attr_b = 2
print('执行B的初始化函数')
class C(A):
def __init__(self):
A.__init__(self)
self.attr_c = 3
print('执行C的初始化函数')
class D(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
self.attr_d = 4
print('执行D的初始化函数')
d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)
代码执行结果
执行A的初始化函数
执行B的初始化函数
执行A的初始化函数
执行C的初始化函数
执行D的初始化函数
1 2 3 4
你应该注意到,类A的初始化函数被执行了两次,这是一个非常危险的行为,如果A的初始化函数执行了一些一个进程中只能执行一次的代码,这样的多进程就会导致严重的问题, super的引入就是为了解决这种问题。
class A:
def __init__(self):
self.attr_a = 1
print('执行A的初始化函数')
class B(A):
def __init__(self):
super().__init__()
self.attr_b = 2
print('执行B的初始化函数')
class C(A):
def __init__(self):
super().__init__()
self.attr_c = 3
print('执行C的初始化函数')
class D(B, C):
def __init__(self):
super().__init__()
self.attr_d = 4
print('执行D的初始化函数')
d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)
程序执行结果
执行A的初始化函数
执行C的初始化函数
执行B的初始化函数
执行D的初始化函数
1 2 3 4
在D的初始化函数中,只使用了一行代码super().__init__(), 就将两个父类B和C的初始化函数都执行了, 而且不会重复执行A的初始化函数,这些都是super帮助我们完成的。
QQ交流群: 211426309