面向对象
概念
类(Class) :用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。其中的对象被称作类的实例。
实例/对象:通过类定义的初始化方法,赋予具体的值,成为一个"有血有肉的实体"。
实例化:类--->对象 的过程或操作。
类变量:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。
实例变量:定义在实例中的变量,只作用于当前实例。
实例方法:至少有一个参数并且以实例对象(self)作为其第一个参数的方法。
静态方法:不需要实例化就可以由类执行的方法。
类方法:类方法是将类本身作为对象进行操作的方法。
封装:将内部实现包裹起来,对外透明,提供api接口进行调用的机制。
继承:即一个派生类(derived class)继承父类(base class)的变量和方法。
多态:根据对象类型的不同以不同的方式进行处理。
类的两种作用
1.属性引用(类名.属性)
class Person: # 定义一个Person类 role = 'person' # 静态属性就是直接在类中定义的变量 def __init__(self,name): self.name = name # 每一个角色都有自己的昵称; def walk(self): # 动态属性就是定义在类中的方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
2.实例化:类名加括号,自动触发__init__函数的运行,为每个实例定制自己的特征
class 类名: 类属性 = None def __init__(self,参数1,参数2): self.对象属性1 = 参数1 self.对象属性2 = 参数2 def 方法名(self): pass 实例/对象名 = 类名(参数) # 对象就是实例,代表一个具体的东西 # 类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 # 括号里传参数,参数不需要传self,其他与init中的形参一一对应 # 结果返回一个对象 实例/对象名.对象属性 # 查看对象的属性 实例/对象名.方法名() # 调用类中的方法
类的属性和方法
类属性/实例属性(也叫类变量、实例变量)
1:实例属性: 最好在__init__(self,...)中初始化 内部调用时都需要加上self. 外部调用时用instancename.propertyname 2:类属性: 在__init__()外初始化 在内部用classname.类属性名调用 外部既可以用classname.类属性名又可以用instancename.类属性名来调用 3:私有属性: 1):单下划线_开头:只是告诉别人这是私有属性,外部依然可以访问更改 2):双下划线__开头:外部不可通过instancename.propertyname来访问或者更改 实际将其转化为了_classname__propertyname
实例方法/静态方法/类方法
实例方法:类的实例方法由实例调用,至少包含一个self参数,且为第一个参数。执行实例方法时,会自动将调用该方法的实例赋值给self。self代表的是类的实例,而非类本身
静态方法:静态方法由类调用,无默认参数。将实例方法参数中的self去掉,然后在方法定义上方加上@staticmethod,就成为静态方法。它属于类,和实例无关。建议只使用类名.静态方法的调用方式。(虽然也可以使用实例名.静态方法的方式调用)
class Foo: @staticmethod def static_method(): pass #调用方法 Foo.static_method()
类方法:类方法由类调用,采用@classmethod装饰,至少传入一个cls(代指类本身,类似self)参数。执行类方法时,自动将调用该方法的类赋值给cls。建议只使用类名.类方法的调用方式。(虽然也可以使用实例名.类方法的方式调用)
class Foo: @classmethod def class_method(cls): pass Foo.class_method()
综合例子:
class Foo: def __init__(self, name): self.name = name def ord_func(self): """定义实例方法,至少有一个self参数 """ print('实例方法') @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print('类方法') @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print('静态方法') # 调用实例方法 f = Foo("Jack") f.ord_func() Foo.ord_func(f) # 请注意这种调用方式,虽然可行,但建议不要这么做! # 调用类方法 Foo.class_func() f.class_func() # 请注意这种调用方式,虽然可行,但建议不要这么做! # 调用静态方法 Foo.static_func() f.static_func() # 请注意这种调用方式,虽然可行,但建议不要这么做!
封装、继承、多态
封装
封装是指将数据与具体操作的实现代码放在某个对象内部,使这些代码的实现细节不被外界发现,外界只能通过接口使用该对象,而不能通过任何形式修改对象内部实现,正是由于封装机制,程序在使用某一对象时不需要关心该对象的数据结构细节及实现操作的方法。使用封装能隐藏对象实现细节,使代码更易维护,同时因为不能直接调用、修改对象内部的私有信息,在一定程度上保证了系统安全性。类通过将函数和变量封装在内部,实现了比函数更高一级的封装。
继承
Python3的继承机制:
- 子类在调用某个方法或变量的时候,首先在自己内部查找,如果没有找到,则开始根据继承机制在父类里查找。
- 根据父类定义中的顺序,以深度优先的方式逐一查找父类!
继承参数的书写有先后顺序,写在前面的被优先继承。
多态
多态指的是一类事物有多种形态
import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao') peo=People() dog=Dog() pig=Pig() # peo、dog、pig都是动物,只要是动物肯定有talk方法 # 于是我们可以不用考虑它们三者的具体是什么类型,而直接使用 peo.talk() dog.talk() pig.talk() #更进一步,我们可以定义一个统一的接口来使用 def func(obj): obj.talk() # 调用的逻辑都一样,执行的结果却不一样 talk(peo) talk(dog) talk(pig)
方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:‘’
#!/usr/bin/python3 class Parent: # 定义父类 def myMethod(self): print ('调用父类方法') class Child(Parent): # 定义子类 def myMethod(self): print ('调用子类方法') c = Child() # 子类实例 c.myMethod() # 子类调用重写方法 super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
执行结果:
调用子类方法
调用父类方法
super()函数是用于调用父类(超类)的一个方法。
super() 函数是用于调用父类(超类)的一个方法。
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
语法
super(type[, object-or-type])
参数
- type -- 类。
- object-or-type -- 类,一般是 self
Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
Python3.x 实例:
class A: pass class B(A): def add(self, x): super().add(x)
Python2.x 实例:
class A(object): # Python2.x 记得继承 object pass class B(A): def add(self, x): super(B, self).add(x)
示例
#!/usr/bin/python # -*- coding: UTF-8 -*- class FooParent(object): def __init__(self): self.parent = 'I\'m the parent.' print ('Parent') def bar(self,message): print ("%s from Parent" % message) class FooChild(FooParent): def __init__(self): # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类B的对象 FooChild 转换为类 FooParent 的对象 super(FooChild,self).__init__() print ('Child') def bar(self,message): super(FooChild, self).bar(message) print ('Child bar fuction') print (self.parent) if __name__ == '__main__': fooChild = FooChild() fooChild.bar('HelloWorld')
执行结果:
Parent Child HelloWorld from Parent Child bar fuction I'm the parent.
类的专有方法:
__init__ : 构造函数,在生成对象时调用 __del__ : 析构函数,释放对象时使用 __repr__ : 打印,转换 __setitem__ : 按照索引赋值 __getitem__: 按照索引获取值 __len__: 获得长度 __cmp__: 比较运算 __call__: 函数调用 __add__: 加运算 __sub__: 减运算 __mul__: 乘运算 __div__: 除运算 __mod__: 求余运算 __pow__: 乘方
常用如下
1.__getitem__()、__setitem__()、__delitem__() a = 标识符[] : 执行__getitem__方法 标识符[] = a : 执行__setitem__方法 del 标识符[] : 执行__delitem__方法 class Foo: def __getitem__(self, key): print('__getitem__',key) def __setitem__(self, key, value): print('__setitem__',key,value) def __delitem__(self, key): print('__delitem__',key) obj = Foo() result = obj['k1'] # 自动触发执行 __getitem__ obj['k2'] = 'jack' # 自动触发执行 __setitem__ del obj['k1'] # 自动触发执行 __delitem__ 2.__str__(),__repr__()改变对象的字符串显示 3.__format__ 自定制格式化字符串 4.__del__()析构方法,当对象在内存中被释放时,自动触发执行 5.__new__单例模式 6.__call__()对象后面加括号,触发执行 7.__len__() len()时执行 8.__module__ 表示当前操作的对象在属于哪个模块 9.__class__ 表示当前操作的对象属于哪个类 10.__dict__ 列出类或对象中的所有成员!非常重要和有用的一个属性 11.__iter__ 这是迭代器方法!列表、字典、元组之所以可以进行for循环,内部定义了 __iter__()这个方法 12.__slots__ 限制实例可以添加的变量