Python实战之class类的详解

  • Post author:
  • Post category:python


上一篇:Python实战之可迭代对象、迭代器、生成器、yield

点击跳转





目录篇:python相关目录篇

点击跳转


下一篇:Python实战之反射hasattr、getattr、setattr、delattr

点击跳转


目录




class 类:定义某类对象相同的功能属性



1.object对象:


除了调用类的功能属性,自身也拥有自身的特性



2.构造函数:


在实例化时做一些类的初始化的工作: def __init__(self)



3.析构函数:


在实例释放、销毁的时候执行,通常用于做一些收尾工作,关闭一些数据库连接,打开的临时文件(def __func__ (self):实例化对象被删除就会执行类的该方法)



4.类分量:


所有实例共用可以调取变量,节省开销



5.实例变量:


初始化实例x后,实例x自身的初始属性



属性:



实例变量(静态属性):


初始化实例x后,赋予实例x的属性



方法(动态属性):


也称之功能,所有实例都可以调用,类分量也可以列为方法



私有方法:


把方法变成私有方法格式def __xxx(self)( 类内部可以修改调用,但是外部调用不了)



私有属性:


把实例变量变成私有属,格式:self.__xxx = yyy(类内部可以修改调用,但是外部调用不了)



特征:(封装, 继承, 多态)



Encapsulation封装:


在类中对数据赋值,内部可以调用,外部是透明的,这使类变成了一个整体,里面包含着类的数据和方法(1私有属性  2.私有方法)



Inheritance继承:


一个类可以派生出子类,在这个父类定义的属性,方法自动被子类继承



父子类有相同的方法(功能):



1.有限调取子类的方法,但是子类可以调用父类相同的方法执行后 在执行自己的方法。

2.等级相同的子类:互相不可以调用对方的方法

3.单继承

4.多继承

注意: py2经典类是按深度优先来继承的,新式类是按广度优先继承的、py3全是按广度优先继承



polymorphism多态:


一个基类有不同的子类,每个子类实现的功能不一样,不同程序调用实现功能不一样

一个接口调用不同实例,接口重用,一种接口,多种实现



class类的继承


父子类有相同的方法(功能):有限调取子类的方法,但是子类可以调用父类相同的方法执行后 在执行自己的方法。

等级相同的子类:互相不可以调用对方的方法

py2经典类是按深度优先来继承的,新式类是按广度优先继承的

py3全是按广度优先继承


继承类和多继承类的基本原理


1.调用X类的a方法,如果X类没有a方法,会继续从该X类的父类继续找该方法,直到base类也没有为止


2.X类有a方法,X类的父类也有a方法,优先执行X类的a方法,结束


3.如果我们要指定执行X类的a方法,同时也要执行X类的父类的a方法(相同的方法),需要手动X类的a方法下使用super调用父类的a方法即可:

class X类(父类):

    def a(message) :

        super(X类名,self).bar(message) #执行父类的bar方法


4.多继承(广度优先(py3:同层级找遍以后再需深入一层),深度优先(py2:父类找)




1.执行的时候 obj没有f1该方法,那么根据py3 的广度规则优先从第一顺位的父类A开始找f1方法,然后A内部有f1方法执行完毕以后,就应该结束了。

2.但是可以继续其他继承的类拥有相同的f1方法执行,就需要用到了super进行指定继续

3.结果我们知道C类是base类(没有父类了),C类也进行了super执行指定执行了f1方法,结果执行B类的f1方法,说明super是按照深度优先顺序执行f1方法而非执行继承的父类的f1方法)

4.同理得到结果,如果super是广度优先执行的话,使用super执行指定的f1方法的话,那么super会按照广度优先顺序执行f1方法,而非父类的f1方法)


5.问题来了,本身是深度优先模式,我们非要在某个深度的类强制指定另外一个非本身继承的类执行其相同的方法,就需要如下操作

调用某个类把自身传递进去


得到结论:super是按照自身的顺序执行的,当然我们也可以进行自己指定顺序执行(指定类名.方法名(self))


从上面来看self到底是什么,其实self就是本身该对象  == obj=Foo()如下:

两种调用方法,需要注意:

1是实例化后成对象后,通过自身调用f1方法,self就是自身

2.是实例化以后成对象后,调用某类的某方法,就需要把自身对象作为self传递进去

两种都一样,一种是自动的,一种就是手动的

得出self==实例化的对象(调用方法的对象)


类自带装饰器


@staticmethod #静态方法


# 加了这个静态方法:把类的该方法跟类切断,变成一个单纯的函数

# 加了这个静态方法:把类的该方法跟类切断,变成一个单纯的函数

# 非要说有关系,就是需要通过类调用

# 该方法变成函数自然就不需要self,就算有也是实参


@classmethod #类方法


#装饰了该装饰器的方法self.xxx调用的是类变量xxx而不是self.xxx


@property #attribute属性方法


#装饰了该装饰器以后,调用就不能用()等于不能传参#


@方法.setter


#赋值方法(通常配合装饰attribute属性方法,添加起需要的self变量)

#装饰了该装饰器以后,传参方式从obj.xx(‘实参’) 修改成obj.xx = ‘实参’


@方法.deleter


#删除方法(通常配合装饰attribute属性方法,删除指定的self变量)

#装饰了该装饰器以后,外部调用方式 del obj.xx  执行了该obj.xx方法


类的参数


class Xx():def method…

#Xx=类名  method=类方法  obj=实例化的XX类对象


prin(obj.__doc__)  or prin(Xx.__doc__)

#打印类的描述信息 (注释的信息)


prin(obj.__module__)

#打印该对象实例化的Xx类的绝对路径:目录.文件名


prin(obj.__class__ )

#打印该对象实例化的Xx类的绝对路径+类名:<class ‘目录.文件名.类名’>


obj.__call__()

#调用方式:obj = Xx()  obj() == obj.__call__()  #调用了__call__方法


print(Xx.__dict__ )

#打印该类的所有方法和功能(不包括实例变量)以字典格式显示


print(obj.__dict__)

#打印该对象(实例)的变量,以字典格式显示


__init__

#构造方法(初始化方法),通过类创建对象时,自动触发执行


__del__

#析构方法,当对象在内存中被释放时,自动触发执行。(程序执行完毕会执行该方法)


__str__

#obj = Xx()  print(obj) ==执行了该Xx类的str方法 没有就返回obj对象内存地址



类的字典方式:


__getitem__

#实例以这种格式出现yy[‘k1’] :自动触发执行 __getitem__


__setitem__

#实例以这种格式出现:yy[‘k2’] = ‘alex’:自动触发执行 __setitem__


__delitem__

#实例以这种格式出现del yy[‘k1’]#自动触发执行__delitem__

class Foo(object):

    def __init__(self):

         self.data ={}

    def __setitem__(self, key, value):

        print('__setitem__', key, value)

        self.data[key] =value

    def __getitem__(self, key):

        print('__getitem__', key)

        return self.data.get(key)

    def __delitem__(self, key):

        print('__delitem__', key)

obj = Foo()

obj['name']= 'Burgess'

print(obj.data) #结果:{'name':'Burgess'}

print(obj['name']) #结果'Burgess'

del obj[''name'']  

print(obj['name']) #结果{}



通过字符串取值有两种:



字典 :

dict={'y':'xiaohong','x':'xiaoming'}  
gettest = dict['y']       #取值
         #gettest == xiaohong
dict['z'] = 'xiaoqiang'    #字典里面追加新的key和值
dict={'y':'xiaohong','x':'xiaoming','z':'xiaoqiang'}


对象:

class Bar(object):
   def __init__(self):
        pass

   def __contains__(self, item):
        pass

   def __setitem__(self,key,value):
        pass

   def __getitem__(self,key):
        pass

   def __delitem__(self.key):
        pass
 
        
obj = Bar()

obj[‘a’] = ‘xiaoxin’ 
#这种格式自动会触发执行Bar下面的def __setitem__方法 ,’a’ 和xiaoxin’作为实参

obj[‘c’]
#这种格式会自动触发执行Bar下面的def __getitem__方法,’c’作为实参

del obj[‘d’]
#这种格式会自动触发执行Bar下面的def __delitem__方法,’d’作为实参

v = ‘x’ in obj
#这种格式会自动触发执行Bar下面的def __ contains __方法,’d’作为实参



类的__contains__方法示例




类的两种创建方式




#普通方式

class Foo(object):

    def __init__(self, name):

         self.name = name



f = Foo("alex")

print(type(f))#查看该实例继承的类的名 结果显示:<class '__main__.Foo'>

print(type(Foo))#Foo是什么  结果显示:<class 'type'>



#特殊方式

def func(self):

    print('hello Burgess')

def __init__(self,name,age):

    self.name = name

    self.age = age



Foo = type("Foo",(),{'talk': func,'__init__':__init__})

#创建类  talk:方法 __init__:方法也是构造函数

#Foo本身是类 Foo也是对象,是type的对象, 我们称type是类的类

print(type(Foo))

f = Foo("Burgess",22)#实例化得到:实例f

f.talk()

#调取类Foo的方法talk

#{talk:func} talk的执行结果来自于调取了func的执行结果

print(f.name)


Type类

类是由type类实例化来的


类中有一个属性


__metaclass__


,其用来表示该类由





来实例化创建,所以,我们可以为


__metaclass__


设置一个


type


类的派生类,从而查看





创建的过程。

通过以上图:实例化Foo类的

obj


对象

得到顺序

#1.首先 MyType(type)会先执行自己的__new__(创建了__init__)

#2.执行自己的__init__ 在

#3.执行自己的__call__(创建了Foo 的__new__)

#4.执行Foo __new__(创造了Foo __init__)

#5. 执行Foo __init__


python3把MyType隐藏了(等于我们无需操作)



多态



多态性(polymorphisn


)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。


那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了


——


代码重用。而多态则是为了实现另一个目的


——


接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用





家谱





中任一类的实例的某一属性时的正确调用。


Pyhon


很多语法都是支持多态的,比如


len(),sorted(),


你给


len


传字符串就返回字符串的长度,传列表就返回列表长度。


多态:总之一句话就是一个接口调用不同实例


多态试验

__author__ = "Burgess Zheng"

class Animal:
    def __init__(self, name):  # Constructor of the class
        self.name = name

    def talk(self):  # Abstract method, defined by convention only
        pass #raise NotImplementedError("Subclass must implement abstract method")

    @staticmethod# 装饰器
    def animal_talk(obj):  #该函数实现1个接口调用不同实例
        obj.talk()

class Cat(Animal):
    def talk(self):
        print('Meow!')


class Dog(Animal):
    def talk(self):
        print('Woof! Woof!')
'''
d = Dog("xiaoming")
d.talk
c = Cat("zhangshan")
c.talk()
#以上比如我要调用d 和 c的时候 那么我必须要调用2个接口: d.talk 和c.talk
#现在是需要一个接口就可以调用不同实例,增加多一个函数
'''

'''
#一个接口就可以调用不同实例
def animal_talk(obj):  #如:接收到了c作为形参 obj=c
    obj.talk()         #c.talk()  
d = Dog("xiaoming")
c = Cat("zhangshan") 
animal_talk(c)
animal_talk(d)
#原理是一样的但是却实现了一个接口调用不同函数
但是需求又来了:把该函数放入父类进行实现
'''

#父类增加一个函数实现通过父类的一个接口调用不同函数
d = Dog("xiaoming")
c = Cat("zhangshan")
Animal.animal_talk(d)
Animal.animal_talk(c)
#这样就实现了1个接口调用不同函数,这也称之为多态



实例化类对象的两种方式




实例化类对象有两种方式:



1.通过类直接实例化成对象示例:


/test/he.py

Class Obj(object):

   def __init__(self,x ,y,z)


/test/settings

XXX= ‘模块对象路径’

YYY= ‘模块对象路径’

ZZZ= ‘模块对象路径


/test/set.py

from test import settings

clss crawler()

           def__init__(self)

                   self.settings = setting


===============================================================


#


通过类直接实例化


#1.


获取一个


crawler


对象


#2.


通过


crawler


对象调出


settings


配置文件对象


#3.


通过


settings


配置文件对象反射获取多个对象


#4.


多个对象作为形参进行实例化


/test/he.py


下的


Obj




/test/test01.py

from test import set

crawler = set.crawler()

settings = crawler.settings

x = load_object(settings[‘XXX’])

y = load_object(settings[‘YYY’])

z = load_object(settings[‘ZZZ’])

form test impor he 

obj = he.Obj(x= x,y=y,z=z) 


/test/test02.py

from test import set

crawler = set.crawler()

settings = crawler.settings

x = load_object(settings[‘XXX’])

y = load_object(settings[‘YYY’])

z = load_object(settings[‘ZZZ’])

form test impor he 

obj = he.Obj(x= x,y=y,z=z) 


2.通过类的方法实例化对象示例(推荐)


/test/he.py

Class Obj(object):

   def __init__(self,x ,y,z)

   def from_crawler(cls,crawler):
       settings = crawler.settings
       x = load_object(settings[‘XXX’])
       y = load_object(settings[‘YYY’])
       z = load_object(settings[‘ZZZ’])
       return cls(x =1,y=y,z=2)


/test/settings

XXX= ‘模块对象路径’

YYY= ‘模块对象路径’

ZZZ= ‘模块对象路径

/test/set.py

from test import settings

clss crawler()

     def__init__(self)

           self.settings = settings


===============================================================


#


通过类直接实例化


#1.


获取


crawler


对象


#2. crawler


对象作为形参进行实例化


/test/he.py


下的


Obj




/test/test01.py

from test import set

crawler = set.crawler()

form test impor he 

obj = he.Obj.from_crawler(crawler)


/test/test02.py

from test import set

crawler = set.crawler()

form test impor he 

obj = Obj.from_crawler(crawler)


通过以上得出结论:显而易见,通过类的方法进行实例化对象好

上一篇:Python实战之可迭代对象、迭代器、生成器、yield

点击跳转





目录篇:python相关目录篇

点击跳转


下一篇:Python实战之反射hasattr、getattr、setattr、delattr

点击跳转



版权声明:本文为Burgess_zheng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。