类的基本使用

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def info(self):
        print(f'大家好,我是{self.name},我今年{self.age}岁了')


xiaohua = Person('小花',21)
xiaohua.info()

打印结果:

大家好,我是小花,我今年21岁了

python里面的类,架子大概就是这个样子,__init__就是构造函数,所有的方法的第一个形参都是self,这个不是关键字,命名为self是行业默认写法,你把self改成abc也行,重点是第一个形参,进来的都是当前实例对象,对标其他编程语言的this。

属性的存取

正常存取

python里面没有私有属性这个东西,默认全部都是public

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def info(self):
        print(f'大家好,我是{self.name},我今年{self.age}岁了')


xiaohua = Person('小花',21)
print(f'年龄是:{xiaohua.age}')
xiaohua.age = 22
print(f'改变后的年龄是:{xiaohua.age}')

打印结果:

年龄是:21
改变后的年龄是:22

存取器

python的存取器实际上是用了小花招,它允许你定义属性或者方法的名字前面加上两个下划线,它会对这种格式的名称进行转换,转换后名称也就变了,外部就访问不到该属性,所以就有了私有属性的效果。

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}岁了')


xiaohua = Person('小花',21)
xiaohua.info()
print(f'年龄是:{xiaohua.__age}')

xiaohua.info()这一行是可以正常打印出信息,但是下面一行就会报错,报错原因是没有__age这个属性。

我们鉴于这种玩法,就可以做出存取器方法

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}岁了')

    def get_age(self):
        return self.__age

    def set_age(self,age):
        self.__age = age

xiaohua = Person('小花',21)
xiaohua.info()
xiaohua.set_age(23)
xiaohua.info()

打印结果:

大家好,我是小花,我今年21岁了
大家好,我是小花,我今年23岁了

但是事实上,私有属性只能成为一种程序员之间的约定,它是拦不住人的,因为python把带两个下划线打头的属性转换后的结果是有规则的,它会转换成一个下划线+类名+原属性名。

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}岁了')

    def get_age(self):
        return self.__age

    def set_age(self,age):
        self.__age = age


xiaohua = Person('小花',21)
xiaohua.info()
xiaohua._Person__age = 22
xiaohua.info()

打印结果:

大家好,我是小花,我今年21岁了
大家好,我是小花,我今年22岁了

特性

在新版的python3中,提供了property函数,可以关联到存取方法,实际上它是一个类,只不过我们用起来是函数的用法。

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}岁了')

    def get_age(self):
        print(f'这是类里面-我正在读取age的值:{self.__age}')
        return self.__age

    def set_age(self,age):
        print(f'这是类里面-我正在设置age的值:{age}')
        self.__age = age

    def del_age(self):
        print(f'这是类里面-我正在删除age:{self.__age}')
        del self.__age

    age = property(get_age,set_age,del_age)

xiaohua = Person('小花',21)
xiaohua.info()
xiaohua.age = 18
xiaohua.info()
print(f'我在外面读取age的值:{xiaohua.age}')
del xiaohua.age

打印结果:

大家好,我是小花,我今年21岁了
这是类里面-我正在设置age的值:18
大家好,我是小花,我今年18岁了
这是类里面-我正在读取age的值:18
我在外面读取age的值:18
这是类里面-我正在删除age:18

示例中property传入了三个参数,顺序分别是读取方法,设置方法,删除方法,如果都不传,那么该特性将不可读也不可写,传了哪个方法就拥有哪个功能,有第四个可选参数,传入一个文档字符串。

property也可以当成装饰器用

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}岁了')

    @property
    def age(self):
        print(f'这是类里面-我正在读取age的值:{self.__age}')
        return self.__age

    @age.setter
    def age(self,age):
        print(f'这是类里面-我正在设置age的值:{age}')
        self.__age = age

xiaohua = Person('小花',21)
xiaohua.info()
xiaohua.age = 18
xiaohua.info()
print(f'我在外面读取age的值:{xiaohua.age}')

打印结果:

大家好,我是小花,我今年21岁了
这是类里面-我正在设置age的值:18
大家好,我是小花,我今年18岁了
这是类里面-我正在读取age的值:18
我在外面读取age的值:18

继承

常规继承

继承的写法是在类定义的时候类名后面的括号里传入父类名称

class Person():
    def info(self):
        print('人类正在统治世界')

class student(Person):
    def __init__(self):
        print('我是一名小学生')

p = student()
p.info()

打印结果:

我是一名小学生
人类正在统治世界

访问父类方法

在python中访问父类方法用一个特殊的函数 : super()

class Person():
    def info(self):
        print('人类正在统治世界')

class student(Person):
    def __init__(self):
        super().info()
        print('我是一名小学生')

p = student()

打印结果:

人类正在统治世界
我是一名小学生

如果是初始化类的时候要调用父类的构造函数,也是一样的调用方式:

class Person():
    def __init__(self,name):
        self.__name = name

    def info(self):
        print(f'人类正在统治世界:{self.__name}')

class student(Person):
    def __init__(self,name):
        super().__init__(name)

p = student('阿西吧')
p.info()

打印结果:

人类正在统治世界:阿西吧

方法重写

子类将父类的方法进行重写覆盖

class Person():
    def info(self):
        print('人类正在统治世界')

class student(Person):
    def info(self):
        print('小学生正在统治世界')

p = student()
p.info()

打印结果:

小学生正在统治世界

多重继承

多重继承虽然很强大,也很容易成为车祸现场,多个父类中如果有构造函数如果有同名方法都将搞得你头晕脑胀,正常情况下,应该避免使用多重继承,除非忍不住。。。

class Person():
    def info(self):
        print('人类正在统治世界')

class Young():
    def young_info(self):
        print('年轻人太天真')

class student(Person,Young):
    def __init__(self):
        print('小学生正在统治世界')

p = student()
p.info()
p.young_info()

打印结果:

小学生正在统治世界
人类正在统治世界
年轻人太天真

类型校验

class Person():
    def info(self):
        print('人类正在统治世界')

class Young():
    def young_info(self):
        print('年轻人太天真')

class student(Person,Young):
    def __init__(self):
        print('小学生正在统治世界')


a = issubclass(student,Person)
print(f'是不是子类:{a}')

x = student.__bases__
print(f'父类是:{x}')

s = student()
z = isinstance(s,student)
print(f'是不是实例:{z}')

打印结果:

是不是子类:True
父类是:(<class '__main__.Person'>, <class '__main__.Young'>)
小学生正在统治世界
是不是实例:True

是不是实例判断  如果和父类进行判断也算是实例。

抽象接口

面向接口编程的时候都是先定义接口,然后子类去实现接口实现方法,在python3中引入了abc模块,可以帮助我们定义抽象接口

import abc

class Person(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def eat(self):
        pass


class student(Person):

    def eat(self):
        print('小学生也可以吃饭')


x = student()
x.eat()

打印结果:

小学生也可以吃饭

抽象类中定义的接口在子类中必须实现

静态方法

class student():

    remark = '我是祖国的花朵'

    @classmethod
    def sing(cls):
        print('小学生也可以唱歌 ' + cls.remark)

    @staticmethod
    def eat():
        print('小学生也可以吃饭')

student.eat()
student.sing()

打印结果:

小学生也可以吃饭
小学生也可以唱歌 我是祖国的花朵

两种装饰器可以定义静态方法,注意区别,@classmethod装饰的方法有默认参数cls,表示当前类,可以取到属性。

07-13 17:18