博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
day7--面向对象进阶(内含反射和item系列)
阅读量:5240 次
发布时间:2019-06-14

本文共 12529 字,大约阅读时间需要 41 分钟。

一面向对象的结构和成员

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.nameclass D(C):    def show(self):        print C.nameC.name         # 类访问obj = C()obj.func()     # 类内部可以访问obj_son = D()obj_son.show() # 派生类中可以访问
公有静态字段
class C:    __name = "私有静态字段"    def func(self):        print C.__nameclass D(C):    def show(self):        print C.__nameC.__name       # 不可在外部访问obj = C()obj.__name  # 不可在外部访问obj.func()     # 类内部可以访问   obj_son = D()obj_son.show() #不可在派生类中可以访问
私有静态字段
class C:    __name = "私有静态字段"    def func(self):        print C.__nameclass D(C):    def show(self):        print C.__nameC.__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_priceobj = 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:passclass B(A):passabj=B()print(isinstance(abj,B)) #Trueprint(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) #xinchengprint(hasattr(obj,'name')) #True 检查是否含有name的属性#获取my_name=getattr(obj,'name') #获取某个对象的属性print(my_name) #xinchengfunc=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) #hehesetattr(obj,'show_name',lambda self:self.name+'sb') #此属性相当于设置了一个函数print(obj.__dict__) #{'name': 'xincheng', 'age': 73, 'sb': 'hehe', 'show_name': 
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# 
#
func=getattr(Foo,'bar')print(func) ##
内存地址和类的bar方法一样
View Code

III对当前模块

def login():    print(888)msg=input('>>>>').strip()import sysprint(sys.modules)this_module=sys.modules[__name__]print(this_module) #
print(hasattr(this_module,'login')) #Trueif hasattr(this_module,msg): getattr(this_module,msg)()else: print('没有此属性')
View Code

IIII对另外一个模块

#模块名称模块测试反射,内容如下def test():    print('来自于另外一个模块')#本地操作:import 模块测试反射 as objprint(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 Bprint('%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) # 1b=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>egonegon它们内存地址一样,这是个单例模式的例子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----->sbsetitem----->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 Truep_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

 

posted on
2018-06-28 10:10 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/mmyy-blog/p/9237306.html

你可能感兴趣的文章
宏脚本链接数据库
查看>>
HDU1004
查看>>
MySQL高速缓存
查看>>
DropdownList绑定的两种方法
查看>>
价值观
查看>>
数值计算中,浮点类型给我们挖的坑
查看>>
(String)、toString、String.valueOf
查看>>
mongodb命令----批量更改文档字段名
查看>>
python多线程下载网页图片并保存至特定目录
查看>>
《人工智能的未来》--------------经典语录
查看>>
了解循环队列的实现
查看>>
CentOS 简单命令
查看>>
Linux中修改docker镜像源及安装docker
查看>>
数位dp(模板+例题)
查看>>
Android 自动安装脚本
查看>>
[编程之美]电梯调度算法
查看>>
常用的jQuery九宫格布局图片展示特效代码
查看>>
scrollView的bounds
查看>>
【洛谷】[FJOI2018]领导集团问题
查看>>
《springcloud 三》分布式配置中心
查看>>