刻意练习——Python基础10.类与对象
- 定义类的语法:
class 类名:
执行语句...
零个到多个类变量...
零个到多个方法...
- 类所包含的类变量和实例变量都可以动态增加或删除
- 类中定义的方法默认是实例方法
- 定义实例方法的方法与定义函数的方法基本相同,只是实例方法的第一个参数会被绑定到方法的调用者(该类的实例)——因此实例方法至少应该定义一个参数,该参数通常会被命名为self。
- __ init__构造方法:构造方法用于构造该类的对象,Python通过调用构造方法返回该类的对象(无须使用new)
- 对象访问方法或变量的语法:对象.变量|方法(参数)
- 为对象动态增加方法(Python不会自动将调用者绑定到第一个参数,需要手动绑定;或者借助types模块下的MethodType进行包装)
#定义一个函数
def info(self):
print(ahhhhh,self)
#使用info对p的foo方法赋值
p.foo=info
p.foo(p)
#使用lambda表达式对p对象的bar方法赋值
p.bar = lambda self:print(emmmmm,self)
p.bar(p)
def intro_func(self,content):
print("我是一个人,信息为:%s" % content)
#导入MethodType
from types import MethodType
#使用MethodType对intro_func进行包装,将该函数的第一个参数绑定为p
p.intro = MethodType(intro_func,p)
#第一个参数已经绑定了,无须传入
p.intro("生活在别处")
-
如果在某个方法中把self参数作为返回值,则可以多次连续调用方法(只要该方法也返回self),从而使得代码更加简洁
-
类也能调用实例方法,只是必须绑定self对象
-
@classmethod修饰的方法就是类方法;@staticmethod修饰的方法就是静态方法
-
类方法会自动绑定第一个参数;静态方法不会自动绑定第一个参数
-
@函数装饰器:当程序使用“@函数”函数A装饰另一个函数函数B时,实际上完成如下两步:
①.将被修饰的函数B作为参数传给@符号引用的函数函数A
②.将函数B替换(装饰)成第①步的返回值 -
通过实例访问类变量的本质依然是通过类名在访问
-
如果程序通过对象对类变量赋值,其实不是对“类变量赋值”,而是定义新的实例变量
-
用property()函数定义函数:
property(fget=None,fset=None,fdel=None,doc=None)
(4个参数分别代表:getter、setter、del、doc) -
隐藏和封装:封装是面向对象编程语言对客观世界的模拟,在客观世界里,对象的状态信息都被隐藏在对象内部,外界无法直接操作和修改。对一个类或对象实现良好的封装,可以达到以下的目的:
1.隐藏类的实现细节
2.让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对属性的不合理访问
3.可进行数据检查,从而有利于保证对象信息的完整性
4.便于修改,提高代码的可维护性 -
Python隐藏的格式:将Python类的成员命名为以双下画线开头的,Python就会把它们隐藏起来(Python并没有提供类似于其他语言的private等修饰符,因此Python并不能真正支持隐藏)
-
Python会改变以双下画线开头的方法名,会在这些方法名前添加单下画线和类名。因此程序可通过为隐藏的实例变量或方法添加下画线和类名的方法访问或修改对象的实例变量或方法
-
传承的语法格式:
class SubClass(SuperClass1,SuperClass2,...)
-
如果在定义一个Python类时并未显式指定这个类的直接父类,则这个类默认继承object类
-
如果多个父类中包含了同名的方法,此时排在前面的父类中的方法会遮蔽排在后面的父类中的同名方法
-
重写父类方法:子类包含与父类同名的方法的现象叫做方法重写(Override)也叫方法覆盖,子类会重新定义父类的同名方法
-
可以使用未绑定方法调用被重写的方法
-
Python的子类只会继承优先级高的父类的构造方法
-
如果子类重写了父类的构造方法,那么子类的构造方法必须调用父类的构造方法。子类的构造方法调用父类的构造方法:
1.使用未绑定方法
2.使用super()函数调用父类的构造方法
class Manager(Employee,Customer):
#重写父类的构造方法
def __init__(self,salary,favorite,address):
print('--Manager的构造方法--')
#通过super()函数调用父类的构造方法
super().__init__(salary)
#与上一行代码的效果相同
#super(Manager,self).__init__(salary)
#使用未绑定方法调用父类的构造方法
Customer.__init__(self,favorite,address)
- 通过为类添加方法,以实现为所有实例都添加方法(前面的添加方法只是对于单一的实例)
- __ slots__属性:限制实例为某个类动态添加属性和方法。__ slots__属性并不限制通过类来动态添加属性或方法。__ slots__属性指定的限制只对当前类的实例起作用,对该类派生出来的子类是不起作用的。
- 用type()函数定义类:
类名 = type(类名,(父类集合),dict(该字典对象为该类绑定的类变量和方法))
- 使用metaclass可以动态修改程序中的一批类,对它们集中进行某种修改
- 多态类的灵活应用
-
Python提供了两个函数来检查类型:
1.issubclass(cls,class_or_tuple):检查cls是否为后一个类或元组包含的多个类中任意类的子类
2.isinstance(obj,class_or_tuple):检查obj是否为后一个类或元组包含的多个类中任意类的对象 -
__ bases__属性:通过该属性可以查看该类的所有直接父类
-
__ subclasses__()方法:查看该类的所有直接类,返回该类的所有子类组成的列表
-
枚举类:实例有限且固定的类
-
定义枚举类:
1.直接使用Enum()列出多个枚举值来创建枚举类
2.通过继承Enum基类来派生枚举类
#直接使用Enum列出多个枚举值
import enum
#Enum()函数格式
#类名 = enum.Enum(类名,(元组))
Season = enum.Enum(Season,('spring','summer','fall','winter')
- 枚举类每个成员都有name、value两个属性,其中name属性值为该枚举值的变量名,value代表该枚举值的序号(序号通常从1开始)
- __ members__属性:该属性返回一个dict字典,字典包含了该枚举的所有枚举实例
- 通过继承Enum来派生更加复杂的枚举类