zoukankan      html  css  js  c++  java
  • python基础(十一)面向对象和类

    面向对象

    面向对象,简单来说用类对一切对象进行描述的一种编程思维和方法.在这里就不多做介绍(因为我也只是意会到一点点).根据面向对象的概念,我们需要注意的几个概念:

    • 类(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)
    
  • 相关阅读:
    【html】【21】高级篇--搜索框
    【html】【20】高级篇--轮播图[聚焦]
    【html】【19】高级篇--大事件时间轴
    【html】【18】高级篇--下拉列表[竖向手风琴]
    【html】【17】高级篇--loading加载
    【html】【16】高级篇--毛玻璃效果[模糊]
    【html】【15】特效篇--分页
    【html】【14】特效篇--侧边栏客服
    【mysql】【分组】后取每组的top2
    【html】【13】特效篇--下拉导航
  • 原文地址:https://www.cnblogs.com/ops-sylar/p/8424067.html
Copyright © 2011-2022 走看看