Python3快速入门—6.类(未完结)

6.类

6.1类和对象

6.1.1类的定义

计算机语言中有2个重要概念:数据、算法。在Python3中,数据可以使用数字、序列、集合、字典来表示;算法可以用函数/方法来实现。为了将数据和算法统一管理,于是引申出了类。

Python3中,类中的数据称为变量(注:也有人称为属性),包括类变量和实例变量;类中算法的实现称为方法,包括类方法、实例方法、静态方法和专有方法。

类定义格式如下:

class Classname(object):

pass

其中,使用关键字class来定义一个类,Classname表示类的名称,object表示该类的父类/基类。

在Python3中,变量都是小写,单词之间使用_来连接;常量都是大写;类名是首字母大写,单词之间使用首字母大写来区分。这些都是程序员默认的书写规则。

若该类无父类,则括号()和object可以不写,即格式修改如下:

class Classname:

pass

class Classname(): #建议采用此格式

pass

#程序6-1

class Person():

    name = ''

    age = 0

    def print_info(self):

        print('this is a test')

        

p1 = Person()

p1.print_info()

运行结果:

this is a test

6.1.2创建对象

类是一个抽象性的概念。类的定义就是将所有对象的共性提取出来,如Person类中的姓名和年龄是所有人都会有的。

对象是一个具体的实体。创建对象可以理解为类实例化的过程,将Person类实例化出一个具体的人,如姓名’zhangsan’、年龄18。

#程序6-2

class Person():

    #this is a test

    name = ''

    age = 0

    def __init__(self,name = 'none',age = 0):

        self.name = name

        self.age = age

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

 

p1 = Person()

p1.print_info()

 

p2 = Person('zhangsan',18)

p2.print_info()

运行结果:

name :none

age :0

name :zhangsan

age :18

在Python3中,使用”object = Classname(parameters)”的形式来创建对象。在其他编程语言中如C++,会使用”Classname object(parameters)”这样的形式来创建对象,但是这在Python3中是完全不行的。

原因:在Python3中,变量、对象是没有数据类型的,因此必须使用赋值运算符(=)的形式来给变量、对象赋值;而使用Classname object(parameters)的形式来创建对象,则对象的数据类型会被限制为Classname。

6.2变量和方法

在Python3中,对象或类使用点运算符(.)来访问类中的变量和方法。

6.2.1实例方法

在类中定义的实例方法,其第一个参数都必须是self;必须使用对象才可以调用。

#程序6-3

class Person():

    #this is a test

    name = ''

    age = 0

    def __init__(self,name = 'none',age = 0):

        self.name = name

        self.age = age

    def print_info(self,profession):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

        print('profession :'+ profession)

 

p1 = Person()

p1.print_info('baby')

 

p2 = Person('zhangsan',18)

p2.print_info('student')

运行结果:

name :none

age :0

profession :baby

name :zhangsan

age :18

profession :student

程序6-3中的方法print_info(self,profession)就是实例方法,其必须是实例化的对象才可以调用。注:类无法调用,如执行Person.print_info('student')就会出错。

实例方法中的self到底是什么?

#程序6-4

class Person():

    #this is a test

    name = ''

    age = 0

    def __init__(self,name = 'none',age = 0):

        self.name = name

        self.age = age

    def print_info(self,profession):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

        print('profession :'+ profession)

        print(self)

 

p1 = Person()

p1.print_info('baby')

 

p2 = Person('zhangsan',18)

p2.print_info('student')

运行结果:

name :none

age :0

profession :baby

<__main__.Person object at 0x00E90910>

name :zhangsan

age :18

profession :student

<__main__.Person object at 0x00E90930>

在实例方法中,self指的就是对象本身。当执行p1.print_info('baby')时,self就是p1;执行p2.print_info('student')时,self就是p2。

在类的方法定义中,self可以换成其它名称,只要符合变量的定义即可;但是Python3默认规定是使用self或this。

6.2.2专有方法-构造函数和析构函数

类的专有方法是在特殊情况下或使用特殊语法时,由Python主动调用;其形式一般是__xxx__。

构造函数和析构函数是类的专有方法。当创建对象时,会默认调用构造函数;当删除对象时,会默认调用析构函数。构造函数的格式:def __init__(self, parameter...);析构函数的格式:def __del__(self)。

#程序6-5

class Person():

    #this is a test

    name = ''

    age = 0

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name

        self.age = age

    def __del__(self):

        print('__del__')

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

 

p1 = Person() #调用构造函数

p1.print_info()

 

p2 = Person('zhangsan',18) #调用构造函数

p2.print_info()

运行结果:

__init__

name :none

age :0

__init__

name :zhangsan

age :18

__del__

__del__

构造函数可以使用对象直接调用;不可以使用类来调用。

#程序6-6

class Person():

    #this is a test

    name = ''

    age = 0

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name

        self.age = age

    def __del__(self):

        print('__del__')

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

 

p1 = Person()

p1.__init__('lisi',16)

p1.print_info()

 

p2 = Person('zhangsan',18)

p2.print_info()

运行结果:

__init__

__init__

name :lisi

age :16

__init__

name :zhangsan

age :18

__del__

__del__

在程序6-6中,由于使用了p1.__init__('lisi',16),因此多调用了一次构造函数。

析构函数也可以用对象来调用;或使用del关键字。

#程序6-7

class Person():

    #this is a test

    name = ''

    age = 0

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name

        self.age = age

    def __del__(self):

        print('__del__')

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

 

p1 = Person()

p1.print_info()

 

p2 = Person('zhangsan',18)

p2.print_info()

 

p3 = Person('lisi',16)

p3.print_info()

 

print(p1.__dict__)

p1.__del__()

print(p1.__dict__)

 

print(p2.__dict__)

del p2

print(p2.__dict__)

 

print(p3.__dict__)

运行结果:

__init__

name :none

age :0

__init__

name :zhangsan

age :18

__init__

name :lisi

age :16

{'name': 'none', 'age': 0}

__del__

{'name': 'none', 'age': 0}

{'name': 'zhangsan', 'age': 18}

__del__

Traceback (most recent call last):

  File ".\run.py", line 32, in <module>

    print(p2.__dict__)

NameError: name 'p2' is not defined

__del__

__del__

当执行p1.__del__()会调用类Person的析构函数,但是析构函数并没有对p1对象做任何处理,因此在第二次使用__dict__时依旧不变。这也是在程序执行完后,打印了4次__del__的原因,因为p1对象并没有被删除。

当执行del p2时也调用了类Person的析构函数,但是del删除了p2对象,因此使用__dict__时会报出变量不存在的错误。注:__dict__是一个字典,其存放着对象的变量,key表示变量名,value表示变量值。

总结:

(1)对象删除一定调用析构函数;调用析构函数并不一定删除对象。

(2)在构造函数和析构函数中,self指的也是对象。

(3)我们应该遵循”构造函数和析构函数的调用次数相等”,因此不要使用对象来调用构造函数和析构函数。在创建对象时,会有Python主动调用构造函数;当程序执行完或使用del关键字时,会有Python主动调用析构函数。

(4)构造函数和析构函数是无返回值的。

6.2.3类变量和实例变量

类变量:属于类的变量,可以使用类名调用;不属于对象的变量,无法使用对象来调用。

实例变量:属于对象的变量,可以使用对象来调用;不属于类的变量,无法使用类名调用。

#程序6-8

class Person():

    #this is a test

    count = 0   #类变量

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name    #实例变量

        self.age = age      #实例变量

    def __del__(self):

        print('__del__')

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

 

p1 = Person('zhangsan',18)

 

print(Person.__dict__)

print(p1.__dict__)

运行结果:

__init__

{'__module__': '__main__', 'count': 0, '__init__': <function Person.__init__ at 0x03A096F0>, '__del__': <function Person.__del__ at 0x03A09618>, 'print_info': <function Person.print_info at 0x03A097C8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'zhangsan', 'age': 18}

__del__

在类Person的变量打印中,出现count,因此count是类变量;在对象p1的变量打印中,出现name和age,因此name和age是实例变量。

#程序6-9

class Person():

    #this is a test

    count = 0   #类变量

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name    #实例变量

        self.age = age      #实例变量

    def __del__(self):

        print('__del__')

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

 

p1 = Person('zhangsan',18)

p1.abc = 'object variable'

Person.xyz = 'class variable'

 

print(Person.__dict__)

print(p1.__dict__)

运行结果:

__init__

{'__module__': '__main__', 'count': 0, '__init__': <function Person.__init__ at 0x01580A08>, '__del__': <function Person.__del__ at 0x016696F0>, 'print_info': <function Person.print_info at 0x016696A8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'xyz': 'class variable'}

{'name': 'zhangsan', 'age': 18, 'abc': 'object variable'}

__del__

我们发现使用点运算符(.)不仅可以访问类中定义的变量和方法,还可以构造变量。当使用点运算符访问变量时,若此变量已定义则直接访问;若未定义则构造变量。若访问者是类名,则构造类变量;若是对象,则构造实例变量。

总结:类的定义中,在方法外定义的变量以及使用类名和点运算符构造的变量是类变量;使用对象和点运算符构造的变量是实例变量。

实例变量的调用:类的方法中,使用self来调用;类外,使用对象来调用。

类变量的调用:使用类名来调用,即class_name.variable;使用__class__来调用,即object.__class__.variable。

#程序6-10

class Person():

    #this is a test

    count = 0   #类变量

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name    #实例变量

        self.age = age      #实例变量

        Person.count += 1

        # self.__class__.count += 1

    def __del__(self):

        print('__del__')

Person.count -= 1

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))

        print('count :'+ str(self.__class__.count))

 

p1 = Person()

p1.print_info()

 

p2 = Person('zhangsan',18)

p2.print_info()

 

p3 = Person('lisi',12)

p3.print_info()

运行结果:

__init__

name :none

age :0

count :1

__init__

name :zhangsan

age :18

count :2

__init__

name :lisi

age :12

count :3

__del__

__del__

__del__

代码中,count用来表示对象创建的个数。当调用构造函数时,count加1;调用析构函数时,count减1。

6.2.4类方法

前面学习了类变量和实例变量,类变量由类来调用,实例变量由对象来调用。那么在方法中,是否有一种方法专门由类来调用?这就是本节要讲的类方法。

类方法格式:

@classmethod

def funcname(cls, parameter_list):

pass

其中,classmethod是装饰器,表示这个方法是类方法;cls表示类名,也可以换成其它名称,但是在Pyhton3种默认规定使用cls。

类方法一般由类来调用,其类名作为第一个参数传入类方法的cls参数中。

#程序6-11

class Person():

    #this is a test

    count = 0   #类变量

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name    #实例变量

        self.age = age      #实例变量

        Person.count += 1

        # self.__class__.count += 1

    def __del__(self):

        print('__del__')

        Person.count -= 1

    def print_info(self):

        print('name :'+ self.name)

        print('age :'+ str(self.age))  

    @classmethod

    def get_count(cls): #类方法

        print('count :'+ str(cls.count))

 

p1 = Person()

p1.print_info()

 

p2 = Person('zhangsan',18)

p2.print_info()

p2.get_count()

 

p3 = Person('lisi',12)

p3.print_info()

 

Person.get_count()

 

del p2

Person.get_count()

运行结果:

__init__

name :none

age :0

__init__

name :zhangsan

age :18

count :2

__init__

name :lisi

age :12

count :3

__del__

count :2

__del__

__del__

类方法和实例方法不同,它可以由类名或对象来调用;而实例方法只能由对象调用。在正常的使用中,类方法还是用类名来访问比较好;一般对类变量的操作都会放在类方法中。

6.2.5静态方法

在类的定义中,还有一种方法称为静态方法。静态方法中一般用来存放逻辑性的代码,它与类、对象之间没有任何交互。

静态方法格式:

@staticmethod

def funcname(parameter_list):

pass

其中,staticmethod是装饰器,表示这个方法是静态方法;parameter_list是参数列表,不需要传入self或cls。

#程序6-12

class Person():

    #this is a test

    count = 0   #类变量

    def __init__(self,name = 'none',age = 0):

        print('__init__')

        self.name = name    #实例变量

        self.age = age      #实例变量

        Person.count += 1

    def __del__(self):

        print('__del__')

        Person.count -= 1

    def print_info(self):

        print('name:'+ self.name,', age:'+ str(self.age),end = ' , ')

        Person.chinese_zodiac(self.age)

    @classmethod

    def get_count(cls):     #类方法

        print('count :'+ str(cls.count))

    @staticmethod

    def chinese_zodiac(age): #生肖

        a = age%12

        if a==0:

            print('生肖:猪')

        elif a==1:

            print('生肖:狗')

        elif a==2:

            print('生肖:鸡')

        elif a==3:

            print('生肖:猴')

        elif a==4:

            print('生肖:羊')

        elif a==5:

            print('生肖:马')

        elif a==6:

            print('生肖:蛇')

        elif a==7:

            print('生肖:龙')

        elif a==8:

            print('生肖:兔')

        elif a==9:

            print('生肖:虎')

        elif a==10:

            print('生肖:牛')

        elif a==11:

            print('生肖:鼠')

 

 

 

p1 = Person()

p1.print_info()

 

p2 = Person('zhangsan',18)

p2.print_info()

 

p3 = Person('lisi',12)

p3.print_info()

 

p4 = Person('lzb',28)

p4.print_info()

运行结果:

__init__

name:none , age:0 , 生肖:猪

__init__

name:zhangsan , age:18 , 生肖:马

__init__

name:lisi , age:12 , 生肖:猪

__init__

name:lzb , age:28 , 生肖:羊

__del__

__del__

__del__

__del__

代码中,使用静态方法chinese_zodiac来计算生肖,以2019年基本年份,以年龄为参数。

静态方法可以用类名和对象来调用。在正常使用中,一般会由类名来调用;不使用对象调用。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值