名词解析
【类】 :是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用;
【对象】:是由类创建出来的一个具体存在,可以直接使用;
【属性】:对对象的特征的描述;特征 <===>属性
【类属性】:类是一个特殊的对象,给类对象定义的特征,不会用于记录具体的类对象特征
【实例】:对象创建后,内存中就有了一个对象的实实在在的存在 ;实例 <===>对象
【实例化】:创建对象的动作;
【实例属性】:就是对象的属性;
【方法】:对对象的行为/动作的描述; 行为 <===>方法
【类方法】:类是一个特殊的对象,给类对象定义的行为动作;
【实例方法】:对象调用的方法
【静态方法】:在开发时,不需要访问实例属性(类属性),也不需要调用实例方法(类方法)时定义的方法
命名规范和语法格式
【类的命名】:
命名规范:名词提炼法,用==大驼峰命名法==来命名
语法格式:class 类名:
【创建(实例)对象】:对象变量=类名();变量引用了对象,对象去调用类中方法
【创建类对象】:class 类名:
【定义(实例)方法】:def 方法名(self,参数1,参数2……):第一个参数必须要默认传实例对象,一般习惯用self。
【定义类方法】:@classmethod
def 类方法名(cls,参数1,参数2…)第一个参数必须要默认传类,一般习惯用cls
【定义静态方法】:@staticmethod
def 静态方法名():参数没有要求。
静态方法:主要是用来放一些方法,方法的逻辑属于类,但是又和类本身没有交互,从而形成了静态方法,主要是让静态方法放在此类的名称空间之内,从而能够更加有组织性。静态方法在类的命名空间之中
访问(调用)的方式
类和对象:类是模版(只有一个),对象是实例(可以有多个),先有类,再有对象;哪一个类创建出来的对象,就拥有哪 个类定义的属性和方法
self (cls):由哪一个对象调用的方法(类方法),方法内的self(cls)就是哪一个对象(类对象)的引用
在类的外部:通过变量名 . 访问实例属性和方法
<1>通过 类名 . 访问类属性(调用类方法)/ (调用静态方法)
<2>通过对象.类属性访问类属性(此方式不推荐)
[注意]:如果使用对象.类属性 = 值 赋值语句,只会 给对象添加一个属性,而不会影响到类属性的值
封装方法内部:通过self.访问实例属性(或调用实例方法)
通过 cls. 访问类属性(或调用类方法)
类属性和实例属性的区别
它们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,
实例属性属于对象;实例属性在每个对象中都要保存一份;
类属性属于类;类属性在内存中只保留一份;
例如:
class Province(object):
country = '中国' # 类属性
def __init__(self, name):
self.name = name # 实例属性
obj = Province('山东省') # 创建一个实例对象
print(obj.name) # 直接访问实例属性
Province.country # 直接访问类属性
实例方法、静态方法和类方法格式及比较
比较:
相同点:对于所有的方法而言,均属于类,所以 在内存中也只保存一份
不同点:方法调用者不同、调用方法时自动传入的参数不同。
案例:
class Foo(object):
def __init__(self, name):
self.name = name
def ord_func(self):
""" 定义实例方法,至少有一个self参数 """
# print(self.name)
print('实例方法')
@classmethod
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法')
@staticmethod
def static_func():
""" 定义静态方法 ,无默认参数"""
print('静态方法')
f = Foo("中国")
# 调用实例方法
f.ord_func()
# 调用类方法
Foo.class_func()
# 调用静态方法
Foo.static_func()
私有化、私有属性、私有方法
私有化
xx: 公有变量
_x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字
xx_:单后置下划线,用于避免与Python关键词的冲突
通过name mangling(名字重整(目的就是以防子类意外重写基类的方法或者属性)如:_Class__object)机制就可以访问
private了。
私有属性:对象 不希望公开的属性
私有方法:对象 不希望公开的方法
定义方式:在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法
访问方式:访问私有属性和方法的时,在 名称 前面加上 _类名 => _类名__名称
总结:
父类中属性名为__名字的,子类不继承,子类不能访问;
如果在子类中向__名字赋值,那么会在子类中定义的一个与父类相同名字的属性;
_名的变量、函数、类在使用from xxx import *时都不会被导入
封装、继承、多态
封装 :根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中;
多态:
(简言之:子类重写了,调用子类,子类没有重写,调用父类,这就是多态)
不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
多态 可以 增加代码的灵活度
以 继承 和 重写父类方法 为前提
是调用方法的技巧,不会影响到类的内部设计
继承:
概念:子类 拥有 父类 的所有 方法 和 属性;实现代码的重用,相同的代码不需要重复的编写
继承的传递性:子类 拥有 父类 以及 父类的父类 中封装的所有 属性 和 方法
方法的重写:
<1>覆盖 父类的方法
<2>对父类方法进行 扩展: 在需要的位置使用 super().父类方法 来调用父类方法的执行
[备注] :python3中super后面的括号里 不要加参数,python2必须要加参数,python2 例如:super(Dog,self).bark(color)
父类的 私有属性 和 私有方法:
子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法
子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法
多继承
概念:子类 可以拥有 多个父类,并且具有 所有父类 的 属性 和 方法
[备注] 开发时,应该尽量避免这种容易产生混淆的情况!如果父类之间存在同名的属性或者方法,应该 尽量避免 使用多继承
多继承以及MRO顺序
案例如下:
单独调用父类的方法:
class Parent(object):
def __init__(self, name):
self.name = name
class Son1(Parent):
def __init__(self, name, age):
self.age = age
Parent.__init__(self, name)
class Son2(Parent):
def __init__(self, name, gender):
self.gender = gender
Parent.__init__(self, name)
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
Son1.__init__(self, name, age) # 单独调用父类的初始化方法
Son2.__init__(self, name, gender)
多继承中super调用有所父类的被重写的方法:
class Parent(object):
def __init__(self, name, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
self.name = name
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
self.age = age
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
self.gender = gender
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
# 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
# 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
# super(Grandson, self).__init__(name, age, gender)
super().__init__(name, age, gender)
print(Grandson.__mro__)
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
单继承中super
class Parent(object):
def __init__(self, name):
self.name = name
class Son1(Parent):
def __init__(self, name, age):
self.age = age
super().__init__(name) # 单继承不能提供全部参数
class Grandson(Son1):
def __init__(self, name, age, gender):
super().__init__(name, age) # 单继承不能提供全部参数
单继承多继承使用super方法的总结
super().__init__相对于类名.__init__,在单继承上用法基本无差
但在多继承上有区别:
super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果
多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错
单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错
多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍,而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
新式类与旧式(经典)类
新式类:以 object 为基类的类,推荐使用
经典类:不以 object 为基类的类,不推荐使用
单例
目的 —— 让 类 创建的对象,在系统中 只有 唯一的一个实例
每一次执行 类名() 返回的对象,内存地址是相同的
单例示例
只执行一次初始化工作
网友评论