zoukankan      html  css  js  c++  java
  • 面向对象进阶

    一、isistance(obj,cls)和issubclass(sub,supper)

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

    class Foo(object):
        pass
     
    obj = Foo()
     
    isinstance(obj, Foo)
    

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

    class Foo(object):
        pass
     
    class Bar(Foo):
        pass
     
    issubclass(Bar, Foo)

    二、反射

      一、什么是反射

    反射的概念式有Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

      二、Python中面向对象中的反射

    通过字符串的形式操作对象先关的属性。Python中的一切事物都是对象,都可以使用反射。

      1、反射相关的四个函数(适用于类和对象:Python中一切皆对象,类本身也是一个对象)

    1、hasattr(object,name)
    判断object中有没有一个name字符串对应的方法或属性
    
    2、getattr(object, name, default=None)
    def getattr(object, name, default=None): # known special case of getattr
        """
        getattr(object, name[, default]) -> value
    
        Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
        When a default argument is given, it is returned when the attribute doesn't
        exist; without it, an exception is raised in that case.
        """
        pass
    
    3、setattr(x, y, v)
    def setattr(x, y, v): # real signature unknown; restored from __doc__
        """
        Sets the named attribute on the given object to the specified value.
    
        setattr(x, 'y', v) is equivalent to ``x.y = v''
        """
        pass
    
    4、delattr(x, y)
    def delattr(x, y): # real signature unknown; restored from __doc__
        """
        Deletes the named attribute from the given object.
    
        delattr(x, 'y') is equivalent to ``del x.y''
        """
        pass

      2、使用实践

    应用:可以判断使用模块或者类中是否包含某个属性或方法,有则执行,没有告知。

    • 类:反射静态属性,类方法
    • 对象:反射方法和属性
    • 模块:反射方法、变量
    • 本模块:反射函数、变量
     1 # 通过输入的内容,找到相应的值
     2 class Person:
     3     role = 'Person'
     4     country = 'China'
     5 
     6     def __init__(self,name,age):
     7         self.name = name
     8         self.age = age
     9 
    10     def func(self):
    11         print('%s in func' %self.name)
    12 alex = Person('alex',20)
    13 # # 通过反射调用类中的属性
    14 # name = input('属性名:')
    15 # 判断类中是否有相应的属性,有的话,返回结果;没有的话,什么都不做
    16 # person.role
    17 if hasattr(Person,name):
    18     print(getattr(Person,name))
    19 
    20 # 通过输入字符串的形式,访问类中的变量   alex.name alex.age
    21 if hasattr(alex,'age'):
    22     print(getattr(alex,'age'))
    23 
    24 # 通过反射调用类中的方法
    25 if hasattr(alex,'func'):
    26     func = getattr(alex,'func')
    27     func()
    28 
    29 
    30 def func2(self):
    31     print('%s in func2' % self.name)
    32 # # setattr
    33 # alex.sex = None
    34 # setattr(alex,'sex','不详')
    35 # print(alex.sex)
    36 
    37 # setattr(alex,'func2',func2)  ##setattr绑定方法是一个假的,在使用的时候必须要手动传self
    38 # alex.func2(alex)
    39 # print(alex.func)
    40 
    41 
    42 # delattr
    43 # delattr(alex,'name')  #等价于del alex.name  ##删除属性

      三、使用反射的好处

    好处一:实现可插拔机制

    有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    1 class FtpClient:
    2     'ftp客户端,但是还么有实现具体的功能'
    3     def __init__(self,addr):
    4         print('正在连接服务器[%s]' %addr)
    5         self.addr=addr
    egon还没有完成功能
    1 #from module import FtpClient
    2 f1=FtpClient('192.168.1.1')
    3 if hasattr(f1,'get'):
    4     func_get=getattr(f1,'get')
    5     func_get()
    6 else:
    7     print('---->不存在此方法')
    8     print('处理其他的逻辑')
    不影响lili代码编写

    好处二:动态导入模块(基于反射当前模块成员)

    三、类中的装饰器property、classmethod和staticmethod

    一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):

        1. 绑定到类的方法:用classmethod装饰器装饰的方法。

        为类量身定制

        类.boud_method(),自动将类当作第一个参数传入

        (其实对象也可调用,但仍将类当作第一个参数传入)

        2. 绑定到对象的方法:没有被任何装饰器装饰的方法。

        为对象量身定制

        对象.boud_method(),自动将对象当作第一个参数传入

        (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

    二:非绑定方法:用staticmethod装饰器装饰的方法

       1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已

       注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

      一、property 将功能属性转化为数据属性

      1、计算圆的周长和面积

     1 # area和perimeter方法伪装成属性
     2 from math import pi
     3 class Circle:
     4     def __init__(self,r):
     5         self.r = r
     6     @property
     7     def perimeter(self):
     8         return self.r*pi*2
     9     @property
    10     def area(self):
    11         return pi*self.r**2
    12 c1 = Circle(5)
    13 print(c1.area)
    14 print(c1.perimeter)

      2、在类的外面访问类的私有属性

    1 class A:
    2     def __init__(self,name):
    3         self.__name = name
    4 
    5     @property
    6     def name(self):
    7         return self.__name
    8 a = A('alex')
    9 print(a.name)

      3、在外面可以访问私有属性,又可以修改私有属性

      名字必须要相同

     1 class A:
     2     def __init__(self,name):
     3         self.__name = name
     4 
     5     @property
     6     def name(self):
     7         return self.__name
     8     @name.setter
     9     def name(self,new_name): ##可以做出限制
    10         if type(new_name) is str:  
    11             self.__name = new_name
    12 a = A('alex')
    13 # print(a.name)
    14 a.name = 'alex_sb'
    15 print(a.name)

      二、classmethod绑定给类的方法

       classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法

    1 #!/usr/bin/env python
    2 # -*- coding:utf-8 -*-
    3 # __author__ = "wzs"
    4 #2017/11/6
    5 
    6 HOST='127.0.0.1'
    7 PORT=3306
    8 DB_PATH=r'G:dataPyCharm_ProjectPythons19day8面向对象编程db'
    settings.py
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/11/6
     5 
     6 import settings
     7 class MySQL:
     8     def __init__(self,host,port):
     9         self.host=host
    10         self.port=port
    11 
    12     @classmethod
    13     def from_conf(cls):
    14         print(cls)
    15         return cls(settings.HOST,settings.PORT)
    16 
    17 print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>>
    18 conn=MySQL.from_conf()
    19 
    20 conn.from_conf() #对象也可以调用,但是默认传的第一个参数仍然是类
    db.py

      三、staticmethod

      在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数(将外面的函数想放在类中使用,需要放到相关的类中,前面加上@staticmethod)

      staticmethod不与类或对象绑定,谁都可以调用,没有自动传值效果

    应用场景:完全的面向对象编程——需将所有的方法代码都必须写类里,只能把原来的函数写进类里(原本又只是函数,所以就加上一个staticmethod装饰器)

     1 import hashlib
     2 import time
     3 class MySQL:
     4     def __init__(self,host,port):
     5         self.id=self.create_id()
     6         self.host=host
     7         self.port=port
     8     @staticmethod
     9     def create_id(): #就是一个普通工具
    10         m=hashlib.md5(str(time.time()).encode('utf-8'))
    11         return m.hexdigest()
    12 
    13 
    14 print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看结果为普通函数
    15 conn=MySQL('127.0.0.1',3306)
    16 print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看结果为普通函数
    staticmethod

      四、classmethod与staticmethod的区别

     1 class A:
     2     country = 'China'
     3     #必须先是实例化才能调用对象的方法且可以使用示例的属性
     4     def func(self):
     5         self.name = 'alex'
     6 
     7     @classmethod #类方法:不需要传具体的对象,但是可以使用类的静态属性
     8     def c_method(cls):
     9         print('in class method')
    10         print(cls.country)
    11 
    12     @staticmethod ##静态方法:不需要传任何参数,但是也不能使用任何属性
    13     def s_method():
    14         print('in the static method')
    15 
    16 A.c_method()
    17 A.s_method()
    简单
     1 import settings
     2 class MySQL:
     3     def __init__(self,host,port):
     4         self.host=host
     5         self.port=port
     6 
     7     @staticmethod
     8     def from_conf():
     9         return MySQL(settings.HOST,settings.PORT)
    10 
    11     # @classmethod #哪个类来调用,就将哪个类当做第一个参数传入
    12     # def from_conf(cls):
    13     #     return cls(settings.HOST,settings.PORT)
    14 
    15     def __str__(self):
    16         return '就不告诉你'
    17 
    18 class Mariadb(MySQL):
    19     def __str__(self):
    20         return '<%s:%s>' %(self.host,self.port)
    21 
    22 
    23 m=Mariadb.from_conf()
    24 print(m) #我们的意图是想触发Mariadb.__str__,但是结果触发了MySQL.__str__的执行,打印就不告诉你:
    深入:mariadb是mysql

      五、练习

      1、定义MySQL类

      1.对象有id、host、port三个属性
      2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一
      3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化
      4.为对象定制方法,save和get_obj_by_id,save能自动将对象序列化到文件中,文件路径为配置文件中DB_PATH,文件名为id号,保存之前验证对象是否已经存在,若存在则抛出异常,;get_obj_by_id方法用来从文件中反序列化出对象

    原文链接:http://www.cnblogs.com/dkblog/archive/2011/10/10/2205200.html
     Python官方Doc:《20.15. uuid — UUID objects according to RFC 4122》
        UUID的算法介绍:《A Universally Unique IDentifier (UUID) URN Namespace》
    
    概述:
    
        UUID是128位的全局唯一标识符,通常由32字节的字符串表示。
        它可以保证时间和空间的唯一性,也称为GUID,全称为:
                UUID —— Universally Unique IDentifier      Python 中叫 UUID
                GUID —— Globally Unique IDentifier          C#  中叫 GUID
    
        它通过MAC地址、时间戳、命名空间、随机数、伪随机数来保证生成ID的唯一性。
        UUID主要有五个算法,也就是五种方法来实现:
    
           1、uuid1()——基于时间戳
    
                   由MAC地址、当前时间戳、随机数生成。可以保证全球范围内的唯一性,
                   但MAC的使用同时带来安全性问题,局域网中可以使用IP来代替MAC。
    
           2、uuid2()——基于分布式计算环境DCE(Python中没有这个函数)
    
                    算法与uuid1相同,不同的是把时间戳的前4位置换为POSIX的UID。
                    实际中很少用到该方法。
    
          3、uuid3()——基于名字的MD5散列值
    
                    通过计算名字和命名空间的MD5散列值得到,保证了同一命名空间中不同名字的唯一性,
                    和不同命名空间的唯一性,但同一命名空间的同一名字生成相同的uuid。    
    
           4、uuid4()——基于随机数
    
                    由伪随机数得到,有一定的重复概率,该概率可以计算出来。
    
           5、uuid5()——基于名字的SHA-1散列值
    
                    算法与uuid3相同,不同的是使用 Secure Hash Algorithm 1 算法
    
    使用方面:
    
        首先,Python中没有基于DCE的,所以uuid2可以忽略;
        其次,uuid4存在概率性重复,由无映射性,最好不用;
        再次,若在Global的分布式计算环境下,最好用uuid1;
        最后,若有名字的唯一性要求,最好用uuid3或uuid5。
    
    编码方法:
    
        # -*- coding: utf-8 -*-
    
        import uuid
    
        name = "test_name"
        namespace = "test_namespace"
    
        print uuid.uuid1()  # 带参的方法参见Python Doc
        print uuid.uuid3(namespace, name)
        print uuid.uuid4()
        print uuid.uuid5(namespace, name)
    创建唯一id之UUID
     1 #settings.py内容
     2 '''
     3 HOST='127.0.0.1'
     4 PORT=3306
     5 DB_PATH=r'E:CMSaaadb'
     6 '''
     7 import settings
     8 import uuid
     9 import pickle
    10 import os
    11 class MySQL:
    12     def __init__(self,host,port):
    13         self.id=self.create_id()
    14         self.host=host
    15         self.port=port
    16 
    17     def save(self):
    18         if not self.is_exists:
    19             raise PermissionError('对象已存在')
    20         file_path=r'%s%s%s' %(settings.DB_PATH,os.sep,self.id)
    21         pickle.dump(self,open(file_path,'wb'))
    22 
    23     @property
    24     def is_exists(self):
    25         tag=True
    26         files=os.listdir(settings.DB_PATH)
    27         for file in files:
    28             file_abspath=r'%s%s%s' %(settings.DB_PATH,os.sep,file)
    29             obj=pickle.load(open(file_abspath,'rb'))
    30             if self.host == obj.host and self.port == obj.port:
    31                 tag=False
    32                 break
    33         return tag
    34     @staticmethod
    35     def get_obj_by_id(id):
    36         file_abspath = r'%s%s%s' % (settings.DB_PATH, os.sep, id)
    37         return pickle.load(open(file_abspath,'rb'))
    38 
    39     @staticmethod
    40     def create_id():
    41         return str(uuid.uuid1())
    42 
    43     @classmethod
    44     def from_conf(cls):
    45         print(cls)
    46         return cls(settings.HOST,settings.PORT)
    47 
    48 # print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>>
    49 conn=MySQL.from_conf()
    50 conn.save()
    51 
    52 conn1=MySQL('127.0.0.1',3306)
    53 conn1.save() #抛出异常PermissionError: 对象已存在
    54 
    55 
    56 obj=MySQL.get_obj_by_id('7e6c5ec0-7e9f-11e7-9acc-408d5c2f84ca')
    57 print(obj.host)
    settings.py

      2、其他练习

     1 class Date:
     2     def __init__(self,year,month,day):
     3         self.year=year
     4         self.month=month
     5         self.day=day
     6     @staticmethod
     7     def now(): #用Date.now()的形式去产生实例,该实例用的是当前时间
     8         t=time.localtime() #获取结构化的时间格式
     9         return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
    10     @staticmethod
    11     def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
    12         t=time.localtime(time.time()+86400)
    13         return Date(t.tm_year,t.tm_mon,t.tm_mday)
    14 
    15 a=Date('1987',11,27) #自己定义时间
    16 b=Date.now() #采用当前时间
    17 c=Date.tomorrow() #采用明天的时间
    18 
    19 print(a.year,a.month,a.day)
    20 print(b.year,b.month,b.day)
    21 print(c.year,c.month,c.day)
    22 
    23 
    24 #分割线==============================
    25 import time
    26 class Date:
    27     def __init__(self,year,month,day):
    28         self.year=year
    29         self.month=month
    30         self.day=day
    31     @staticmethod
    32     def now():
    33         t=time.localtime()
    34         return Date(t.tm_year,t.tm_mon,t.tm_mday)
    35 
    36 class EuroDate(Date):
    37     def __str__(self):
    38         return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
    39 
    40 e=EuroDate.now()
    41 print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
    42 '''
    43 输出结果:
    44 <__main__.Date object at 0x1013f9d68>
    45 '''
    46 因为e就是用Date类产生的,所以根本不会触发EuroDate.__str__,解决方法就是用classmethod
    47 
    48 import time
    49 class Date:
    50     def __init__(self,year,month,day):
    51         self.year=year
    52         self.month=month
    53         self.day=day
    54     # @staticmethod
    55     # def now():
    56     #     t=time.localtime()
    57     #     return Date(t.tm_year,t.tm_mon,t.tm_mday)
    58 
    59     @classmethod #改成类方法
    60     def now(cls):
    61         t=time.localtime()
    62         return cls(t.tm_year,t.tm_mon,t.tm_mday) #哪个类来调用,即用哪个类cls来实例化
    63 
    64 class EuroDate(Date):
    65     def __str__(self):
    66         return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
    67 
    68 e=EuroDate.now()
    69 print(e) #我们的意图是想触发EuroDate.__str__,此时e就是由EuroDate产生的,所以会如我们所愿
    70 '''
    71 输出结果:
    72 year:2017 month:3 day:3
    73 '''
    其他练习

    四、其他

    见链接 http://www.cnblogs.com/linhaifeng/articles/6204014.htm

    http://www.cnblogs.com/Eva-J/articles/7351812.htm

  • 相关阅读:
    request常用的方法
    JS通过正则限制 input 输入框只能输入整数、小数(金额或者现金)
    基于云原生的秒杀系统设计思路
    html<input>输入框中各种正则表达式设置
    cursor:hand与cursor:pointer的区别介绍
    读入/输出优化
    手动扩栈,防止溢出
    快速乘(O(1))
    二分图若干性质
    康拓展开
  • 原文地址:https://www.cnblogs.com/happy-king/p/7793860.html
Copyright © 2011-2022 走看看