Python菜鸟起飞day9_类

目录

一、概述

二、面向对象编程的三大特性

2.1、封装

2.1.1、self形参

2.1.2、成员字段和私有成员字段(示例在2.1.5)

2.1.3、成员方法(实例方法)和私有成员方法(示例在2.1.5)

2.1.4、类方法和静态方法(示例在2.1.5)

2.1.5、属性

2.2、继承

2.2.1、被继承的多个父类没有共同的父类

2.2.2、被继承的多个父类有共同的父类

2.3、多态

三、类的创建

3.1、类中的特殊成员方法

3.1.1、__doc__、__module__、__class__、__add__

3.1.2、__init__、__del__

3.1.3、__dict__、__str__

3.1.4、__getitem__、__setitem__、__delitem__

3.1.5、__getslice__、__setslice__、__delslice__

3.1.6、__call__

3.2、类的创建过程

3.2.1、类本身也是对象

3.2.2、__metaclass__ 

3.2.3、过程

四、反射

4.1、反射中的四个方法

4.2、示例一:基本用法

4.3、示例二:动态加载和执行模块或方法

五、单例模式(Singleton Pattern)



一、概述

  • 面向过程:根据业务逻辑从上到下写垒代码
  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”

二、面向对象编程的三大特性

面向对象的三大特性是指:封装、继承和多态。

2.1、封装

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

2.1.1、self形参

除了一些特殊的方法之外,在类中定义的方法第一个形式参数必须是self,这个self类似于java中的this关键字,代表了当前的对象,即已经实例化的对象。只不过,java中隐式地传入了这个参数,而python需要显式地定义这个参数。实例化对象时和调用类中方法时,传入的实参则不需要传当前对象,也就是说,使用时忽略self。

2.1.2、成员字段和私有成员字段(示例在2.1.5)

1、通常情况下,定义类的时候,会在构造方法中通过self参数来添加成员字段。这样做的话,这个类的每个实例化对象都会有这些字段,如果直接通过实例化的对象来添加字段的话,则只是对当前实例有效。一般情况下不会再其他的方法中添加字段。

2、私有成员字段,一般定义在类中,字段名以“__”开头,只属于这个类,外界需要访问的时候,则需要调用类提供的方法来访问。这类字段不可被继承。

2.1.3、成员方法(实例方法)和私有成员方法(示例在2.1.5)

1、定义一个成员方法和在外部定义函数一样都是使用def关键字,不同点就在于,除了一些特殊方法,类中的方法第一个参数都要是self。

2、私有成员方法,跟普通方法定义方式相同,不同点就是方法名以“__”开头,该类方法不可被继承。

2.1.4、类方法和静态方法(示例在2.1.5)

1、这两种方法形参不需要写self,可直接通过类名调用,因此,这两种方法看起来似乎和某个具体的示例没有关系,也因此不需要传入当前实例,也就是不需要self参数。当然,通过实例也可以调用这两种方法。

2、类方法:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)。

3、静态方法:使用装饰器@staticmethod。参数随意,但是方法体中不能使用类或实例的任何属性和方法;

2.1.5、属性

1、访问属性时可以制造出和访问字段完全相同的假象,属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。属性内部进行一系列的逻辑计算,最终将计算结果返回。

2、定义时,①使用@property装饰器,并且只有self一个参数;②使用静态字段

3、调用时和访问成员字段方式相同,实例.属性名(方法名不加括号)

示例如下:

class Girl:
    __age = None  #私有成员字段
    def __init__(self,name,age = 18):
        self.name = name #self.name中的name是成员字段
        self.__age = age
    
    @classmethod#类方法
    def clsmethod(cls):#当前类对象
        print('class method')
    
    @staticmethod#静态方法
    def stamethod():
        print('static method')
    
    @property#通过装饰器来创建属性
    def Age(self):#通过方法访问私有成员字段
        return '姑娘芳龄:%d'%self.__age

    def getAge(self):
        return self.__age
    GETAGE = property(getAge)
    
    @property
    def Name(self):
        return self.name
    
    @Name.setter
    def Name(self,name):
        self.name = name
    
    @Name.deleter
    def Name(self):
        print('Name.delete')
    
    def getName(self):
        return self.name
    
    def setName(self,name):
        self.name = name
    
    def delName(self):
        print('delname')
    
    NAME = property(getName,setName,delName,'description....')

Girl.clsmethod()
Girl.stamethod()

g = Girl('诸葛大力')
print(g.Age)
print(g.GETAGE)
print(g.Name)#调用@property
g.Name='小力'#@Name.setter
del g.Name#@Name.deleter

g.NAME = '大力'#setName(self,name)
print(g.NAME)#def getName(self):
del g.NAME#def delName(self):

'''
输出结果:
class method
static method
姑娘芳龄:18
18
诸葛大力
Name.delete
大力
delname
'''

2.2、继承

顾名思义,子类(派生类)继承父类(基类)的属性、成员字段和成员方法等。python支持多继承,因此会有方法冲突的问题,解决这个问题的机制简而言之,在方法没有被重写的情况下,无论何时何地都是从最左边的父类开始。不只是对成员方法是这样,对于构造方法等都是这样。分为两种情况。

记住一点,这里面所有的self都是指的子类的实例

2.2.1、被继承的多个父类没有共同的父类

意思就是被继承的多个父类,他们分别都没有继承共同的父类。在这种情况下,依据从左到右的搜索原则,首先从最左边的父类开始搜索欲调用的方法。示例如下:

class a:
    def __init__(self):
        pass
    def abc(self):
        pass

class b:
    def __init__(self):
        pass
    
    def abc(self):
        pass
    
    def test(self):
        abc(self)

class c(a,b):
    def t(self):
        test()

ins = c()
ins.t()

'''
这里只描述这种情况:
如例所示,实例c调用了test方法,在test方法没有被重写的情况下,去父类中找这个方法,首先是要去a类中找这个方法,但是a中没有这个方法,
然后再去b中找,找到了这个方法,test方法又调用了abc方法,显然,a、b中都包含这个方法,这个时候,回到最初的起点,在abc没有被重写的
情况下,去最左边的a类中找这个abc方法,a中存在此方法,故调用了a中的abc方法。

这里面所有的self都指的是ins这个实例,我觉得应该是这个原因,才使得这种搜索原则应运而生吧。
'''

2.2.2、被继承的多个父类有共同的父类

示例如下:

class p:
    def abc(self):
        pass    

class a(p):
    def __init__(self):
        pass


class b(p):
    def __init__(self):
        pass
    
    def test(self):
        abc(self)

class c(a,b):
    def t(self):
        test()

ins = c()
ins.t()

'''
这里只说明这种情况:
如上代码所示,c调用了abc方法,依据从左到右的原则,在方法没有被重写的情况下,在父类中寻找test方法,从a-->b,在b中找到被执行,
再找abc方法,在abc方法没有被重写的情况下,在父类中寻找,先从a中开始找,a中不存在这个方法,这个时候不会搜索a与b共同的父类,也
就是说,如果a继承了另一个类,这个类继承了p,那么这个类也会被搜索,但是不会搜索p;然后再搜索b中的方法,依然没有找到,最后搜索
a,b共同的父类,也就是类p。

这里面所有的self也是指的ins这个实例。
'''

2.3、多态

python是一种弱类型语言,原生就是多态的,有利有弊。


三、类的创建

3.1、类中的特殊成员方法

示例参见:https://www.cnblogs.com/wupeiqi/p/4766801.html

3.1.1、__doc__、__module__、__class__、__add__

__doc__表示类的描述信息

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

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

__add__运算符重载+

3.1.2、__init__、__del__

__init__构造方法

__del__析构方法

3.1.3、__dict__、__str__

__dict__ 字典类型,类或对象中的所有成员

__str__ print实例化的对象的时候,默认调用

3.1.4、__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

3.1.5、__getslice__、__setslice__、__delslice__

用于切片操作

3.1.6、__call__

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

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

3.2、类的创建过程

3.2.1、类本身也是对象

class Foo:#默认调用type类的构造方法来创建类
    pass

obj = Foo()

print type(obj) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建

'''
通过type类创建Foo类
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员
'''
Foo = type('Foo',(object,), {'func': func})

所以,obj对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

3.2.2、__metaclass__ 

类中有一个属性 __metaclass__,其用来表示该类由谁来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看类创建的过程。示例如3.2.3

3.2.3、过程

class MyType(type):
    def __init__(self,what,bases=None,dic=None):
        super(MyType,self).__init__(what,bases,dic)#执行type的构造方法
        print(self,'this is mytype init')
   
    def __call__(self, *args, **kwargs):
        print(self,"this is Mytype call")
        return type.__call__(self, *args, **kwargs)

 
class Foo(object,metaclass=MyType):#指定使用MyType来创建类
    def __new__(self, *args, **kwargs):
        print(self,'this is Foo new')
        return object.__new__(self, *args, **kwargs)
    
    def __init__(self):
        print(self,'this is Foo init')

    def func(self):
        print('hello foo')
f = Foo()

①通过class Foo()来调用MyType类的构造函数,从而实例化MyType类,而这个实例就是Foo

②f = Foo(),从而会调用MyType中的__call__()方法,上面这个实例中调用type类中的__call__(),在type类中,有一条语句是:self.__new__(self,*args,**kwargs),从而调用了Foo类中的__new__()方法,执行完__new__()之后最后调用Foo中的构造方法,最终创建了Foo的实例f.

大致过程如下盗的一张图:


四、反射

参考文章:https://www.cnblogs.com/rexcheny/p/9498091.html

反射是将字符串映射到示例的变量或者示例的方法。通俗点将就是可以用字符串来使用实例和实例中方法的技术。想象场景:在浏览器的地址栏中输入对应的网址,对应的网站也就会有反应,并给你返回对应的网页。我们输入到浏览器地址栏的url是一个字符串,这个字符串的url到web服务器上后是怎么找到对应的代码函数并执行后给我们返回内容的。

4.1、反射中的四个方法

  • getattr 获取指定字符串名称的对象属性
  • setattr 为对象设置一个对象
  • hasattr 判断对象是否有对应的对象(字符串)
  • delattr 删除指定属性

这里的属性指的是类中的字段和方法,但是不能获取私有字段和方法。

4.2、示例一:基本用法

class Foo:
    stat = 'on'
    def __init__(self,name,age):
        self.name = name
        self.age = age
     
    def show(self):
        return '%s-%s'%(self.name,self.age)

 
obj = Foo('alex',18)

'''以下三种方式都可以取到name这个成员字段的值'''
b = eval('obj.name')
print(b)

name = obj.__dict__['name']
print(name)

'''使用字符串获取变量'''
print(getattr(obj, 'name'))

'''获取并执行成员方法show'''
func = getattr(obj, 'show')
print(func)
print(func())

'''对成员的其他操作'''
print(hasattr(obj, 'name'))#变量是否存在
setattr(obj, 'key', 'value')#设置变量
print(getattr(obj, 'key'))
delattr(obj, 'key')#删除变量

'''对引入的模块内容操作'''
import day13.new5_test as new5
print(getattr(new5, 'name'))
func = getattr(new5, 'func')
print(func)
func()
clas = getattr(new5, 'cla')
print(clas)
print(clas().show())

4.3、示例二:动态加载和执行模块或方法

temp = "re"
model = __import__(temp)

if __name__ == '__main__':
    txt = "hj123uo"
    pattern = model.compile(r"\d+")#匹配连续的数字
    print(model.search(pattern, txt).group())
'''
输出结果:
123
'''



temp = "re"  # 要引入的模块
func = "compile"  # 要使用的方法
model = __import__(temp)  # 导入模块
function = getattr(model, func)  # 找到模块中的属性

if __name__ == '__main__':
    txt = "hj123uo"
    pattern = function(r"\d+")  # 这里执行funcation()就等于执行re.compile()函数
    print(model.search(pattern, txt).group())
'''
输出结果:
123
'''

五、单例模式(Singleton Pattern)

该模式的主要目的是确保某一个类只有一个实例存在。也就是说在整个系统中,如果你希望某个类只能出现一个实例。

参考文章:https://www.cnblogs.com/huchong/p/8244279.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值