一、运算符重载【重点掌握】
"""
【面试题】简述函数重写和函数重载的区别
函数重写:override,在继承的前提下,如果子类中重新实现了父类中的函数
运算符重载/函数重载:overload,对于自定义的类,通过该类创建的对象,如果不支持某些运算,
如:+ - * / > < >= <= == !=等,则可以在该类中实现这些运算符对应的函数
"""
# 系统中定义的函数,如果命名的前后各两个下划线,则该类函数被称为魔术函数/魔术方法/双下划线方法
# 1.dir(对象):获取指定对象相关的函数或属性
# print(dir("abc"))
# print(dir(10))
# print(dir([1,3]))
# print(dir((1,3)))
# print(dir({'a':10}))
# 2.+ - * /
"""
__add__() +
__sub__() -
__mul__() *
__mod__() %
__divmod__ /
"""
# __add__()为例
# a
print(12 + 10)
print(12 + 45.6)
print(34.5 + 9.7)
print('abc' + 'def')
print('abc'.__add__("def"))
print([1,2] + [4,6])
print([1,2].__add__([4,6]))
print((1,2) + (3,6))
# print({'a':10} + {'b':20})
print("*" * 50)
# b.
class Person():
def __init__(self,age):
self.age = age
# 重载
def __add__(self, other):
# self和other表示参与运算的两个对象
# 结合实际情况,两个对象无法直接相加,可以对两个对象的属性进行加法运算
return Person(self.age + other.age)
# 重写
def __str__(self):
return str(self.age)
__repr__ = __str__
p1 = Person(10)
p2 = Person(5)
# 问题:Person + Person = int---->Person + Person = Person
print(p1 + p2)
print(p1.__add__(p2))
"""
工作原理:
p1 + p2----》p1.__add__(p2)----》Person(self.age + other.age)
print(p1 + p2)----》print(Person(self.age + other.age))---》自动调用__str__
"""
# 3. > < >= <= == !=
"""
__eq__() equal,==
__ge__() greater equal >=
__gt__() greater than >
__le__() less equal <=
__lt__() less than <
__ne__() not equal !=
"""
class Person():
def __init__(self,age):
self.age = age
# 自定义比较规则
def __gt__(self, other):
# self和other是参与比较的两个对象
# 一般情况下,结合实际的使用,参与比较的是对象的同类属性
# if self.age > other.age:
# return True
# return False
# return True if self.age > other.age else False
return self.age > other.age
p1 = Person(10)
p2 = Person(5)
print(p1 > p2) # True
二、多态
一种事物的多种体现形式,举例:动物有很多种
定义时并不确定是什么类型,要调用的是哪个方法,只有运行的时候才能确定调用的是哪个
注意:继承是多态的前提
# 多态:必须是在继承的前提下
# 1.一种事物的多种体现形式【一个对象的多种数据类型】
class Animal(object):
pass
class Cat(Animal):
pass
class SmallCat(Cat):
pass
c = SmallCat()
# isinstance(对象,类型):查看某个对象是否是指定的数据类型
print(isinstance(c,SmallCat))
print(isinstance(c,Cat))
print(isinstance(c,Animal))
print(isinstance(c,object))
a = Animal()
print(isinstance(a,Animal))
print(isinstance(a,Cat))
# 2.定义时并不确定是什么类型,要调用的是哪个方法,只有运行的时候才能确定调用的是哪个
class Animal(object):
def show(self):
print("Animal~~~~~~~show")
class Cat(Animal):
def show(self):
print("Cat~~~~~~~show")
class SmallCat(Cat):
def show(self):
print("SmallCat~~~~~~~show")
def func(a):
a.show()
c = SmallCat()
func(c)
c1 = Cat()
func(c1)
三、其他
1.对象的内置属性
# 1.__slots__:限制对象属性的动态绑定 ****
class Person():
__slots__ = ("name",)
# 2.__doc__:表示类的描述信息,获取类中的文档注释
class Check(object):
"""
功能:实现数据的校验
"""
def show(self):
pass
print(Check.__doc__)
# 3.__dict__:获取类或对象的信息,包括属性和方法 ******
class Person(object):
# 类属性
place = "地球"
# 限制属性
__slots__ = ("name",)
# 构造函数
def __init__(self,name):
# 实例属性
self.name = name
# 实例函数
def show(self):
pass
# 类函数
@classmethod
def func1(cls):
pass
# 静态函数
@staticmethod
def func2():
pass
def __str__(self):
return self.name
__repr__ = __str__
# 类名.__dict__:可以获取类中类属性,实例属性,构造函数,实例函数。类函数,静态函数
print(Person.__dict__)
print(list.__dict__) # dir()
# 4.__module__:获取当前对象在哪个模块,类似于__name__
p = Person('aaa')
print(p.__module__)
print(__name__) # if __name__ == "__main__":
# 5.__class__:类似于type(xxx),获取一个对象的类型
print(p.__class__)
print(type(p))
2.对象的内置函数
# 1.id():获取一个对象在内存中的地址
# 比较两个对象的地址是否相同
a = 45
b = 46
print(id(a) == id(b))
print(a is b)
# 2.type():获取一个对象的数据类型
print(type("fajgh"))
# 比较变量的类型 *****
print(type("abc") == str)
print(type("123") == type(123))
print(type(type(123))) # <class 'type'>
# 自定义类的类型,格式:<class '__main__.类名'>
class Person(object):
pass
p = Person()
print(type(p))
# 借助于types模块,可以判断函数的类型
import types
print(type(lambda x:x ** 2) == types.LambdaType)
print(type((i for i in range(5))) == types.GeneratorType)
# 3.isinstance():判断一个对象是否是某种指定的数据类型 ******
print(type("abc") == str)
print(isinstance("abc",str))
# 4.dir() :查看一个对象的信息 ******
print(dir(34))
# 5.issubclass():判断两个类之间是否具有继承关系
class Animal(object):
def __init__(self,name):
self.name = name
def eat(self):
print("eating")
class Cat(Animal):
pass
print(issubclass(Cat,Animal))
print(issubclass(Cat,object))
3.类方法和静态方法【重点掌握】
【面试题】简述实例函数,类函数和静态函数之间的区别
a.定义不同:被@classmethod装饰的函数表示类函数,被@staticmethod装饰的函数表示静态函数,实例函数没有指定的装饰器
b.形参列表不同:实例函数的第一个参数是self,表示当前对象,类函数的第一个参数是cls,表示当前类,静态函数对参数没有要求
c.调用方式不同:类函数和静态函数都可以通过类名或对象调用,但是,实例函数只能通过对象调用
d.使用场景不同:如果要封装一个工具类,则尽量使用类函数或静态函数,在实际项目开发中,实例函数使用较多,如果需要在类中的函数中创建对象,则一般会将该函数定义成类函数
class Person():
# 类属性
place = "地球"
# 构造函数
def __init__(self,name,age):
# 实例属性
self.name = name
self.age = age
# 实例函数
# self:表示当前对象
def show(self,sth):
print("showing",sth,self.name,self.age)
# 类函数
# cls:class的缩写,表示当前类,使用cls相当于使用Person
@classmethod
def func(cls,num1,num2):
print('func~~~~',num1,num2)
# 需求:在类函数中调用实例函数
# 第一步:创建对象
c = cls(100,200) # 等价于Person(xx,xx)
# 第二步:调用
c.show(465)
#静态函数
@staticmethod
def check(a,b,c):
print('check~~~',a,b,c)
Person.func(12,45)
# Person.check(3,6,7)
#
# p = Person('aaa',10)
# p.show('apple')
# p.func(34,7)
# p.check(243,6,8)
# 应用:定义一个工具类,其中可以进行两个数的加减乘除的运算
class Math():
@staticmethod
def add(num1,num2):
return num1 + num2
@staticmethod
def sub(num1, num2):
return num1 - num2
@staticmethod
def mul(num1, num2):
return num1 * num2
@staticmethod
def div(num1, num2):
return num1 / num2
print(Math.add(34,10))
四、单例设计模式【重点掌握】
1.概念
什么是设计模式?
设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案
设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言
23种设计模式,其中比较常用的是单例设计模式,工厂设计模式,代理模式,装饰者模式等等
什么是单例设计模式?
单例:单个实例【单个对象】,一个类只能创建一个对象
程序运行过程中,确保某一个类只有一个实例【对象】,不管在哪个模块获取这个类的对象,获取到的都是同一个对象。该类有一个静态方法,向整个工程提供这个实例,例如:一个国家只有一个主席,不管他在哪
单例设计模式的核心:一个类有且仅有一个实例,并且这个实例需要应用于整个程序中,该类被称为单例类
思考:验证两个变量表示的是同一个对象,该怎么验证?
解决:验证地址,方式:is 或者 id()
2.应用场景
应用程序中描述当前使用用户对应的类 ———> 当前用户对于该应用程序的操作而言是唯一的——> 所以一般将该对象设计为单例
实际应用:数据库连接池操作 ——> 应用程序中多处地方连接到数据库 ———> 连接数据库时的连接池只需一个就行,没有必要在每个地方都创建一个新的连接池,这种也是浪费资源 ————> 解决方案也是单例
3.实现
3.1方式一
# 定义一个类,该类只能创建一个对象,则该类被称为单例类,这种实现方式被称为单例设计模式
# 1,普通类:可以创建无数个对象
class Person1(object):
def __new__(cls, *args, **kwargs):
print("new被调用了~~~~~")
return super().__new__(cls)
def __init__(self,name,age):
print('init被调用了')
self.name = name
self.age = age
p1 = Person1('张三',10)
p2 = Person1("李四",20)
print(p1 is p2) # False
print(id(p1),id(p2))
print("*" * 50)
# 2
class Person2(object):
# 定义一个私有类属性,表示当前类可以创建的唯一的实例
__instance = None
# super().__new__(cls)但凡执行一次,就会创建一个新的对象,
# 所以只要super().__new__(cls)从头到尾只执行一次,则表示只有一个对象
def __new__(cls, *args, **kwargs):
print("new被调用了~~~~~")
# 判断__instance是否为None,如果是,则将super().__new__(cls)赋值给__instance
# 如果不是,则直接返回
if not cls.__instance:
print("if语句的执行")
cls.__instance = super().__new__(cls)
return cls.__instance
def __init__(self,name,age):
print('init被调用了')
self.name = name
self.age = age
p1 = Person2('张三',10) # 创建
p2 = Person2("李四",20) # 返回第一次创建的对象
print(p1 is p2) # True
print(id(p1),id(p2))
# 原因:每次执行p = Person2(xx,xx),都会执行__init__()
print(p1.name,p2.name) # 李四
p1.name = "aaa"
print(p1.name,p2.name) # aaa
3.2方式二
# 1.装饰器装饰函数
def wrapper(func):
print('1111')
def inner():
print("new~~~~~~")
func() # test()
return inner
@wrapper # 调用wrapper()
def test():
print("testing")
test() # inner()
print("*" * 50)
# 2.装饰器装饰类
def wrapper(cls):
print('1111')
def inner():
print("new~~~~~~")
cls() # Test()创建对象,构造函数
return inner
@wrapper # 调用wrapper(Test)
class Test():
print("testing")
Test() # inner()
print("*" * 30)
# 3.
def singleton(cls): # cls--->Person1
# 定义instance,表示被装饰的类可以创建的唯一的对象
instance = None
def get_instance(*args,**kwargs):
nonlocal instance
if not instance:
instance = cls(*args,**kwargs) # 创建被装饰的类的对象,调用__init__
return instance
return get_instance
@singleton
class Person1(object):
def __init__(self,name,age):
self.name = name
self.age = age
print('init被调用了',self.name,self.age)
p1 = Person1('张三',10) # 调用get_instance函数
p2 = Person1("李四",20)
print(p1 is p2) # True
print(id(p1),id(p2))
# 原因:只有第一次执行p = Person1(xx,xx),才会执行cls(*args,**kwargs),也就会执行__init__()
print(p1.name,p2.name) # 张三
p1.name = "aaa"
print(p1.name,p2.name) # aaa
3.3方式三
def singleton(cls):
# 定义一个字典,用于存储被装饰的类和对应的唯一的对象
# key:被装饰的类 value:被装饰的类能够创建的唯一的对象
instance_dict = {}
def getinstance(*args,**kwargs):
# 判断instance_dict为空,则向字典中添加一对键值对
if not instance_dict:
instance_dict[cls] = cls(*args,**kwargs)
return instance_dict[cls]
return getinstance
@singleton
class Person(object):
def __init__(self,name):
self.name = name
p1 = Person("张三")
p2 = Person("李四")
print(p1 is p2)
print(id(p1) == id(p2))
print(p1.name,p2.name)
p1.name = "tom"
print(p1.name,p2.name)
五、抽象类
"""
如果说类是从多个对象中抽取相同的属性和方法,则抽象类表示从一堆类中抽取相同的属性或方法
抽象类是一个特殊的类,他的特殊之处在于只能被当做父类使用,也就是说,只能被继承,不能被实例化
本质:抽象类就是为被继承的,其中提供子类可以使用的接口,所以在实际开发中,充当父类
"""
# 在Python中,本身没有抽象类,但是,可以通过abc模块模拟
import abc # abstract class
# 抽象类/父类
class AllFile(metaclass=abc.ABCMeta):
# 在抽象类中定义抽象方法,该方法的作用只是给子类提供一个接口,在子类中只需要实现该接口即可
@abc.abstractmethod
def read(self):
pass
@abc.abstractmethod
def write(self):
pass
# def show(self):
# pass
# 子类
class Txt(AllFile):
# 重写
def read(self):
print("txt文件的读取")
def write(self):
print("txt文件的写入")
class Excel(AllFile):
# 重写
def read(self):
print("excel文件的读取")
def write(self):
print("excel文件的写入")
class Csv(AllFile):
# 重写
def read(self):
print("csv文件的读取")
def write(self):
print("csv文件的写入")
t = Txt()
t.read()
t.write()
"""
注意
1.抽象类中可以提供普通实例函数和抽象函数,不能实例化对象,
但是,一般情况下,使用抽象类,只会在其中提供抽象方法
2.抽象类中的抽象方法一般只是一个接口,不需要实现,具体的实现需要在子类中完成
3.如果一个类继承自抽象类,但是未重写抽象类中的抽象方法,则该类仍然是一个抽象类
"""