Python进阶知识
面向对象
面向对象与面向过程的区别:
面向过程:通过一个个方法的执行解决问题,着重的是过程。
面向对象:着重的是谁去帮我做这件事情。
面向对象的三大特征 :封装、继承 、多态。
类与对象
一、类
类:对一系列具有相同属性和行为的事物的统称,不是真实存在的事物。
类的三要素:类名、属性、方法
基本格式:
class 类名:
代码块
查看类属性:类名.属性名
新建类属性:类名.属性名 = 值
1.新式类写法:
经典类:不由任何内置类派生出的类,例:class A:或class A():
新式类:class A(object) 继承object类或者该类的子类都是新式类。
Python3中如果一个类没有继承任何类,则默认继承object类,因此Python3都是新式类。
二、对象
对象:是类的具体实现,是类创建出来的真实存在的事物,面向对象思想的核心。
创建对象(也称实例化对象)的基本格式:
对象名 = 类名()
例:
class Washer:
height = 800 #类属性
def wash(self): #类方法
print("我会洗衣服")
print("方法中的self:",self) #self表示当前调用该方法的对象
wa = Washer() #创建对象
print("wa",wa)
wa.wash() #对象调用类中的方法
实例属性与实例方法
一、实例属性
1.类属性属于类,是公共的,大家都可以访问到,实例属性属于对象的,是私有的。
2.实例属性只能由对象名访问,不能由类名访问。
3.访问类属性,类可以访问到,实例对象也可以访问到。
二 、实例方法
由对象调用,至少有一个self参数,执行实例方法的时候,自动将调用该方法的对象赋值给self。
例:
class Person:
sex = "男" #类属性
def introduce(self):
print("我是实例方法 ")
print(f"{self.name}的年龄是:{self.age},性别是:{Person.sex}")
xiaoming = Person()
xiaoming.name = "xiaoming" #新增实例属性
xiaoming.age = 18
print(xiaoming.name) #根据对象名访问实例属性
xiaoming.introduce()
三、init():构造函数
作用:通常用来做属性初始化或者赋值操作。
在类实例化对象的时候,会被自动调用
例:
class Person:
def __init__(self,name,age,height):
self.name = name #实例属性
self.age = age
self.height = height
def introduce(self):
print(f"{self.name}的年龄是:{self.age},身高是:{self.height}")
xiaoming = Person("xiaoming",18,183)
xiaoming.introduce()
封装
封装:将复杂的信息、流程给包起来,内部处理,让使用者只需要通过简单的操作步骤,就能实现,指的是隐藏对象中一些不希望被外部所访问到的属性或方法。
1.xxx:普通属性与方法,如果是类中定义的,则类可以在任何地方使用
2._xxx:私有属性与方法,如果定义在类中,外部可以使用,子类也可以继承,但无法通过from xxx import *导入。
3.__xxx:隐藏属性与方法,如果定义在类中,无法在外部被直接访问,之类不会继承,也无法通过from xxx import *导入。
一、隐藏属性与方法
隐藏属性(私有权限),只允许在类的内部使用,无法通过对象访问。
写法是在属性名或者方法名前面加上两个下划线_
1.隐藏属性实际上是将名字修改为:_类名__属性名(了解)
2.隐藏属性在类的内部访问。(推荐使用,正规手段)
例:
class Person:
name = "xiaoming" #类属性
__age = 28 #隐藏属性
def introduce(self):
print(f"{Person.name}的年龄是:{Person.__age}")
xiaoming = Person()
print(xiaoming.name)
# xiaoming._Person__age = 18
print(xiaoming._Person__age)
xiaoming.introduce()
隐藏方法:在实例方法中调用隐藏方法。
例:
class Man:
def __play(self): #隐藏方法
print("玩手机")
def funa(self):
print("平平无奇的实例方法")
Man.__play(self) #在实例方法中调用隐藏方法,不推荐
self.__play() #推荐使用,更简便
ma = Man()
ma.funa()
二、私有属性与方法
私有属性:使用对象名._属性名调用
私有方法:使用对象名.方法名调用
例:
class Girl:
def _buy(self): #私有方法
print("整天买买买")
girl = Girl()
girl._buy()
继承
继承就是让类与类之间转变为父子关系,子类默认继承父类的属性和方法。
语法:
class 类名(父类名)
代码块
一、单继承
子类可以继承父类的属性和方法,就算子类自己没有,也可以使用父类的。
例:
class Person: #父类
def eat(self):
print("我会吃饭")
def sing(self):
print("我是唱歌小能手")
class Girl(Person): #Person类的子类
pass #占位符,代码里面类下面不写任何东西,会自动跳过,不会报错
class Boy(Person): #Person类的子类
pass
girl = Girl()
girl.eat()
girl.sing()
boy = Boy()
1.继承的传递(多重继承)
C(子类)继承B(父类),B(子类)继承A(父类),C类具有A/B类的属性和方法。
子类拥有父类的父类的属性和方法。
继承的传递性就是子类拥有父类以及父类的父类中的属性和方法。
例:
class Father:
def eat(self):
print("吃饭")
def sleep(self):
print("睡觉")
class Son(Father): #Father类的子类
pass
class Grandson(Son):
pass
grandson = Grandson()
grandson.sleep()
grandson.eat()
2.方法的重写
方法的重写:指在子类中定义与父类相同名称的方法
1.覆盖父类方法
2.对父类方法进行扩展:继承父类的方法,子类也可以增加自己的功能。
(1)父类名.方法名(self)
(2)super().方法名() ——推荐使用
(3)super(子类名,self).方法名()
super在Python里面是一个特殊的类,super()是使用super类创建出来的对象,可以调用父类中的方法。
例:
class Person: #父类
def money(self):
print("一百万需要被继承")
class Man(Person): #子类
def money(self):
Person.money(self)
super().money()
super(Man,self).money()
print("自己赚一千万")
man = Man()
man.money()
二、多继承
多继承:子类可以拥有多个父类,并且具有所有父类的属性和方法。
不同的父类存在同名的方法时,调用就近原则,括号里哪个在前,优先调用哪个类的方法。
Python中内置的属性__mro__可以查看方法搜索顺序。
弊端:容易引发冲突,会导致代码设计的复杂度增加。
例 :
class Father(object): #父类一
def money(self):
print("拥有一百万财产需要继承")
class Mother(object): #父类二
def money(self):
print("拥有一百二十万财产需要继承")
def appearance(self):
print("绝世容颜需要被继承")
class Son(Father,Mother):
pass
son = Son()
son.money()
son.appearance()
print(Son.__mro__)
1.多态:
多态:同一种行为具有不同的表现形式
多态的前提:1.继承 2.重写
例:
class Animal(object):
def shout(self):
print("动物会叫")
class Cat(Animal):
def shout(self):
print("小猫喵喵喵")
class Dog(Animal):
def shout(self):
print("小狗汪汪汪")
cat = Cat()
cat.shout()
dog = Dog()
dog.shout()
多态性:一种调用方式,不同的执行结果,定义一个统一的接口,一个接口多种实现。
例:
class Animal(object):
def eat(self):
print("我会干饭")
class Pig(Animal):
def eat(self):
print("猪吃饲料")
class Dog(Animal):
def eat(self):
print("狗吃狗粮")
def test(a): #test函数传入不同的对象,执行不同的对象的eat方法
a.eat()
animal = Animal()
pig = Pig()
dog = Dog()
test(animal)
test(pig)
test(dog)
2.静态方法@staticmethod:
使用@staticmethod来进行修饰,静态方法没有self,cls参数的限制。
静态方法与类无关,可以被转换成函数使用。
定义格式:
class 类名:
@staticmethod
def 方法名(形参):
方法体
调用格式:
类名.方法名(实参)
对象名.方法名(实参)
取消不必要的参数传递,有利于减少不必要的内存占用空间和性能消耗。
例:
class Person(object):
@staticmethod #静态方法
def study(name):
print(f"{name}会学习")
Person.study("xiaoming") #静态方法既可以使用对象访问,也可以使用类访问
pe = Person()
pe.study("xiaoming") #调用方法时传参数
3.类方法@classmethod:
使用@classmethod来标识为类方法,对于类方法,第一个参数必须是类对象,一般是以cls作为第一参数。
定义格式:
class 类名:
@classmethod
def 方法名(cls,形参):
方法体
类方法内部可以访问类属性,或者调用其他的类方法。
应用场景:当方法中需要使用到类对象(如访问私有类属性等),定义类方法时,类方法一般配合类属性使用。
例:
class Person(object):
name = "xiaoming"
@classmethod
def sleep(cls):
print("cls:",cls) #cls代表类对象本身,类本质上就是一个对象
print("人类在睡觉")
print(cls.name)
print(Person)
Person.sleep()
总结:
1.实例方法:方法内部访问实例属性,方法内部可以通过类名.类属性名来访问类属性名。
2.静态方法@staticmethod:方法内部不需要访问实例属性和类属性,可以通过类名.类属性名访问类属性,不能访问实例属性。
3.类方法@classmethod:方法内部只需要访问类属性,可通过cls.类属性访问类属性,不能访问实例属性。
4.类属性是公共的,所有方法内部都能够访问到,静态方法不需要访问类属性,因为静态方法和类,对象没有关联。
5.实例属性是私有的,只有实例属性内部能够访问到。
例:
class Person(object):
name = "xiaoming" #类属性:类所拥有的属性
def __init__(self):
self.age = 18 #实例属性:对象私有的
def play(self): #实例方法
print(f"{self.name}在玩游戏") #在实例方法中访问类属性
print(self.age) #在实例方法中访问实例属性
@staticmethod #静态方法,类中的函数,形参没有限制
def introduce1():
print(f"我是{Person.name}") #静态方法能够访问到类属性,但是无意义
@classmethod #类方法:针对类存在的方法
def introduce2(cls): #cls代表类对象本事
print(cls.name)
pe = Person()
pe.play()
pe.introduce1()
pe.introduce2()
单例模式
可以理解成一个特殊的类 ,这个类只存在一个对象。
优点:可以节省内存空间,减少了不必要的资源浪费。
弊端:多线程访问的时候容易引发线程安全问题。
方式:
1.通过@classmethod
2.通过装饰器实现
3.通过重写__new__()实现(重点)
4.通过导入模块实现,模块就是天然的单例模式。
一、new():
new(): object基类提供的内置的静态方法
作用:1.在内存中为对象分配空间。 2.返回对象的引用。
执行步骤:
一个对象的实例化过程:首先执行__new__(),如果没有__new__(),则默认调用object里面的__new__(),返回一个实例对象,然后再去调用__init__(),对对象进行初始化。
例:
class Test(object):
def __init__(self):
print("这是__init__()")
print(self)
def __new__(cls, *args, **kwargs): #cls代表类本身
print("我是__new__()")
print(cls)
# 对父类方法进行扩展:super.方法名()
res = super().__new__(cls) #方法重写,res里面保存的是实例对象的引用
# __new__()是静态方法,形参里面有cls,实参就必须传cls
return res
#注意:重写__new__()一定要return super().__new__(cls)
# 否则python解释器得不到分配空间的对象引用,就不会调用__init__()方法
te = Test()
print("te:",te)
总结:
1.new()是创建对象,init()是初始化对象。
2.new()是返回对象引用,init()定义实例属性。
3.new()是类级别方法,init()是实例级别的方法。
二、通过重写__new__()实现单例模式
设计流程:
1.定义一个类属性,初始值为None,用来记录单例对象的引用。
2.重写__new__()方法。
3.进行判断,如果类属性是None,把__new__()返回的对象引用保存进去。
4.返回类属性中记录的对象引用。
单例模式:每一次实例化所创建的对象都是同一个,内存地址都一样。
例:
class Singleton(object):
a = None #类属性,用来记录第一个被创建的对象的引用
def __new__(cls, *args, **kwargs):
print("这是__new__()方法")
if cls.a == None:
cls.a = super().__new__(cls)
return cls.a
def __init__(self):
print("我是__init__()")
s1 = Singleton()
print("s1:",s1,end="\n\n")
s2 = Singleton()
print("s2:",s2,end="\n\n")
三、应用场景
1.回收站对象
2.音乐播放器,一个音乐播放软件负责音乐播放的对象只有一个。
3.开发游戏软件,场景管理器。
4.数据库配置、数据库连接池的设计。
魔法方式和魔法属性
1.doc:
类函数的描述信息
例:
class Person(object):
"""人类---类的描述信息""" #只能使用多行注释,单行注释无效
pass
print(Person.__doc__)
2.module:
表示当前操作对象所在的模块
3.class:
表示当前操作对象所在的类
例:
class B:
def funa(self):
print("哈哈哈")
b = B()
print(b)
print(b.__class__)
4.str:
对象的描述信息
如果类中定义了此方法,那么在打印对象时,默认输出该方法的返回值,也就是打印方法中的return的数据。
注意:str()必须返回一个字符串。
例;
class C:
def __str__(self):
return "这是str的返回值" #必须有返回值,并且一定是字符串类型
c = C()
print(c)
5.del:析构函数
del()主要是表示该程序模块或者函数已经全部执行结束。
1.删除对象的时候,解释器会调用__del__()方法
2.正常运行时,不会调用__del__(),对象执行结束之后,系统会自动调用__del__()
3.del 对象名语句执行的时候,内存会立即被收回,会调用对象本身的__del__()方法
例:
class Person:
def __init__(self): #最先执行
print("我是__init__()")
def __del__(self): #最后执行
print("被销毁了")
p = Person()
print("这是最后一行代码")
del p #删除p这个对象
6.call:
使一个实例对象成为一个可调用对象,就像函数那样可以调用。
可调用对象:函数\内置函数和类都是可调用函数,凡是可以把一对()应用到某个对象身上都可以称之为可调用对象。
例:
class A:
def __call__(self, *args, **kwargs):
print("这是__cal__()")
a = A()
a() #调用一个可调用的实例对象,其实就是在调用它的__call__()方法
print(callable(a))
callable():判断一个对象是否可调用
例:
def func():
print("哈哈哈")
func()
print(callable(func))
name = "bingbing"
print(callable(name))