zoukankan      html  css  js  c++  java
  • day7--面向对象进阶(内含反射和item系列)

    一面向对象的结构和成员

    1.1面向对象的结构

    class A:
    
        company_name = '老男孩教育'  # 静态变量(静态字段)
        __iphone = '1353333xxxx'  # 私有静态变量(私有静态字段)
    
    
        def __init__(self,name,age): #普通方法(构造方法)
    
            self.name = name  #对象属性(普通字段)
            self.__age = age  # 私有对象属性(私有普通字段)
    
        def func1(self):  # 普通方法
            pass
    
        def __func(self): #私有方法
            print(666)
    
    
        @classmethod  # 类方法
        def class_func(cls):
            """ 定义类方法,至少有一个cls参数 """
            print('类方法')
    
        @staticmethod  #静态方法
        def static_func():
            """ 定义静态方法 ,无默认参数"""
            print('静态方法')
    
        @property  # 属性
        def prop(self):
            pass
    View Code

    1.2面向对象的私有和公有

    对于静态字段(静态变量),普通字段(对象属性),方法

    公有:类可以访问,类内部可以访问,派生类可以访问

    私有:仅类内部可以访问

    class C:
    
        name = "公有静态字段"
    
        def func(self):
            print C.name
    
    class D(C):
    
        def show(self):
            print C.name
    
    
    C.name         # 类访问
    
    obj = C()
    obj.func()     # 类内部可以访问
    
    obj_son = D()
    obj_son.show() # 派生类中可以访问
    公有静态字段
    class C:
    
        __name = "私有静态字段"
    
        def func(self):
            print C.__name
    
    class D(C):
    
        def show(self):
            print C.__name
    
    
    C.__name       # 不可在外部访问
    
    obj = C()
    obj.__name  # 不可在外部访问
    obj.func()     # 类内部可以访问   
    
    obj_son = D()
    obj_son.show() #不可在派生类中可以访问 
    私有静态字段
    class C:
    
        __name = "私有静态字段"
    
        def func(self):
            print C.__name
    
    class D(C):
    
        def show(self):
            print C.__name
    
    
    C.__name       # 不可在外部访问
    
    obj = C()
    obj.__name  # 不可在外部访问
    obj.func()     # 类内部可以访问   
    
    obj_son = D()
    obj_son.show() #不可在派生类中可以访问 
    公有普通字段
    class C:
        
        def __init__(self):
            self.__foo = "私有字段"
    
        def func(self):
            print self.foo  # 类内部访问
    
    class D(C):
        
        def show(self):
            print self.foo # 派生类中访问
    
    obj = C()
    
    obj.__foo     # 通过对象访问    ==> 错误
    obj.func()  # 类内部访问        ==> 正确
    
    obj_son = D();
    obj_son.show()  # 派生类中访问  ==> 错误
    私有普通字段
    class C:
    
        def __init__(self):
            pass
        
        def add(self):
            print('in C')
    
    class D(C):
    
        def show(self):
            print('in D')
            
        def func(self):
            self.show()
    obj = D()
    obj.show()  # 通过对象访问   
    obj.func()  # 类内部访问    
    obj.add()  # 派生类中访问  
    公有方法
    class C:
    
        def __init__(self):
            pass
    
        def __add(self):
            print('in C')
    
    class D(C):
    
        def __show(self):
            print('in D')
    
        def func(self):
            self.__show()
    obj = D()
    obj.__show()  # 通过不能对象访问
    obj.func()  # 类内部可以访问
    obj.__add()  # 派生类中不能访问
    私有方法

    1.3面向对象的成员

    1 字段

    class Province:
    
        # 静态字段
        country = '中国'
    
        def __init__(self, name):
    
            # 普通字段
            self.name = name
    
    
    # 直接访问普通字段
    obj = Province('河北省')
    print obj.name
    
    # 直接访问静态字段
    Province.country
    View Code

    上面的代码可以看出:普通字段需要通过对象来访问  , 静态字段需要通过类访问

    内存中存储方式:

    静态字段在内存中子保存一份,实例化对象后,访问静态字段都指向类中的这个内存地址

    普通字段在每个对象中都要保存一份

    2方法

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

    • 普通方法:由对象调用;至少一个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参数 """
               return cls('xingchen') 
    
        @staticmethod
        def static_func(): #设置不依赖于类和函数,不需要它们传self或者cls
            """ 定义静态方法 ,无默认参数"""
    
            print '静态方法'
        @staticmethod
        def static_func2(n): #可以设置为传递一个参数
            print('n')
        
    
    
    # 调用普通方法
    f = Foo()
    f.ord_func()
    
    # 调用类方法
    Foo.class_func()
    Foo.name #可以打印出xingchen
    
    # 调用静态方法
    Foo.static_func()     
    
    f.static_func2(1)   
    Foo.static_func2(2)   
    View Code

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

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

    3属性

    什么是property

    它是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
        @property
        def bmi(self):
            return self.weight / (self.height**2)
    
    p1=People('egon',75,1.85)
    print(p1.bmi)  #本来应该时p1.bmi()
    View Code

    为什么要用property

    将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

    由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

    class Goods(object):
    
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        @property
        def price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
    
        @price.setter
        def price(self, value):
            self.original_price = value
    
        @price.deltter
        def price(self, value):
            del self.original_price
    
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    del obj.price     # 删除商品原价
    View Code

     二面向对象的内置函数

    1 isinstance和issubclass

    isinstance() 与 type() 区别:
      type() 不会认为子类是一种父类类型,不考虑继承关系。
      isinstance() 会认为子类是一种父类类型,考虑继承关系。

    #isinstance(obj,cls)检查是否obj是否是类 cls 的对象
    class A:pass
    class B(A):pass
    
    abj=B()
    print(isinstance(abj,B)) #True
    print(isinstance(abj,A)) #True
    
    #issubclass(sub, super)检查sub类是否是 super 类的派生类
    print(issubclass(B,A)) #True
    View Code

    2 反射

    反射:是通过字符串的形式去操作对象相关的属性

     I对实例化对象的反射

    class Foo:
        f='类的静态变量'
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def say_hi(self):
            print('my name is: ',self.name)
    
    obj=Foo('xincheng',18)
    print(obj.name) #xincheng
    print(hasattr(obj,'name')) #True 检查是否含有name的属性
    #获取
    my_name=getattr(obj,'name') #获取某个对象的属性
    print(my_name) #xincheng
    func=getattr(obj,'say_hi') #获取某个对象的属性
    func() #my name is:  xincheng
    #报错设置
    # print(getattr(obj,'aa')) #报错:AttributeError: 'Foo' object has no attribute 'aa'
    print(getattr(obj,'aa','没有此属性')) #可以设置自己需要的报错说明 没有此属性
    #增加或修改
    setattr(obj,'sb','hehe')
    print(obj.__dict__) #{'name': 'xincheng', 'age': 73, 'sb': 'hehe'}
    print(obj.sb) #hehe
    setattr(obj,'show_name',lambda self:self.name+'sb') #此属性相当于设置了一个函数
    print(obj.__dict__) #{'name': 'xincheng', 'age': 73, 'sb': 'hehe', 'show_name': <function <lambda> at 0x0000027089CA6048>}
    print(obj.show_name(obj)) #xinchengsb
    #删除
    delattr(obj,'age')
    delattr(obj,'show_name')
    delattr(obj,'show') #没有此属性报错,不能设置报错说明
    View Code

    II对类的反射

    class Foo(object):
        staticField = "old boy"
    
        def __init__(self):
            self.name = 'wupeiqi'
    
        def func(self):
            return 'func'
    
        @staticmethod
        def bar():
            return 'bar'
    
    
    print(getattr(Foo, 'staticField'))
    print(getattr(Foo, 'func'))
    print(getattr(Foo, 'bar'))
    #结果为:
    # old boy
    # <function Foo.func at 0x000002903EE65730>
    # <function Foo.bar at 0x000002903EE657B8>
    func=getattr(Foo,'bar')
    print(func) ## <function Foo.bar at 0x000002903EE657B8> 内存地址和类的bar方法一样
    View Code

    III对当前模块

    def login():
        print(888)
    
    msg=input('>>>>').strip()
    import sys
    print(sys.modules)
    this_module=sys.modules[__name__]
    print(this_module) #<module '__main__' from 'G:/day8/练习.py'>
    
    print(hasattr(this_module,'login')) #True
    if hasattr(this_module,msg):
        getattr(this_module,msg)()
    else:
        print('没有此属性')
    View Code

    IIII对另外一个模块

    #模块名称模块测试反射,内容如下
    def test():
        print('来自于另外一个模块')
    
    #本地操作:
    import 模块测试反射 as obj
    print(hasattr(obj,'test'))
    getattr(obj,'test')()
    View Code

     3 __len__

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __len__(self):
            return len(self.__dict__)
    a = A()
    print(a.__dict__) #{'a': 1, 'b': 2}
    print(len(a)) #2 使用len函数的时候它计算的是实例化对象字典的长度
    View Code

    4 __hash__

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __hash__(self):
            return hash(str(self.a)+str(self.b))
    a = A()
    print(hash(a)) #这个hash值刷新一次改变一次
    View Code

    5 __str__和__repr__

    如果一个类定义了__str__方法,那么在打印的时候,默认触发该方法

    format_dict={
        'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
        'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
        'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
    }
    class School:
        def __init__(self,name,addr,type):
            self.name=name
            self.addr=addr
            self.type=type
    
        def __repr__(self):
            return 'School(%s,%s)' %(self.name,self.addr)
        def __str__(self):
            return '(%s,%s)' %(self.name,self.addr)
    
        def __format__(self, format_spec):
            if not format_spec or format_spec not in format_dict:
                format_spec='nat'
            fmt=format_dict[format_spec]
            return fmt.format(obj=self)
    
    s1=School('oldboy1','北京','私立')
    print('from repr: ',repr(s1))  #from repr:  School(oldboy1,北京)
    print('from str: ',str(s1))  #from str:  (oldboy1,北京)
    print(s1) #(oldboy1,北京) 默认触发str方法
    
    '''
    str函数或者print函数--->obj.__str__()
    repr或者交互式解释器--->obj.__repr__()
    如果__str__没有被定义,那么就会使用__repr__来代替输出
    注意:这俩方法的返回值必须是字符串,否则抛出异常
    '''
    
    print(format(s1,'nat'))
    print(format(s1,'tna'))
    print(format(s1,'tan'))
    print(format(s1,'asfdasdffd'))
    #结果为:
    # oldboy1-北京-私立
    # 私立:oldboy1:北京
    # 私立/北京/oldboy1
    # oldboy1-北京-私立
    View Code

    打印类型的触发

    class B:
    
        def __str__(self):
            return 'str : class B'
    
        def __repr__(self):
            return 'repr : class B'
    
    
    b = B()
    print('%s' % b)  #str : class B
    print('%r' % b)  #repr : class B
    View Code

    6 __call__

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

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

    class Foo:
    
        def __init__(self):
            pass
        
        def __call__(self, *args, **kwargs):
    
            print('__call__')
    
    
    obj = Foo() # 执行 __init__
    obj()       # 执行 __call__ #打印出 __call__
    View Code

     7 __del__

    析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    class Foo:
        def __del__(self):
            print('del----->')
    
    obj=Foo()
    print('hehe!')
    '''
    结果为:
    hehe!
    del----->
    这种情况是等待这个py的脚本完成执行的时候,触发del命令
    '''
    #如果换一种情况呢
    class Moo:
        def __del__(self):
            print('del----->')
    
    oby=Moo()
    del oby #提前触发 del命令
    print('hehe!')
    '''
    结果为:
    del----->
    hehe!
    
    '''
    View Code

     8 __new__

    此方法在实例化的时候触发,它的调用在__init__之前发生,object默认就有此方法

    先讲一个模式:单例模式   --》就是一个类只能有一个实例

    应用场景

    1.当一个类,多次实例化时,每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次

    2.当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日志文件)的控制,对计数器的同步控制等,这种情况下由于只有一个实例,所以不用担心同步问题

    情况一:一般的情况

    class A:
        def __init__(self):
            self.x = 1
            print('in init function')
        def __new__(cls, *args, **kwargs):
            print('in new function')
            return object.__new__(A, *args, **kwargs)
    
    a = A()
    '''
    in new function  #触发__new__,在__init__之前
    in init function
    '''
    print(a.x) # 1
    
    b=A() # 结果和a一样
    View Code

    情况二:单例模式

    class B:
        __instance = None
    
        def __new__(cls, *args, **kwargs):
            if cls.__instance is None:
                obj = object.__new__(cls)
                cls.__instance = obj
            return cls.__instance
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def func(self):
            print(self.name)
    
    
    a = B('alex', 80)  # 实例化,传值
    print(a.name)
    b = B('egon', 20)  # 实例化,覆盖值
    print(a)
    print(b)
    print(a.name)
    print(b.name)
    '''
    alex
    <__main__.B object at 0x0000023A1D0B8BA8>
    <__main__.B object at 0x0000023A1D0B8BA8>
    egon
    egon
    它们内存地址一样,这是个单例模式的例子
    b实例化的时候,传的值覆盖了a
    '''
    单例模式

     9 __eq__

    使用==的时候触发

    10 item系列

    class Foo:
        def __init__(self,name):
            self.name=name
    
        def __getitem__(self, item):
            print('getitem----->')
            return self.__dict__[item]
    
        def __setitem__(self, key, value):
            print('setitem----->')
            self.__dict__[key]=value
        def __delitem__(self, key):
            print('del obj[key]时,我执行')
            self.__dict__.pop(key)
        def __delattr__(self, item):
            print('del obj.key时,我执行')
            self.__dict__.pop(item)
    
    f1=Foo('sb')
    print(f1['name']) #触发 getitem方法
    f1['age']=18 #触发setitem方法
    f1['age1']=19 #触发setitem方法
    del f1.age1   #触发 delattr方法
    del f1['age'] #触发 delitem方法
    f1['name']='alex' #触发setitem方法
    # print(f1.__dict__)
    
    '''
    执行结果为:
    getitem----->
    sb
    setitem----->
    setitem----->
    del obj.key时,我执行
    del obj[key]时,我执行
    setitem----->
    {'name': 'alex'}
    '''
    View Code

     11 最后来看一个实例,关于hash和eq

    class Person:
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def __hash__(self):
            return hash(self.name+self.sex)
    
        def __eq__(self, other):
            if self.name == other.name and self.sex == other.sex:return True
    
    
    p_lst = []
    for i in range(10):
        p_lst.append(Person('egon',i,'male'))
    
    print(p_lst)
    yy=set(p_lst)
    print(yy)
    '''
    结果为:
    [<__main__.Person object at 0x00000152982D8DD8>, <__main__.Person object at 0x00000152982D8E10>, <__main__.Person object at 0x00000152982D8EB8>, <__main__.Person object at 0x00000152982E1EB8>, <__main__.Person object at 0x00000152982E1E80>,
     <__main__.Person object at 0x00000152984770F0>, <__main__.Person object at 0x00000152984774E0>, <__main__.Person object at 0x0000015298477518>,<__main__.Person object at 0x0000015298477550>, <__main__.Person object at 0x0000015298477588>]
    {<__main__.Person object at 0x00000152982D8DD8>}
    
    
    '''
    通过debug模式调试看到过程:针对set(p_lst)
    1 集合是个去重的过程,判断一个元素是否是重复的看的是hash值
    2 调用hash值就触发了__hash__,找到元素的hash值
        首先<__main__.Person object at 0x00000152982D8DD8>开始放入集合中,接着<__main__.Person object at 0x00000152982D8E10>也触发__hash__放入集合中
    3 两个元素的比较接着触发了 __eq__ ,而eq设置的判断标准,它们几乎一样,返回true ,也就是这两个元素的hash判断标准而言,它们是相等的,这样的话,元素<__main__.Person object at 0x00000152982D8E10>被去除了
    4 以此类推,接着下一个元素
    5 最后只会剩下唯一的第一个元素
    View Code
  • 相关阅读:
    jquery 选择器
    LeetCode_217. Contains Duplicate
    LeetCode_206. Reverse Linked List
    LeetCode_205. Isomorphic Strings
    LeetCode_204. Count Primes
    LeetCode_203. Remove Linked List Elements
    LeetCode_202. Happy Number
    LeetCode_198. House Robber
    LeetCode_191. Number of 1 Bits
    LeetCode_190. Reverse Bits
  • 原文地址:https://www.cnblogs.com/mmyy-blog/p/9237306.html
Copyright © 2011-2022 走看看