面向对象
面向对象,简单来说用类对一切对象进行描述的一种编程思维和方法.在这里就不多做介绍(因为我也只是意会到一点点).根据面向对象的概念,我们需要注意的几个概念:
类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.
对象(Object):通过类定义的数据结构实例.对象包括两个数据成员(类变量和实例变量)和方法。
类变量:类变量在整个实例化的对象中是公用的,类变量定义在类中且在函数体之外,类变量通常不作为实例变量使用.
实例变量:定义在方法中的变量,只作用于当前实例.
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法:类中定义的函数.
继承:即一个派生类(derived class)继承基类(base class)的字段和方法.也称为父类和子类
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写.
实例化:创建一个类的实例,类到具体对象的过程
属性: 不管是变量或者是方法,都称为属性.变量一般称为静态属性,方法称为动态属性
面向对象的三大特性
1, 封装: 把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.
2, 继承: 让不同类型的对象获得其它类型对象的属性和方法.
3, 多态: 实现接口重用, 即可以不同类型对象使用相同的方法,也可以一个对象的相同方法在不同情形有不同的表现形式
类
类的封装,基本构成和使用
1, 创建类,先来看例子
class Test(object): '''class_doc''' class_var = 'class_var' def class_func(self): obj_var = 'obj_var' print(obj_var)
class | 定类的关键字通常类的首字母使用大写 object | 新式类的所有类的基类,经典类和新式类在后面阐述,python3中建议使用这种形式定义类 class_doc | 类的文档,可以通过__doc__方法查看 obj_var | 实例变量,需要对类进行实例化生成对象后,才能通过对象是属于具体实例的.静态属性 def | 定义类方法的关键字,和普通函数作用相同.动态属性 self | 类方法必须有的参数,代表的是实例自身 class_var | 类变量,可以在外部直接调用,不需要先进行实例话
2, 实例化,在python中使用类似函数调用的方式实例化类,并没有其它语言中的特殊关键字
t1 = Test() #t1 就是类Test的具体对象
3, 访问属性,同样是上例子
class Test(object): class_var = 'class_var' def obj_func(self): obj_var = 'obj_var' print(obj_var) t1 = Test() Test.class_var = 'modify from Test' print(Test.class_var) #print(Test.obj_func()) t1.class_var = 'modify from t1' print('Test:',Test.class_var) print(t1.class_var) print(t1.obj_func()) #print(t1.obj_var)
我们可以发现几个情况:
- (1)类变量不需要实例化可以访问,实例在实例化后会共用类变量,
- (2)不能通过实例修改类变量,修改的自身的那份类变量.相当于新生成了一个实例变量.
- (3)类里定义的方法通常没有实例化,是不能访问.
- (4)类方法里定义的实例变量是不能在外部直接调用的.
4, 类的内置方法,可以查看一些类的基本信息.(有些属性实例不能使用.)
__init__ | 构造方法 __del__ | 析构函数 __name__ | 查看类名 __dict__ | 查看类属性成员 __doc__ | 查看类文档 __class__ | 查看对象所属的类 __module__ | 查看对象所在模块 __bases__ | 查看基类 __mro__ | 查看继承顺序 __call__ | 让实例化的对象可调用(即可以加执行符号()) __str__ | 打印对象是,返回这个方法的值,通常用在实例化的对象定制信息 __getitem__ | 见第9小点 __setitem__ | 见第9小点 __delitem__ | 见第9小点 __new__ | 实例化方法 __slots__ | 限制类属性 __metaclass__ | 查看元类
5, 构造函数,类的实例化时执行的函数,通常用来实现对象的初始化._init__
class Test(): name = 'class_var' def __init__(self,name,choice=None): self.name = name self.choice = choice if self.choice == 'yes': self.say_hello() else: self.other() def say_hello(self): print('Welcome,%s'%self.name) def other(self): print('No choice') t1 = Test('sylar','yes') print(t1.name) #Test.name t2 = Test('tom')
通过这个例子可以发现,构造函数中定义的属性是针对实例本身,并且也印证了类中的关键字self是指对象而不是类
6, 析构函数,__del__()也是可选的,如果不提供,则Python 会在后台提供默认析构函数.在对象销毁时自动执行的函数,显示的执行可以使用del obj
import time class del_test(object): def say_bye(self): print('see you next time') def __del__(self): self.say_bye() o1 = del_test() del o1 time.sleep(3) o2 = del_test()
7, 私有属性,无法在外部调用,但是可以在内部调用,从而隐藏某些属性或方法.
class Test(object): def __init__(self,name,id_status): self.name = name self.__status = id_status def show_status(self): print(self.__status) t1 = Test('sylar','some info') t1.show_status() t1.__status
单下划线、双下划线、头尾双下划线说明:
__foo__: 定义的是特殊方法,一般是系统定义名字,类似 init() 之类的.
_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了.
8, __call__方法,让不可执行的对象变的可执行
class Animal(object): def __call__(self, *args, **kwargs): print('call func') t = Animal() t() Animal()()
9, __getitem__,__setitem__,__delitem__.用类模拟类似字典的操作
class Test(object): def __getitem__(self,key): print('__getitem__:',key) def __setitem__(self, key, value): print('__setitem__:',key,value) def __delitem__(self, key): print('__delitem__:',key) t1 = Test() t1['name'] t1['name'] = 'sylar' del t1['name']
类的继承
1, 继承,代码重用,派生类(子类)会完全继承基类(父类)的所有属性.
class Base_Class(object): def __init__(self,name): self.name = name self.say_hi() def say_hi(self): print('Welcome, %s!'%self.name) def call_me(self): print("%s"%self.name) class Sub_Class(Base_Class): pass t1 = Sub_Class('sylar') t1.call_me()
2, 方法重写: 当子类中定义的属性或方法和父类重名时,子类会覆盖父类中的定义.有些时候需要父类的方法,又需要做一些改动.可以直接在子类中调用父类的方法然后再添加新的代码,或者使用super函数.(建议使用super)
class Base_Class(object): def __init__(self,name): self.name = name def call_me(self): print("%s"%self.name) class Sub_Class(Base_Class): def call_me(self): #super(Sub_Class,self).call_me() Base_Class.call_me(self) print('modify for Sub_Class') t1 = Sub_Class('sylar') t1.call_me()
3, 多继承顺序,又分为经典类和新式类,在python3中默认都是使用广度优先. 使用__mro__方法可以查看继承的查找顺序
class Base_A: def __init__(self): print('from A') class Base_B(Base_A): pass class Base_C(Base_A): def __init__(self): print('from C') class Sub_Class(Base_B,Base_C): pass t1 = Sub_Class() print(Sub_Class.__mro__)
这段经典类的代码在python2X 输出为'from A'深度优先,在python3x输出为'from C'广度优先
python2 的新式类使用的广度优先
类的多态
接口重用,使用统一的接口对子类的方法进行调用
class Animal(object): @staticmethod def run_func(obj): obj.run() class Cat(Animal): def run(self): print('Cat is running') class Mouse(Animal): def run(self): print('Mouse is running') c1 = Cat() m1 = Mouse() Animal.run_func(c1) Animal.run_func(m1)
类内置装饰器
1, 静态方法 staticmethod不能访问类和实例属性,相当于和类本身没有什么关系,只是需要通过类名来调用这个方法.而且实例化后self也不会被传入到这个方法中.前面的多态就是一种使用场景.
2, 类方法 classmethod只能访问类变量不能访问实例变量
class Animal(object): name = 'Tom' def __init__(self): self.name = 'Jerry' @classmethod def run_func(self): print('%s is running'%self.name) t = Animal() t.run_func()
3, 属性方法 把一个方法当作静态属性来使用
单独使用,不能传参数
class Animal(object): def __init__(self): self.name = 'Jerry' @property def run_func(self): print('%s is running'%self.name) t = Animal() t.run_func
配合setter接受赋值,实现类似传入参数的功能
class Animal(object): def __init__(self): self.__who = None @property def run_func(self): print('%s is running'%self.__who) @run_func.setter def run_func(self,who): #print('set to name',who) self.__who = who
配合deleter删除,默认property装饰器转换过来的属性是不能删除的.如果要删除就要使用deleter
class Animal(object): def __init__(self): self.__who = None @property def run_func(self): print('%s is running'%self.__who) @run_func.setter def run_func(self,who): #print('set to name',who) self.__who = who @run_func.deleter def run_func(self): del self.__who t = Animal() t.run_func = 'Tom' t.run_func del t.run_func
类的定制(元类)和type
由于python是解释型语言,所以函数和类的定义不是编译时定义的,而是运行时动态创建的.在python中所有的类都是继承object,并由type方法生成的.type接收三个参数:类名,继承的父类元组,需要绑定的函数. 就可以生成一个类
def my_init(self,name): self.name = name def say_hi(self): print('Hello %s'%self.name) Test = type('Test', (object,), {'say_hi' : say_hi, '__init__' : my_init,}) t = Test('sylar') t.say_hi()
1, __new__类的实例化方法,在所有类实例化的时候都是通过new方法
class MyClass(object): def __init__(self): print('some code in init!') def __new__(cls, *args, **kwargs): print('some code in new!') return object.__new__(cls) t1 = MyClass()
- new是执行在init之前的,并且通过return触发init的执行
- return object.__new__(cls)相当于super去继承但这时候还没生成self,
- cls相当于self,指代MyClass这个类的自身
2,metaclass元类,创建类的类,类是metaclass创建的实例.在python中自定义类需要先创建metaclass再创建类.python3和python2的语法有所改变
python3
def my_add(self,value): self.append(value) class ListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['my_add'] = my_add #这里也可以使用lambda return type.__new__(cls, name, bases, attrs) class MyList(list,metaclass=ListMetaclass): pass l1= MyList() l1.my_add(1) l1.my_add(2) print(l1)
python2
class ListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) return type.__new__(cls, name, bases, attrs) class MyList(list): __metaclass__ = ListMetaclass
属性锁定
前面已经说了python类的属性可以动态创建的,为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
class Test(): #__slots__ = ('name','age') def __init__(self,name,age): self.name = name self.age = age t = Test('sylar',18) t.job = 'it'
反射
判断类或实例是否有相应的属性,简单来说就是通过字符串来操作类.
hasattr(obj,name_str),判断对象里是否有对应字符串的属性
class Test(): #__slots__ = ('name','age') def __init__(self,name,age): self.name = name self.age = age t = Test('sylar',18) choice = input() res = hasattr(t,choice) print(res)
getattr(obj,name_str),根据字符串获取对象相应的属性或是属性的内存地址
class Test(): #__slots__ = ('name','age') def __init__(self,name,age): self.name = name self.age = age t = Test('sylar',18) choice = input() res = getattr(t,choice) print(res)
setattr(obj,name_str,attrs),根据字符串给对象设置相应的属性
class Test(): #__slots__ = ('name','age') def __init__(self,name,age): self.name = name self.age = age t = Test('sylar',18) choice = input() setattr(t,choice,'Tom') v = getattr(t,choice) print(t.name,v)
delattr(obj,name_str),删除字符串对应的属性
class Test(): #__slots__ = ('name','age') def __init__(self,name,age): self.name = name self.age = age t = Test('sylar',18) choice = input() delattr(t,choice) print(t.name)
来源:https://www.cnblogs.com/ops-sylar/p/8424067.html