python 面向对象编程


1
<br><br><br><br>
 

 
好了,明白 了类的基本定义,接下来我们一起分解一下上面的代码分别 是什么意思 
1
2
3
4
5
6
7
class  Role( object ):  #定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法,必须这样写,以后再讲为什么
     def  __init__( self ,name,role,weapon,life_value = 100 ,money = 15000 ):  #初始化函数,在生成一个角色时要初始化的一些属性就填写在这里
         self .name  =  name  #__init__中的第一个参数self,和这里的self都 是什么意思? 看下面解释
         self .role  =  role
         self .weapon  =  weapon
         self .life_value  =  life_value
         self .money  =  money

上面的这个__init__()叫做初始化方法(或构造方法), 在类被调用时,这个方法(虽然它是函数形式,但在类中就不叫函数了,叫方法)会自动执行,进行一些初始化的动作,所以我们这里写的__init__(self,name,role,weapon,life_value=100,money=15000)就是要在创建一个角色时给它设置这些属性,那么这第一个参数self是干毛用的呢? 
 
初始化一个角色,就需要调用这个类一次: 
1
2
r1  =  Role( 'Alex' , 'police' ,'AK47’)  #生成一个角色 , 会自动把参数传给Role下面的__init__(...)方法
r2  =  Role( 'Jack' , 'terrorist' ,'B22’)   #生成一个角色

我们看到,上面的创建角色时,我们并没有给__init__传值,程序也没未报错,是因为,类在调用它自己的__init__(…)时自己帮你给self参数赋值了, 

1
2
r1  =  Role( 'Alex' , 'police' , 'AK47’) #此时self 相当于 r1 ,  Role(r1,' Alex ',' police ',' AK47’)
r2  =  Role( 'Jack' , 'terrorist' , 'B22’)#此时self 相当于 r2, Role(r2,' Jack ',' terrorist ',' B22’)

为什么这样子?你拉着我说你有些犹豫,怎么会这样子?
你执行 r1 = Role('Alex' ,'police' ,'AK47 )时,python的解释器其实干了两件事:
  1. 在内存中开辟一块空间指向r1这个变量名
  2. 调用Role这个类并执行其中的__init__(…)方法,相当于Role.__init__(r1,'Alex','police',’AK47’),这么做是为什么呢? 是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,重要的事情说3次, 因为关联起来后,你就可以直接r1.name, r1.weapon 这样来调用啦。所以,为实现这种关联,在调用__init__方法时,就必须把r1这个变量也传进去,否则__init__不知道要把那3个参数跟谁关联呀。
  3. 明白了么哥?所以这个__init__(…)方法里的,self.name = name , self.role = role 等等的意思就是要把这几个值 存到r1的内存空间里。
如果还不明白的话,哥,去测试一下智商吧, 应该不会超过70,哈哈。
为了暴露自己的智商,此时你假装懂了,但又问, __init__(…)我懂了,但后面的那几个函数,噢 不对,后面那几个方法 为什么也还需要self参数么? 不是在初始化角色的时候 ,就已经把角色的属性跟r1绑定好了么? 
good question, 先来看一下上面类中的一个buy_gun的方法: 
1
2
def  buy_gun( self ,gun_name):
     print (“ % s has just bought  % s”  % ( self .name,gun_name) )

上面这个方法通过类调用的话要写成如下: 
 
1
2
r1  =  Role( 'Alex' , 'police' , 'AK47' )
r1.buy_gun( "B21”) #python 会自动帮你转成 Role.buy_gun(r1,”B21" )

执行结果
#Alex has just bought B21 
依然没给self传值 ,但Python还是会自动的帮你把r1 赋值给self这个参数, 为什么呢? 因为,你在buy_gun(..)方法中可能要访问r1的一些其它属性呀, 比如这里就访问 了r1的名字,怎么访问呢?你得告诉这个方法呀,于是就把r1传给了这个self参数,然后在buy_gun里调用 self.name 就相当于调用r1.name 啦,如果还想知道r1的生命值 有多少,直接写成self.life_value就可以了。 说白了就是在调用类中的一个方法时,你得告诉人家你是谁。
 
好啦, 总结一下2点:
  1. 上面的这个r1 = Role('Alex','police','AK47)动作,叫做类的“实例化”, 就是把一个虚拟的抽象的类,通过这个动作,变成了一个具体的对象了, 这个对象就叫做实例
  2. 刚才定义的这个类体现了面向对象的第一个基本特性,封装,其实就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容

静态方法

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
class  Dog( object ):
 
     def  __init__( self ,name):
         self .name  =  name
 
     @staticmethod  #把eat方法变为静态方法
     def  eat( self ):
         print ( "%s is eating"  %  self .name)
 
 
 
=  Dog( "ChenRonghua" )
d.eat()

上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。

1
2
3
4
Traceback (most recent call last):
   File  "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/静态方法.py" , line  17 in  <module>
     d.eat()
TypeError: eat() missing  1  required positional argument:  'self'

想让上面的代码可以正常工作有两种办法

1. 调用时主动传递实例本身给eat方法,即d.eat(d) 

2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了

复制代码
 1 class Dog(object):
 2 
 3     def __init__(self,name):
 4         self.name = name
 5 
 6     @staticmethod
 7     def eat():
 8         print(" is eating")
 9 
10 
11 
12 d = Dog("ChenRonghua")
13 d.eat()
复制代码

 

类方法  

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

1
2
3
4
5
6
7
8
9
10
11
12
class  Dog( object ):
     def  __init__( self ,name):
         self .name  =  name
 
     @classmethod
     def  eat( self ):
         print ( "%s is eating"  %  self .name)
 
 
 
=  Dog( "ChenRonghua" )
d.eat()

执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的

1
2
3
4
5
6
Traceback (most recent call last):
   File  "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py" , line  16 in  <module>
     d.eat()
   File  "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py" , line  11 in  eat
     print ( "%s is eating"  %  self .name)
AttributeError:  type  object  'Dog'  has no attribute  'name'

此时可以定义一个类变量,也叫name,看下执行效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class  Dog( object ):
     name  =  "我是类变量"
     def  __init__( self ,name):
         self .name  =  name
 
     @classmethod
     def  eat( self ):
         print ( "%s is eating"  %  self .name)
 
 
 
=  Dog( "ChenRonghua" )
d.eat()
 
 
#执行结果
 
我是类变量  is  eating

 

属性方法  

属性方法的作用就是通过@property把一个方法变成一个静态属性

1
2
3
4
5
6
7
8
9
10
11
12
class  Dog( object ):
 
     def  __init__( self ,name):
         self .name  =  name
 
     @property
     def  eat( self ):
         print ( " %s is eating"  % self .name)
 
 
=  Dog( "ChenRonghua" )
d.eat()

调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了

1
2
3
4
5
Traceback (most recent call last):
  ChenRonghua  is  eating
   File  "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py" , line  16 in  <module>
     d.eat()
TypeError:  'NoneType'  object  is  not  callable

正常调用如下

1
2
3
4
5
=  Dog( "ChenRonghua" )
d.eat
 
输出
  ChenRonghua  is  eating

好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

1. 连接航空公司API查询

2. 对查询结果进行解析 

3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?

复制代码
class Flight(object):
    def __init__(self,name):
        self.flight_name = name


    def checking_status(self):
        print("checking flight %s status " % self.flight_name)
        return  1

    @property
    def flight_status(self):
        status = self.checking_status()
        if status == 0 :
            print("flight got canceled...")
        elif status == 1 :
            print("flight is arrived...")
        elif status == 2:
            print("flight has departured already...")
        else:
            print("cannot confirm the flight status...,please check later")


f = Flight("CA980")
f.flight_status
复制代码

cool , 那现在我只能查询航班状态, 既然这个flight_status已经是个属性了, 那我能否给它赋值呢?试试吧

1
2
3
=  Flight( "CA980" )
f.flight_status
f.flight_status  =   2

输出, 说不能更改这个属性,我擦。。。。,怎么办怎么办。。。 

1
2
3
4
5
6
checking flight CA980 status
flight  is  arrived...
Traceback (most recent call last):
   File  "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py" , line  58 in  <module>
     f.flight_status  =   2
AttributeError: can't  set  attribute

当然可以改, 不过需要通过@proerty.setter装饰器再装饰一下,此时 你需要写一个新方法, 对这个flight_status进行更改。

复制代码
class Flight(object):
    def __init__(self,name):
        self.flight_name = name


    def checking_status(self):
        print("checking flight %s status " % self.flight_name)
        return  1


    @property
    def flight_status(self):
        status = self.checking_status()
        if status == 0 :
            print("flight got canceled...")
        elif status == 1 :
            print("flight is arrived...")
        elif status == 2:
            print("flight has departured already...")
        else:
            print("cannot confirm the flight status...,please check later")
    
    @flight_status.setter #修改
    def flight_status(self,status):
        status_dic = {
            0 : "canceled",
            1 :"arrived",
            2 : "departured"
        }
        print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) )

    @flight_status.deleter  #删除
    def flight_status(self):
        print("status got removed...")

f = Flight("CA980")
f.flight_status
f.flight_status =  2 #触发@flight_status.setter 
del f.flight_status #触发@flight_status.deleter 
复制代码

注意以上代码里还写了一个@flight_status.deleter, 是允许可以将这个属性删除


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值