• python学习笔记六 面向对象相关下(基础篇)


    面向对象基本知识:

    • 面向对象是一种编程方式,此编程方式的实现是基于对 对象 的使用
    • 类 是一个模板,模板中包装了多个“函数”供使用(可以将多函数中公用的变量封装到对象中)
    • 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
    • 面向对象三大特性:封装、继承和多态

    面向对象类成员

    一、变量

    变量包括:类变量和实例变量,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

    类变量:属于类

    实例变量:属于实例

    class Role(object):
        #类变量,在内存中仅保存一份
        ac = None 
        def __init__(self,name,role,weapon,life_value):
            #实例变量,保存在各个实例中
            self.name = name   
            self.role = role
            self.weapon = weapon
            self.life_value = life_value
    
        def buy_gun(self,weapon):
            print("%s is buying [%s]" %(self.name,weapon))
            self.weapon = weapon
    
    p1 = Role("p1",'police','b12',100)
    t1 = Role("t1",'tufei','b11',100)
    t2 = Role("t2",'tufei','b13',100)
    t3 = Role("t3",'tufei','b14',100)
    
    #实例赋值,将创建新的变量给实例
    p1.ac = "China Brand"
    t1.ac = "US Brand"
    #类变量赋值,实例中没有创建该变量,继续使用类变量赋的值
    Role.ac = "JP Brand"
    print("p1:",p1.weapon,p1.ac)
    print("t1:",t1.weapon,t1.ac)
    print("t2:",t2.weapon,t2.ac)
    print("t3:",t3.weapon,t3.ac)

    由上述代码可以看出【实例变量需要通过对象来访问】【类变量可以通过类访问】,在使用上可以看出类变量和实例变量的归属是不同的。其在内容的存储方式类似如下图:

    由上图可知:

    • 类变量在内存中只保存一份
    • 实例变量在每个实例中都要保存一份

    应用场景: 通过类创建实例时,如果每个对象都具有相同的变量,那么就使用类变量。

    二、方法

    方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

    • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
    • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
    • 静态方法:由调用;无默认参数;
    class Foo:
        def __init__(self, name):
            self.name = name
    
        def ord_func(self):
            """ 定义普通方法,至少有一个self参数 """
            # print self.name
            print('普通方法')
    
        @classmethod
        #类方法,不能访问实例变量
        def class_func(cls):
            """ 定义类方法,至少有一个cls参数 """
            print('类方法')
    
        @staticmethod
        #静态方法,只是放在类下面,不能访问类和实例属性
        def static_func():
            """ 定义静态方法 ,无默认参数"""
            print('静态方法')

    相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

    不同点:方法调用者不同、调用方法时自动传入的参数不同。

    三、属性  

    如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

    对于属性,有以下三个知识点:

    • 属性的基本使用
    • 属性的两种定义方式
    class foo(object):
        def __init__(self,name):
            self.name = name
            self.num = None
        #属性,将普通方法变成属性
        @property
        def total_num(self):
            return self.num
    
        @total_num.setter
        def total_num(self,num):
            self.num = num
            print("total number is:",self.num)
    
        @total_num.deleter
        def total_num(self):
            print("total number got deleted")
            del self.num
    
    #实例化 d
    = Animal("who") #调用属性
    print(d.total_num) #属性赋值
    d.total_num
    = 3 #删除属性
    del d.total_num #报错num已经被删除
    print(d.total_num)

    由属性的定义和调用要注意一下几点:

    • 定义时,在普通方法的基础上添加 @property 装饰器;
    • 定义时,属性仅有一个self参数
    • 调用时,无需括号
                 方法:obj.func()
                 属性:obj.total_num

    注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

            属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

    四、类的私有化

    类的所有成员都有两种形式:

    • 公有成员,在任何地方都能访问
    • 私有成员,只有在类的内部才能方法

    定义不同私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)

    class Animal(object):
        def __init__(self, name):
            self.name = name #公有变量
            self.__num = None #私有变量 

    访问限制:只有在类的内部可以访问。。。

    class C(object):
        __name = "私有类变量"
        def func(self):
            print(C.__name)
    
    class D(C):
        def show(self):
            print(C.__name) #AttributeError: type object 'C' has no attribute '_D__name'
            #print(D.__name) #AttributeError: type object 'D' has no attribute '_D__name'
    
    C.__name #类访问,出错
    obj = C()
    obj.func() #类内部可以访问
    obj_son = D()  #无法继承私有类属性
    obj_son.show() #派生类访问,出错
    class E(object):
        def __init__(self):
            self.__foo = "私有实例变量"
        def func(self):
            print(self.__foo) #类内部访问
    class F(E):
        def show(self):
            print(self.__foo) #派生类访问
    
    obj2 = E()
    obj2.__foo #通过对象直接访问,出错
    print(obj2._E__foo) #访问私有实例变量
    obj2.func() #类内部访问
    obj2_son = F()
    obj2_son.show() #派生类中访问,出错
    方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用,无法被继承
    ps:非要访问私有属性的话,可以通过 对象._类__属性名

    五、类的特殊成员
    class foo(object):
        """
        __doc__显示类的描述信息
        """
        def __init__(self):
            """
            注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;
            """
            self.name = None
            self.age  = None
            self.sq = []
        def __call__(self):
            """
            __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
            """
            print("__call__")
        def __str__(self):
            """
            如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
            :return:
            """
            return ""
        def __iter__(self):
            """
            用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
            """
            return iter(self.sq)
        def __del__(self):
            pass
        #def __new__(self):
            """
            __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
            一般不用使用这个方法,否则你将无法实例化对象
            """
            #pass
    
    #实例化对象 f
    = foo() #自动执行__init__方法 f() #:对象() 或者 类()()调用__call__ foo()() #调用call方法 print(f.__doc__) #显示类的描述信息 print(f.__dict__) #类或对象中的所有成员 print(f) #方法输出__str__方法定义的返回值 for i in f:print(i) #类型内部定义了 __iter__,可以迭代


    #test.py
    import foo
    obj = foo()
    print(obj.__module__) # 表示当前操作的对象在那个模块
    print(obj.__class__) # 表示当前操作的对象在那个类
    print(isinstance(obj,foo))
    
    

     __module__ 和  __class__ 

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

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

    复制代码
    class C:
    
        def __init__(self):
            self.name = 'wupeiqi'
    复制代码
    from lib.aa import C
    
    obj = C()
    print obj.__module__  # 输出 lib.aa,即:输出模块
    print obj.__class__      # 输出 lib.aa.C,即:输出类

    __dict__

      类或对象中的所有成员

    上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

    class Province:
    
        country = 'China'
    
        def __init__(self, name, count):
            self.name = name
            self.count = count
    
        def func(self, *args, **kwargs):
            print 'func'
    
    # 获取类的成员,即:静态字段、方法、
    print Province.__dict__
    # 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
    
    obj1 = Province('HeBei',10000)
    print obj1.__dict__
    # 获取 对象obj1 的成员
    # 输出:{'count': 10000, 'name': 'HeBei'}
    
    obj2 = Province('HeNan', 3888)
    print obj2.__dict__
    # 获取 对象obj1 的成员
    # 输出:{'count': 3888, 'name': 'HeNan'}
    __dict__

    __iter__ 

    用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ 

    class Foo(object):
        pass
    
    
    obj = Foo()
    
    for i in obj:
        print i
        
    # 报错:TypeError: 'Foo' object is not iterable
    第一步
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    class Foo(object):
        
        def __iter__(self):
            pass
    
    obj = Foo()
    
    for i in obj:
        print i
    
    # 报错:TypeError: iter() returned non-iterator of type 'NoneType'
    第二步
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    class Foo(object):
    
        def __init__(self, sq):
            self.sq = sq
    
        def __iter__(self):
            return iter(self.sq)
    
    obj = Foo([11,22,33,44])
    
    for i in obj:
        print i
    第三步
    以上步骤可以看出,for循环迭代的其实是  iter([11,22,33,44]) ,所以执行流程可以变更为
    #!/usr/bin/env python # -*- coding:utf-8 -*- obj = iter([11,22,33,44]) for i in obj: print i

    六、反射
    python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,这四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

    class Foo(object):
     
        def __init__(self):
            self.name = 'wupeiqi'
     
        def func(self):
            return 'func'
     
    obj = Foo()
     
    # #### 检查是否含有成员 ####
    hasattr(obj, 'name')
    hasattr(obj, 'func')
     
    # #### 获取成员 ####
    getattr(obj, 'name')
    getattr(obj, 'func')
     
    # #### 设置成员 ####
    setattr(obj, 'age', 18)
    setattr(obj, 'show', lambda num: num + 1)
     
    # #### 删除成员 ####
    delattr(obj, 'name')
    delattr(obj, 'func')
    反射实例
    import sys
    class Webserver(object):
        def __init__(self,host,port):
            self.host = host
            self.port = port
        def start(self):
            print("Server is starting...")
        def stop(self):
            print("Server is stopping...")
        def restart(self):
            self.stop()
            self.start()
    
    #def test_run(name):
    #    print("test running...",name)
    
    def test_run(self,name): #定义函数,setter添加该函数至实例方法
        print("test running...",name,self.host)
    
    if __name__ == "__main__":
    server
    = Webserver("1.1.1.1",9999) server2 = Webserver("2.2.2.2",9999)
    #第三种实现 反射
    if hasattr(server,sys.argv[1]): #判断sys.argv[1]是否在对象server中 func = getattr(server,sys.argv[1]) #获取server.method内存地址 func() #执行server.method()
    setattr(server,
    "run",test_run) #在该实例 server 中,添加方法 run 方法名,test_run 函数,无法为方法自动传入self #server.run("koka") #执行添加不带self参数的test_run,无法调用实例变量 server.run(server,"koka") #执行添加self参数的test_run,调用的时候需要手动添加实例
    setattr(server,
    "root","koka") #该在实例中添加变量,同上 print(server.root)      #调用实例变量
    #print(server2.root) #其他实例无法调用
    delattr(Webserver,
    'start') #删除类中的start方法
    print(server.restart())
    """ 判断用户输入是否存在实例 #第一种实现 一个一个输出匹配 if sys.argv[1] == "start":     执行server.start() #第二种实现 定义字典查找 cmd_dic ={ "start":server.start, "stop":server.stop } if sys.argv[1] in cmd_dic: cmd_dic[sys.argv[1]]() """

    结论:反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

    更多内容请参考:http://www.cnblogs.com/wupeiqi/articles/5017742.html

    七、异常处理

    在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!

    try:
        pass
    except Exception,ex:
        pass
    常用的内建异常类 
    Exception                                    所有异常类的基类
    AttributeError                               特性引用或赋值失败时引发
    IOError                                      试图打开不存在文件(报或其他情况)时引发
    IndexError                                   在使用序列中不存在的索引时引发
    KeyError                                     在使用映射中不存在的键是引发
    NameError                                    在找不到名字(变量)时引发
    SyntaxError                                  在代码为错误形式时引发
    TypeError                                    在内建操作或者函数应用于错误类型的对象时引发
    ValueError                                   在内建操作或者函数应用于正确类型的对象,但是该对象使用不合适的值时引发
    ZeroDivisionError                            在除法或者模除操作的第二个参数为0时引发 
    try..except

    万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:

    try:
      s = input('Enter something --> ')
    except EOFError:
      print('
    Why did you do an EOF on me?')
      sys.exit() # exit the program
    except Exception: # 对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行
      print('
    Some error/exception occurred.')
      # here, we are not exiting the program
    手动触发异常
    Raise IndexError 
     
    如果捕捉到异常,但是有想重新引发它(也就是说要传递异常参数),那么可以调用不带参数的异常(还能在捕捉到异常的时候显示的提供具体异常)
     
    多个异常语句
    s1 = 'hello'
    try:
        int(s1)
    except KeyError as e:
        print('键错误')
    except IndexError as e:
        print('索引错误')
    except Exception as e:
        print('错误')
    try..finally
    try:
      f = open('poem.txt')
      while True: # our usual file-reading idiom
        line = f.readline()
        if len(line) == 0:
          break
        time.sleep(2)
        print(line)
    finally:
      f.close()
      print('Cleaning up...closed the file')
     
    class MyException(Exception):
      pass
    try:
      print("normal code here")
    except MyException:
      print("MyException encoutered")
    else:
      print "No exception” 
    自定义异常
    class MyException(Exception):
        pass
    try:
        #some code here
        raise MyException
    except MyException:
        print("MyException encoutered")
  • 相关阅读:
    ubuntu系统里常用的几个命令
    Vue中常用知识点demo
    Vue基础知识学习(后端)
    ubuntu内lnmp相关操作命令
    linux下安装lnmp集成环境
    js时间戳与日期格式之间相互转换
    yii2中 选择布局的方式,可以设置不使用布局
    yii2中通过migration创建数据表
    php实现支付宝在线支付和扫码支付demo
    linux下添加用户并将文件夹授权给某一个用户
  • 原文地址:https://www.cnblogs.com/koka24/p/5226786.html
Copyright © 2020-2023  润新知