• Python学习之==>面向对象编程(二)


    一、类的特殊成员

    我们在Python学习之==>面向对象编程(一)中已经介绍过了构造方法和析构方法,构造方法是在实例化时自动执行的方法,而析构方法是在实例被销毁的时候被执行,Python类成员中还存在着一些具有特殊意义的方法,下面我们来一一介绍一下:

    1、__doc__

    表示类的描述信息

    1 class Foo:
    2     '''
    3     描述类信息
    4     '''
    5     def func(self):
    6         pass
    7 
    8 print(Foo.__doc__)  # 描述类信息
    View Code

    2、__module__ 和  __class__ 

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

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

    1 class C:
    2     def __init__(self):
    3         self.name = 'Jack'
    /lib/practice.py
    1 from lib.practice import C
    2 
    3 obj = C()
    4 print(obj.__module__) # lib.practice,即模块
    5 print(obj.__class__)  # <class 'lib.practice.C'>,即类
    index.py

    3、__init__

    构造方法,类再实例化时自动执行的方法

    1 class Foo:
    2     def __init__(self):
    3         print('init')
    4 
    5 obj = Foo()  # init,自动执行类中的 __init__ 方法
    View Code

    4、__del__

    析构方法,实例被销毁时自动执行的方法,一般可用于自动关闭文件、关闭连接、关闭数据库、删除测试数据等操作

     1 import pymysql
     2 class MyDb(object):
     3     def __init__(self,host,user,db,passwd,
     4                  port=3306,charset='utf8'):  # 构造函数
     5         try:
     6             self.conn = pymysql.connect(
     7                 host=host,user=user,passwd=passwd,port=port,db=db,charset=charset,
     8                 autocommit=True  # 自动提交
     9             )
    10         except Exception as e:
    11             print('数据库连接失败!:%s'%e)
    12         else:
    13             self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
    14 
    15     def __del__(self):  # 析构函数,实例被销毁的时候执行
    16         self.cur.close()
    17         self.conn.close()
    18         print('数据库连接关闭')
    19 
    20     def ex_sql(self,sql):
    21         try:
    22             self.cur.execute(sql)
    23         except Exception as e:
    24             print('sql语句有问题:%s'%sql)
    25         else:
    26             self.res = self.cur.fetchall()
    27             return self.res
    28 
    29 my = MyDb('118.24.3.40','jxz','jxz','123456')
    30 my.ex_sql('select * from stu;')
    31 print(my.res)  # 可以用实例属性取值
    32 print(my.ex_sql('select * from stu;'))  # 也可以用实例方法的返回值
    33 print('我是最后一行代码')   # 执行完最后这行代码后再执行析构函数
    View Code

    5、__dict__

    将对象中封装的内容/成员通过字典的形式返回

     1 class Foo():
     2     '''
     3     这个类是干啥的。。
     4     '''
     5     def __init__(self, name, age):
     6         self.name = name
     7         self.age = age
     8 
     9 obj = Foo('alex',99)
    10 d = obj.__dict__   # 对象有__dict__方法,显示对象的所有成员
    11 print(d)  # {'name': 'alex', 'age': 99}
    12 ret = Foo.__dict__ # 类也有__dict__方法,显示类的所有成员
    13 print(ret)# {'__module__': '__main__', '__doc__': '
        这个类是干啥的。。
        ', '__init__': <function Foo.__init__ at 0x000001EBA9FAF1E0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>}
    View Code

    6、__int__

    如果一个类中定义了__int__方法,那么在打印对象时,默认输出该方法的返回值

     1 class Foo:
     2     def __init__(self):  # 构造方法
     3         print('init')
     4 
     5     def __int__(self):
     6         return 1
     7 
     8 
     9 obj = Foo()  # init,创建对象时自动执行构造方法
    10 r = int(obj) # int后面加上一个对象(obj),它就会自动执行对象(obj)当中的__int__方法,并将返回值赋给int对象(r是int的对象)
    11 print(r)     # 1
    12 print(type(r))# <class 'int'>,r是int类的对象
    View Code

    7、__str__

    如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值

     1 class Foo:
     2     def __init__(self):  # 构造方法
     3         print('init')
     4 
     5     def __str__(self):
     6         return 'niu'
     7 
     8 obj = Foo()  #init,创建对象时自动执行构造方法
     9 print(obj,type(obj))  # <__main__.Foo object at 0x00000236A19CD278> <class '__main__.Foo'>,obj的类型是Foo类
    10                       # niu <class '__main__.Foo'>,类中加上__str__()后的返回
    11 # print()函数在执行时会自动调用对象中的__str__()方法,所以Foo类中加上__str__()方法之前显示为内存地址,加上__str__()方法之后,显示为__str__()方法的返回值‘niu’
    12 # print(obj)相当于print(str(obj))
    13 s = str(obj)  # str后面加上一个对象(obj),它就会自动执行对象(obj)当中的__str__方法,并将返回值赋给str对象(s是str的对象)
    14 print(s)
    View Code

    8、__add__

    如果一个类中定义了__add__方法,那么在两个对象进行相加时,返回的是该方法的返回值

     1 class Foo:
     2     def __init__(self, name, age):
     3         self.name = name
     4         self.age = age
     5 
     6     def __add__(self, other):
     7         return self.age + other.age
     8 
     9 obj1 = Foo('alex', 19)
    10 obj2 = Foo('hiro', 55)
    11 r = obj1 + obj2  # 两个对象相加时,自动执行第一个对象的__add__方法,并且将第二个对象当参数传入
    12 print(r, type(r))# 74 <class 'int'>
    View Code

    9、__call__

    对象后面加括号,触发执行类中的__call__方法

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

     1 class Foo:
     2     def __init__(self):  # 构造方法
     3         print('init')
     4 
     5     def __call__(self, *args, **kwargs):
     6         print('call')
     7 
     8 
     9 obj = Foo()  #init,创建对象时自动执行构造方法
    10 obj()        #call,对象后面加括号直接调用类中的__call__()方法
    View Code

    10、__getitem__、__setitem__、__delitem__

    用于索引、切片操作,如:列表、字典。以上三个方法分别获取、设置、删除数据

     1 class Foo():
     2 
     3     def __init__(self, name, age):
     4         self.name = name
     5         self.age = age
     6 
     7     def __getitem__(self, item):
     8         print(item + 10)
     9 
    10     def __setitem__(self, key, value):
    11         print(key, value)
    12 
    13     def __delitem__(self, key):
    14         print(key)
    15 
    16 li = Foo('alex',99)
    17 # 索引
    18 li[8]          # 自动执行li对象的类中__getitem__方法,8当作参数传递给item
    19 li[100] = 123  # 自动执行li对象的类中__setitem__方法,100和123当作参数传递给key和value
    20 del li[99]     # 自动执行li对象的类中__delitem__方法,99当作参数传递给key
    View Code
     1 class Foo():
     2 
     3     def __init__(self, name, age):
     4         self.name = name
     5         self.age = age
     6 
     7     def __getitem__(self, item):
     8         # 如果item是基本类型,int,str索引获取
     9         # 如果item类型是slice,切片
    10         print(type(item))
    11         if type(item) == slice: # 切片是slice类型
    12             print('切片处理')
    13             print(item.start)
    14             print(item.stop)
    15             print(item.step)
    16         else:
    17             print('索引处理')
    18     def __setitem__(self, key, value):
    19         print(type(key))
    20         if type(key) == slice:
    21             print('切片处理')
    22             print(key.start)
    23             print(key.stop)
    24             print(key.step)
    25         else:
    26             print('索引处理')
    27 
    28     def __delitem__(self, key):
    29         print(type(key))
    30         if type(key) == slice:
    31             print('切片处理')
    32             print(key.start)
    33             print(key.stop)
    34             print(key.step)
    35         else:
    36             print('索引处理')
    37 
    38 li = Foo('alex',99)
    39 # 切片
    40 li[1:3:2]  # <class 'slice'>,切片处理,1 3 2
    41 li[1:3:2] = [11,22] # <class 'slice'>,切片处理,1 3 2
    42 del li[2:4:2] # <class 'slice'>,切片处理,2 4 2
    View Code

    11、__iter__

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

     1 class Foo():
     2 
     3     def __init__(self, name, age):
     4         self.name = name
     5         self.age = age
     6 
     7     def __iter__(self):
     8         return 'alex'
     9 
    10 li = Foo('alex',18)
    11 # 如果类中有__iter__方法,创建的类就是可迭代对象
    12 # 对象.__iter__()方法的返回值是一个迭代器
    13 for i in li.__iter__():
    14     # 1、执行li对象的类Foo类中的__iter__方法,并获取到其返回值alex,是一个可迭代对象
    15     # 2、通过li.__iter__()将返回值转换为迭代器
    16     # 3、然后进行循环
    17     print(i)  # a l e x
    18 # for循环遇到迭代器,直接执行next()
    19 # for循环遇到可迭代对象,先执行对象.__iter__()方法,再执行next()
    View Code

    12、metaclass和__new__

    我们先来看一段代码:

    1 class Foo:
    2     def __init__(self):
    3         pass
    4 
    5 obj = Foo()
    6 print(type(obj))  #<class '__main__.Foo'>,表示obj对象由Foo类创建
    7 print(type(Foo))  #<class 'type'>,表示Foo类对象由type类创建
    View Code

    在Python中有一句话叫做:一切事物皆为对象。通过类实例化的对象是对象,而类本身也是一个对象。

    通过上面这段代码以及执行结果来看,obj是通过Foo类创建的一个对象,而Foo类同样也是一个对象,它是通过type类创建的一个类对象。obj对象是通过执行Foo类的构造方法创建,那么Foo类对象是通过执行type类的构造方法创建。

    那么,类的创建就有以下两种方式:

    (1)普通方式

    1 class Foo():
    2     def func(self):
    3         print(123)
    4 
    5 obj = Foo()  # 实例化
    6 obj.func()   # 调用对象中的方法
    View Code

    (2)特殊方式(type类的构造方法)

    1 def function():
    2     print('Hello,world!!')
    3 
    4 Foo = type('Foo',(object,), {'func':function})
    5 # type第一个参数:类名
    6 # type第二个参数:当前类的父类,这个类继承哪个类
    7 # type第三个参数:类的成员
    8 Foo.func()  # 调用类对象中的方法
    View Code

    那么,我们好奇的是既然类对象是由type类实例化产生的,那么type类内部是如何实现创建类的?类又是如何创建对象的呢?

    创建类时,通过指定metaclass=派生类,用来表示该类由谁来实例化创建。所以,我们可以为metaclass设置一个type类的派生类,从而查看类创建的过程,如下:

    1. 由MyType类来创建Foo类对象,执行MyType类中的__init__方法
    2. 执行obj = Foo(),首先执行MyType类中的__call__方法
    3. MyType类中的__call__方法又会调用Foo类中的__new__方法创建对象obj
    4. 创建对象后再调用Foo类中的__init__方法(将obj对象当参数传入)
     1 # type类内部实现创建类的,类创建对象
     2 class MyType(type):
     3     def __init__(self,*args,**kwargs):
     4         print(123)
     5     def __call__(self, *args, **kwargs):
     6         print(456)
     7         obj = self.__new__(self,*args,**kwargs) # 调用Foo类中的__new__方法
     8         self.__init__(obj)
     9 
    10 class Foo(object,metaclass=MyType): # 执行父类MyType类中的__init__方法
    11     def __init__(self):
    12         print(111)
    13     def __new__(cls, *args, **kwargs): # 创建obj对象
    14         print(789)
    15         return object.__new__(cls,*args,**kwargs)
    16 
    17 # 第一阶段:解释器从上到下执行代码创建Foo类
    18 # 第二阶段:通过Foo类创建object对象
    19 obj = Foo()  # 执行MyType类中的__call__方法
    View Code

    二、反射

    反射,主要指程序可以访问、检测和修改它本身状态或行为的一种能力。Python中面向对象中的反射则是指:通过字符串的形式操作对象中的成员。因Python中一切事物皆为对象,所以都可以使用反射。

    1、hasattr:判断对象中是否有这个成员

     1 class Foo:
     2     height = 180
     3     def __init__(self,name,age):
     4         self.name = name
     5         self.age = age
     6     def show(self):
     7         return '%s-%s'%(self.name,self.age)
     8 
     9 obj = Foo('niu',99)
    10 print(hasattr(obj,'name')) # True,obj对象中有name这个成员
    11 print(hasattr(obj,'age'))  # True,obj对象中有age这个成员
    12 print(hasattr(obj,'show')) # True,obj对象中有show这个成员
    13 print(hasattr(obj,'long')) # False,obj对象中没有long这个成员
    hasattr

    2、getattr:去对象中获取某个成员

     1 class Foo:
     2     height = 180
     3     def __init__(self,name,age):
     4         self.name = name
     5         self.age = age
     6     def show(self):
     7         return '%s-%s'%(self.name,self.age)
     8 
     9 obj = Foo('niu',99)
    10 inp = input('>>>')   # 通过输入成员名来获取属性,这样更灵活
    11 r = getattr(obj,inp) # 这里r可以是name,age,height,show等
    getattr

    直接操作一个类,类也是一个对象:

     1 class Foo:
     2     height = 180
     3     def __init__(self,name,age):
     4         self.name = name
     5         self.age = age
     6     def show(self):
     7         return '%s-%s'%(self.name,self.age)
     8 
     9 # 直接操作类,因为类也是一个对象
    10 print(getattr(Foo,'height'))  # 180
    getattr

    操作文件,文件也是一个对象:

     1 NAME = 'niu'
     2 
     3 def func():
     4     return 'func'
     5 
     6 class Foo:
     7     height = 180
     8 
     9     def __init__(self,name,age):
    10         self.name = name
    11         self.age = age
    12 
    13     def show(self):
    14         return '%s-%s'%(self.name,self.age)
    practice.py
    1 # 操作文件对象
    2 import practice
    3 r1 = getattr(practice,'NAME') # practice.py文件中的NAME常量
    4 print(r1)  # niu
    5 r2 = getattr(practice,'func') # practice.py文件中的func函数
    6 print(r2())# func
    7 cls = getattr(practice,'Foo') # practice.py文件中的Foo类
    8 obj = cls('niuren',99)  # 实例化
    9 print(obj) # <practice.Foo object at 0x0000022C19E9DA58>
    getattr

    3、setattr:给对象中设置一个成员

     1 class Foo:
     2     height = 180
     3 
     4     def __init__(self,name,age):
     5         self.name = name
     6         self.age = age
     7 
     8     def show(self):
     9         return '%s-%s'%(self.name,self.age)
    10 
    11 obj = Foo('niu',99)
    12 setattr(obj,'sex','') # 给obj对象设置一个sex成员,值为‘男’
    13 print(obj.sex)  #
    setattr

    4、delattr:删除对象中的成员

     1 class Foo:
     2     height = 180
     3 
     4     def __init__(self,name,age):
     5         self.name = name
     6         self.age = age
     7 
     8     def show(self):
     9         return '%s-%s'%(self.name,self.age)
    10 
    11 obj = Foo('niu',99)
    12 delattr(obj,'name')  # 删除obj对象中的name成员
    13 print(obj.name)      # 'Foo' object has no attribute 'name',Foo类中没有name成员了
    delattr

    5、反射的应用

    1 def f1():
    2     return '首页'
    3 
    4 def f2():
    5     return '新闻'
    6 
    7 def f3():
    8     return '精华'
    practice.py
    1 import practice
    2 inp = input('请输入要查看的URL:')
    3 if hasattr(practice,inp):  # 输入URL来判断practice文件是否存在相应的成员
    4     func = getattr(practice,inp)  # 如果有则获取这个成员
    5     result = func()
    6     print(result)
    7 else:
    8     print('404')           # 如果不存在则返回404页面
    View Code

    三、单例模式

    单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

    比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

     1 class Foo:
     2 
     3     __v = None
     4 
     5     @classmethod
     6     def get_instance(cls):
     7         if cls.__v:
     8             return cls.__v
     9         else:
    10             cls.__v = Foo()
    11             return cls.__v
    12 
    13 # 实例化时不需要再使用类名+括号,直接调用类方法get_instance
    14 obj1 = Foo.get_instance()
    15 print(obj1)  # <__main__.Foo object at 0x000001B0C8C0D278>
    16 obj2 = Foo.get_instance()
    17 print(obj2)  # <__main__.Foo object at 0x000001B0C8C0D278>
    18 # 创建多个对象都是同一个内存地址,说明使用的是同一个对象
    View Code
  • 相关阅读:
    JAVA面向对象概述
    练习
    字符串
    图形代码
    assets转到内外部存储
    file存储
    sp存储
    Intent练习
    存储登录
    存储
  • 原文地址:https://www.cnblogs.com/L-Test/p/10252954.html
Copyright © 2020-2023  润新知