zoukankan      html  css  js  c++  java
  • Python基础理论

     

    一 面向对象基本理论

    面向过程:核心是过程,过程就是解决问题的步骤,即先干什么,再干什么

    基于面向过程设计程序,就好比在设计一条流水线,是一种机械思维方法

      优点:复杂的问题简单化

      缺点:可扩展性差(牵一发而动全身)

      应用场景:扩展性低的场合,如linux内核,httpd,git

    面向对象:核心是对象,要理解对象应该把自己当成上帝,在上帝眼中一切存在的事物都是对象,不存在也可以创建出来

      优点:可扩展性强

      缺点:无法像面向过程一样准确地知道什么阶段发生什么事,会有什么结果

      应用场景:与用户交互多的,公司内部的软件,游戏,互联网软件

     

    特征与技能的结合体就是一个对象,一系列对象共有的特征(变量的定义)与技能(函数的定义)的结合体就是类

    在Python中,用变量表示特征,用函数表示技能,因而类是变量与函数的结合体,对象是变量与方法(指向类的函数)的结合体

     

    类的定义:类是一系列对象共有的特征(变量的定义)与技能(函数的定义)的结合体

    PS:在Python3中统一了类型与类的概念

    定义类语法:

    class 类名:

        '''注释'''

        类体(可以是任意代码,在定义阶段就执行,产生了作用域的概念)

    类的使用

    1.  属性的引用,定义类会执行,生成名称空间

      - 数据属性:Chinese.country

      - 函数属性:Chinese.talk('123')  # 需要几个参数,就得传几个参数,如self 

    2.  实例化,类是抽象的,实例化后变为对象

      - p = Chinese()

     

    对象的使用:只有一种,就是属性引用

      - p.country

      - p.talk()   # 会把p当为一个参数传入talk(self)

     

    对象可以有自己的特征值

      def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

     

    类实例化本质

    p1 = Chinese('Linda', 18, 'female')    # Chinese.__init__(p1, 'Linda', 18, 'female')

    self=p1, p1.name=name, p1.age=age, p1.sex=sex 

     

    类名称空间

      - print(Chinese.__dict__)   # 属性字典

    对象名称空间

      - print(p1.__dict__)  # 属性字典

    print(p1.name)  # 等价于 p1.__dict__['name'],本质以变量名的字符串作为key,去调用__dict__,取得值
    print(p1.__dict__['name'])

    对象使用属性时,先在自己对象的名称空间,再找所属类的名称空间

    小结:

    1.  类具有数据属性和函数属性,而对象只有数据属性;但是对象可以调用类的方法

      - Chinese.talk(123)  # 类调用时,和普通方法一样,需几个参数,就传几个参数

      - p1.talk()   # 绑定方法,绑定的含义就是p1默认作为一个参数传入,Chinese.talk(p1)

                              谁来用,就是谁的效果,p1.talk()就是p1的效果,self,__main__.Chinese object

    2.  定义在类内部的变量,是所有对象共有的,id全一样

    3.  定义在类内部的函数,是绑定到所有对象的,是给对象来用,obj.func()会把obj本身当做一个参数

    二  封装、继承、多态

    什么是继承

    继承是一种创建新类的方式,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

    class ParentClass(object):

        pass

    class SubClass(ParentClass):

        pass

    print(SubClass.__bases__)

    抽象即抽取类似或者说比较像的部分

    抽象分成两个层次:

    1.  将奥巴马和梅西这俩抽象比较像的部分抽取成类;

    2.  将人、猪、狗这三个类比较像的部分抽取成父类。

    抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

    继承:是基于抽象的结果,通过编程语言去实现它,肯定先经历抽象这个过程,

    才能通过继承的方式去表达抽象的结构。

    继承的好处一:减少冗余代码

    class People(Animal):

        def __init__(self, name, age, sex, education):

            Animal.__init__(self, name, age, sex)

            self.education = education  

    在子类定义新的属性,覆盖掉父类的属性,称为覆盖,override

    s.bar(), 顺序:对象自己的__dict__,类的__dict__,父类的__dict__,....

    继承反映的是 一种什么是什么的关系

    组合反映的是 一种什么有什么的关系

    继承的实现原理  - Python3  

    '''
    E   D
    A   B   C
        F
    Python3 广度优先:F - A - E - B - D - C
    '''

    在子类调用父类的方法

    super(自己类名, self).__init__()  # 父类的__init__()

    使用super()调用的所有属性,都是从MRO列表当前的位置往后找。

    多态

      同一种事物的多种形态,指的是父类

      people_obj1.talk()
      pig_obj1.talk()
      dog_obj1.talk()
      
         def func(obj):
        obj.talk()

    好处:同一种调用方式,传入不同的对象,实现不同功能

    封装不是单纯的隐藏

    封装数据的主要原因:保护隐私

    封装方法的主要原因:隔离复杂度

     

    封装其实分为两个层面,但无论那种层面的封装,都要对外界提供访问你内部隐藏内容的接口

    第一层面的封装(什么都不用做):创建类和对象分别创建二者的名称空间,我们只能用类名.或者obj.的方式访问里面的名字,这本身就是一种封装

    第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只能在类的内部使用、外部无法访问,或者留下少量(函数)供外部访问

    在Python中用双下划线的方式实现隐藏属性(设置成私有的)

     

    语法层面,定义__x时,自动变为_People__x,这种自动变形的特点:

    1.  类中定义的__x只能在内部使用,如self.__x,引用的是变形后的结果

    2.  这种变形其实是针对外部的变形,在外部是无法通过__x这个名字访问到的

    3.  在子类定义的__x不会覆盖父类定义的__x

     

    property 作为类函数的装饰器,把类的函数属性,变为数据属性

    class Foo(object):
        @property
        def test(self):
            print('from Foo.test')
    
    obj = Foo()
    obj.test

    也是一种封装,当test为名词时,更适合作为属性,而不是方法

    被@property装饰的函数,是不能直接赋值的,得通过@test.setter定义单独函数来设置

    class People(object):
        def __init__(self, name):
            self.__name =name
    
        @property
        def name(self):
            return self.__name
    
        @name.setter
        def name(self,value):
            self.__name = value
    
        @name.deleter
        def name(self):
            del self.__name
    
    
    p1 = People('Linda')
    print(p1.name)
    
    p1.name = 'Alex' 
    print(p1.name)
    
    del p1.name
    print(p1.name)   # 报错

    绑定方法与非绑定方法 

    在类内部定义的,只要没有装饰器,就是绑定到对象的方法,给对象用的,对象默认作为第一个参数传入

    在类内部定义的,有@classmethod装饰器,是绑定到类的方法,给类用的,类默认作为第一个参数传入

    class Foo(object):
        @classmethod
        def test(cls):
            print(cls)
    
    f = Foo()
    Foo.test()  # 类作为第一个参数传进去,结果为:<class '__main__.Foo'>
    f.test()    # 即使是对象调用,也是把所属类传进去,结果为:<class '__main__.Foo'>

    在类的定义定义的,有@staticmethod装饰器,就不是绑定方法了,不存在默认传值的问题,定义几个参数,就传几个参数即可

    class Foo(object):
        @staticmethod
        def test():
            print('from Foo.test')
    
    Foo.test()  # from Foo.test
    f = Foo()
    f.test()    # from Foo.test

    分析小结:

    class Foo(object):
        def test1(self):
            pass
    
        @classmethod
        def test2(cls):
            pass
    
        @staticmethod
        def test3():
            pass
    
    f = Foo()
    print(f.test1)    # <bound method Foo.test1 of <__main__.Foo object at 0x000000D539EB55F8>>
    print(Foo.test2)  # <bound method Foo.test2 of <class '__main__.Foo'>>
    print(f.test3)    # <function Foo.test3 at 0x000000D539EA6D08>
    print(Foo.test3)  # <function Foo.test3 at 0x000000D539EA6D08>

     小例子:

    import settings
    import hashlib
    import time
    
    class MySQL(object):
        def __init__(self, host, port):
            self.id = self.create_id()  # create_id()具有生成唯一id的功能,普通工具包而已
            self.host = host
            self.port = port
            print('connecting...')
    
        @classmethod
        def from_conf(cls):
            return cls(settings.HOST, settings.PORT)  # MySQL('127.0.0.1', 3306),cls功能:实例化,得到对象
    
        @staticmethod    # 非绑定方法,普通工具包,不需传入self或者cls
        def create_id():
            m = hashlib.md5(str(time.clock()).encode('utf-8'))
            return m.hexdigest()
    
        def select(self):
            print('select...')
    
    conn1 = MySQL('192.168.0.1', 3306)  # 第一种初始化,用户输入
    conn2 = MySQL.from_conf()           # 第二种初始化,从配置文件读取
    面向对象高级部分

    1.  isinstance(obj, cls)与issubclass(sub, super)

    isinstance(obj, cls)检查obj是否是类cls的对象

    issubclass(sub, super)检查sub是否是类super的子类

    2.  反射

    反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)

    Python面向对象的反射:通过字符串的形式操作对象相关属性。Python中一切事物都是对象(都可以使用发射)

    四个可以实现自省的函数,下列方法适用于类和对象

    # 判断object中有没有一个name字符串对应的方法或属性
    hasattr(object,name)
    # name作为字符串,获取object的属性或方法
    getattr(object, name, default=None)
    # 设置对象x的属性y=v
    setattr(x, y, v)
    # 删除对象x的属性y
    delattr(x, y)
    class Chinese(object):
        country = 'China'
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    p = Chinese('Linda', 18)
    print(p.name)  # p.__dict__('name')
    # p.x            # 报错 'Chinese' object has no attribute 'x'
    print(hasattr(p, 'x'))   # False
    
    # 设置
    setattr(p, 'x', 112233)  # {'name': 'Linda', 'x': 112233, 'age': 18}
    print(p.__dict__)
    
    # 检测、获取
    if hasattr(p, 'x'):
        res = getattr(p, 'x')
        print(res)   # 112233
    
    # 删除
    delattr(p, 'x')
    print(p.__dict__)  # {'name': 'Linda', 'age': 18}
    四个方法的使用演示
    class Foo(object):
        static_field = "static_filed"
    
        def __init__(self):
            self.name = 'Linda'
    
        def func(self):
            return 'func'
    
        @staticmethod
        def bar():
            return 'bar'
    
    print(getattr(Foo, 'static_field'))
    print(getattr(Foo, 'func'))
    print(getattr(Foo, 'bar'))
    类也是对象
    import sys
    
    def s1():
        print('s1')
    
    def s2():
        print('s2')
    
    this_module = sys.modules[__name__]
    
    print(hasattr(this_module, 's1'))
    print(getattr(this_module, 's2'))
    反射模块当前成员
    """
    程序目录:
    module_test.py
    index.py
    
    当前文件:
    index.py
    """
    
    import module_test as obj
    
    # obj.test()
    
    print(hasattr(obj, 'test'))
    
    getattr(obj,'test')()
    导入其他模块,利用反射查找该模块是否存在某个方法

    反射的好处,可以事先定义好接口,接口只有在被完成后才会真正执行

    程序员A开发了一个ftp客户端,但是没有实现get方法,程序员B得调用这个客户端

    # ftpclient.py
    class FtpClient(object):
        def __init__(self, addr):
            self.addr = addr
            print('正在连接[%s]...' % self.addr)
    
        # def get(self):
        #     print('正在下载...')
    ftpclient.py
    import ftpclient
    f1 = ftpclient.FtpClient('192.168.0.1')
    
    if hasattr(f1, 'get'):
        func = getattr(f1, 'get')
        func()
    print('其他程序1')
    print('其他程序2')
    print('其他程序3')
    print('其他程序4')
    引用ftpclient.py

    类基于用户输入的字符串,反射自己是否有相应的方法,从而自动执行

    class FtpClient(object):
        def __init__(self, addr):
            self.addr = addr
            print('正在连接[%s]....' % self.addr)
    
        def get(self, arg):
            print('正在下载[%s]....' % (arg[1]))
    
        def run(self):
            while True:
                inp = input('>>: ').strip()
                inp_list = inp.split()
                if hasattr(self, inp_list[0]):
                    func = getattr(self, inp_list[0])
                    func(inp_list)
    
    f1 = FtpClient('192.168.0.1')
    f1.run()
    交互式反射应用

    反射另外好处,动态导入模块(基于反射当前模块成员)

    m = __import__('sys')
    print(m.path)
    
    import importlib
    m2 = importlib.import_module('sys')
    print(m2.path)
    动态导入模块

    3.  __str__()

    print(obj) 调用obj.__str__()

    det __str__(self):

      # 必须有返回值,且必须返回字符串类型

      return 'xxxxxxx'

    4.  __del__()

    析构函数,对象被删除的时候,立刻执行obj.__del__(),自动回收内存等,也可以写一些清除数据库连接等操作

    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __del__(self):  # 析构函数
            print('del---->')
    
    obj = Foo('Linda', 18)
    # del obj
    print('=========>')
    View Code

    5.  __setitem__(), __getitem__(), __delitem__()

    把对象模拟成字典形式操作,和字典就可以统一处理了

    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __getitem__(self, item):
            print('from __getitem__()')
            return self.__dict__[item]
    
        def __setitem__(self, key, value):
            print('from __setitem__')
            self.__dict__[key] = value
    
        def __delitem__(self, key):
            print('from __delitem__')
            self.__dict__.pop(key)
    
    obj = Foo('Linda', 18)
    print(obj['name'])  # 触发self.__getitem__()执行
    
    obj['name']  = 'Jonathan' # 触发self.__setitem__()执行
    print(obj.name)
    
    del obj['name']
    print(obj.name)  # 'Foo' object has no attribute 'name'
    View Code

    6.  __setattr__(), __getattr__(), __delattr__()

    对象操作属性时,触发相应函数

    class Foo(object):
    
        def __setattr__(self, key, value):
            print('form __setattr__')
            self.__dict__[key] = value
    
        def __getattr__(self, item):
            print('from __getattr__')
    
        def __delattr__(self, item):
            print('from __delattr__')
    
    obj = Foo()
    obj.x = 1          # 设置属性时,会触发执行__setattr__()执行
    print(obj.__dict__)
    print(obj.yyyyy)   # 没有属性yyyyy的时候才会触发 __getatrr__()执行
    del obj.x         # 删除属性时,会触发执行__delattr__()执行
    View Code

    7.   加工标准类型

    继承 class List(list):pass

    授权 class Open(object):pass   关键点  def __getattr__():pass

    class Open(object):
        def __init__(self, file_path, mode='r', encoding='utf-8'):
            self.file_path = file_path
            self.mode = mode
            self.encoding = encoding
            self.f = open(self.file_path, mode=self.mode, encoding=self.encoding)
    
        def __getattr__(self, item):
            print(item, type(item))
            return getattr(self.f, item)
    
    
    obj = Open('a.txt',mode='r')
    obj.seek  # seek <class 'str'>
    View Code

    8.  __next__() 和 __iter__()实现迭代器协议

    class Foo(object):
        def __init__(self, n, stop):
            self.n = n
            self.stop = stop
            
        def __next__(self):
            if self.n >= self.stop:
                raise StopIteration
            x = self.n
            self.n += 1
            return x
    
        def __iter__(self):
            return self
    
    
    obj = Foo(0, 100)
    print(next(obj))
    print(next(obj))
    
    from collections import Iterator
    print(isinstance(obj, Iterator))
    
    for i in obj:
        print(i)
    View Code

    9. __doc__()

    class Foo:
        '我是描述信息'
        pass
    
    print(Foo.__doc__)
    它类的描述信息
    class Foo:
        '我是描述信息'
        pass
    
    class Bar(Foo):
        pass
    print(Bar.__doc__) #该属性无法继承给子类
    该属性无法被继承

    10.  __module__(), __class__()

    __module__ 表示当前操作的对象在那个模块

    __class__     表示当前操作的对象的类是什么

    11.  __enter__(), __exit__()

    我们知道在操作文件对象的时候可以这么写

    with open('a.txt') as f:
       '代码块'

    上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

    class Foo(object):
        def __enter__(self):
            print('__enter__')
            return 'aaaa'
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('__exit__')
    
    with Foo() as f:  # f = Foo(),触发def__enter__()执行
        print(f)
        print('----->')
        print('----->')
        print('----->')
        pass
    
    # 最后触发 __exit__()执行
    View Code

    __exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行

    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            print(exc_type)
            print(exc_val)
            print(exc_tb)
    
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100) #------------------------------->不会执行
    View Code

    如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行

    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            print(exc_type)
            print(exc_val)
            print(exc_tb)
            return True
    
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100) #------------------------------->会执行
    View Code
    class Open:
        def __init__(self,filepath,mode='r',encoding='utf-8'):
            self.filepath=filepath
            self.mode=mode
            self.encoding=encoding
    
        def __enter__(self):
            # print('enter')
            self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
            return self.f
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            # print('exit')
            self.f.close()
            return True 
        def __getattr__(self, item):
            return getattr(self.f,item)
    
    with Open('a.txt','w') as f:
        print(f)
        f.write('aaaaaa')
        f.wasdf #抛出异常,交给__exit__处理
    练习:模拟Open

    用途或者说好处:

    • 使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

    • 在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

    12.  __call__()

    对象后面加括号,触发执行。

    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    class Foo:
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('__call__')
    
    obj = Foo()  # 执行 __init__
    obj()        # 执行 __call__
  • 相关阅读:
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
    UVA 11100 The Trip, 2007 (贪心)
    JXNU暑期选拔赛
    计蒜客---N的-2进制表示
    计蒜客---线段的总长
    计蒜客---最大质因数
    JustOj 2009: P1016 (dp)
  • 原文地址:https://www.cnblogs.com/jonathan1314/p/7746520.html
Copyright © 2011-2022 走看看