• 类和对象


    一. 类和对象的概念

    概念:

    面向对象的两个最重要的概念:类和对象

    :共性事物的抽象,是对某一类具有共性事物的描述,是概念上的定义

    对象:对象是共性事物的一个体现,是这类事物的每个个体,或者说是类的一个实例(instance)

    总结:

    类是对象的模板,对象是类的实例

    类结构:

    里面包含属性与函数

    数据是对象的状态-->成员变量(属性)

    方法是对象的行为-->函数(方法)

    二. 语法

    #创造类的语法
    class Math:
        a = 4                #属性
        b = 5
    
        def add(self):       #方法
            c = self.a + self.b
            return c

    注意:1) 类名一般首字母大写,比如 class User    #class是关键字

         2) 类里面包含属性和方法

       3) 类函数自带self关键字(指向类的实例)。不能少!

       4) 如果类函数里面要调用属性,方法: self.属性名, self.方法名

    实例:

    class Friend:
    
        height = None
        weight = None
        age = None
        money = None
    
        #定义功能——会做饭
        def canCook(self, can=True):
            if can == True:
                print("我会做饭。。。")
            else:
                print("我不会做饭。。。")
    
        def canGetMoney(self):
            print("我会挣钱。。。")
    
        def setAge(self, age):
            self.age = age
            print("年龄为:", self.age)
    
        def setHeight(self, height):
            self.height = height
            print("身高为:", self.height)
    
        def setWeight(self, weight):
            self.weight = weight
            print("体重为:", self.weight)
    
        def setMoney(self, money):
            self.money = money
            print("资产为:", self.money)
    
    #对象一:身高180,会做饭,做挣钱,有200万的资产,而且才29岁
    #实例化:类名()
    danqing = Friend()
    danqing.setAge(29)
    print(danqing.age)
    danqing.setMoney(2000000)
    print(danqing.money)
    danqing.canCook()
    
    print("===========================")
    #对象二:身高175,不会做饭,年龄只有25岁,资产5万
    dancf = Friend()
    #改变对象的属性
    dancf.setAge(25)
    print(dancf.age)
    dancf.setMoney(50000)
    print(dancf.money)
    dancf.setHeight(175)
    print(dancf.height)
    dancf.canCook(False)

    运行结果:

    年龄为: 29
    29
    资产为: 2000000
    2000000
    我会做饭。。。
    ===========================
    年龄为: 25
    25
    资产为: 50000
    50000
    身高为: 175
    175
    我不会做饭。。。

    三. 初始化函数的调用

    初始化函数:def __init__(self, 参数1, 参数2, 参数3)

    __init__函数,是两个下划线!经常会写错,写成单下划线,这样会报错!

    用法:

    def __init__(self, a, b):
        self.a = a 
        self.b = b
        self.c =  10

    注意:

    1) 初始化里面做的是初始化操作,可以带参数也可以不带参数

    2) 跟普通函数一样,可以带默认参数

    3) 初始化里面可以有赋值好了的属性值

    4) 每次创造一个实例,需要传递跟初始化函数参数个数一致的值

    5) 每个实例都会自动调用初始化函数

    6) 初始化参数的写法要注意,怎么把参数赋值给self.参数名,参数名字不一定要一致,但是赋值要正确

    实例1:

    class Friend:
    
        def __init__(self, age, sex, height):
            self.age = age
            self.sex = sex
            self.height = height
    
    
        #定义功能——会做饭
        def canCook(self, can=True):
            if can == True:
                print("我会做饭。。。")
            else:
                print("我不会做饭。。。")
    
        def canGetMoney(self):
            print("我会挣钱。。。")
    xiaozhai
    = Friend(26, "", 178) jian = Friend(18, "", 155)

    实例2:类也可以没有初始化

    class Friend:
    
        #定义功能——会做饭
        def canCook(self, can=True):
            if can == True:
                print("我会做饭。。。")
            else:
                print("我不会做饭。。。")
    
        def canGetMoney(self):
            print("我会挣钱。。。")
    
        def setAge(self, age):
            self.age = age
            print("年龄为:", self.age)
    
        def setHeight(self, height):
            self.height = height
            print("身高为:", self.height)
    
        def setWeight(self, weight):
            self.weight = weight
            print("体重为:", self.weight)
    
        def setMoney(self, money):
            self.money = money
            print("资产为:", self.money)
    
    jian = Friend()
    print(jian.age)
    
    
    运行结果:
    Traceback (most recent call last):
      File "D:/python_workshop/python6/revise/类和对象(一).py", line 63, in <module>
        print(jian.age)
    AttributeError: 'Friend' object has no attribute 'age'

    当直接调用函数后,再打印属性发现有age了,因为函数setAge里生成了一个全局属性age

    jian = Friend()
    jian.setAge(25)
    print(jian.age)
    
    
    运行结果:
    年龄为: 25
    25

    四. 类的继承

    1. 子类拥有父类的所有属性和行为

    2. 子类可以扩展自己的属性和行为

    3. 父类的行为不够用,子类要升级和优化,子类可重写父类的方法——多态

    4. 子类和父类都有的行为:子类实例优先使用自己的,没有再去用父类的

    支持多继承

    多继承语法:用逗号隔开父类

          class 子类类名(父类1, 父类2):

    class Son(Father, Mother):
    
      def __init__():
    
        XXXX

    实例

    class Father:
    
        def __init__(self, id, name, sex, age):
            self.id = id
            self.name = name
            self.sex = sex
            self.age = age
    
        def eat(self, food):
            print("eat:", food)
    
        def earnMoney(self, money):
            print("Father earn money:", money)
    
    
    class Mother:
    
        def sing(self):
            print("xxxxxx")
    
        def earnMoney(self, money):
            print("Mother earn money:", money)
    
    
    
    #子类继承了两个类的所有属性和方法
    class Son(Father, Mother):
    
        #方法重写,调用该方法时会调用自己的方法
        def eat(self, food):
            print("eat:", food)
            print("我吃的更快,比father更快!!!")
    
        def dance(self):
            print("xxxxxx")
    
    
    #子类没有定义的初始化方法,但是父类定义了初始化方法
    #则子类实例化时会调用父类的初始化方法
    jian = Son(123, "jian", "male", 22)
    jian.eat("apple")
    #当子类继承了多个类中同样的方法时,子类会优先使用第一个继承类的方法(从左向右)
    jian.earnMoney(2000)
    
    #父类实例化
    jianBB = Father(111, "li", "male", 56)
    jianBB.eat("orange")

    运行结果

    eat: apple
    我吃的更快,比father更快!!!
    Father earn money: 2000
    eat: orange

    继承—super用法

    在子类的行为中,想调用父类的行为,然后再做额外扩展,可以使用super类

    语法:super().行为(参数)

    class Son(Friend):
    
      def __init__(self, age, sex, name):
    
        super().__init__(age, sex)
    
        #Friend.__init__(age, sex)  这样也可以 
    
        self.name = name

    五. 封装数据

    实现方式:遵循一定的属性和方法命名规约

    不希望这些变量或者方法被外部使用

    • 任何以单下划线_开头的名字都应该是内部实现

    即不希望通过实例名字,变量名/方法名来调用,但是python并不会真的阻止别人访问内部名称,子类也可以继承并重写父类的方法,只是一种约定

    • 以双下划线__开头的名字,仅类自己可访问

    继承——这种方法通过继承是无法被覆盖(重写)的。其实也是可以访问的,只不过换成了_类名__变量名/函数名

    class MyClass:
    
        def __init__(self):
            self._private_data1 = "私有方式一"
            self.__private_data1 = "私有方式二"
            pass
    
        def _pri_func(self):
            print("私有方法一")
    
        def __pri_func(self):
            print("私有方法二")
    
        def public_func(self ):
            print("公开方法")
            #类内部调用自己的私有方法一
            self._pri_func()
    
    mc = MyClass()
    #仍然可以调用单下划线的属性和方法,只不过作为一种约定,告诉别人请不要这样调用
    mc._pri_func()
    mc._private_data1
    #mc.__private_data2  双下划线的方法无法调用
    
    class SonClass(MyClass):
    
        #子类继承父类的单下划线私有方法并重写,也是可以的
        def _pri_func(self):
            print("我是子类的私有方法")
        
        
        #子类无法继承父类的双下划线私有方法并重写,运行时报错
        def __pri_func(self):
            print("我是子类的私有方法二")
    
    son = SonClass()
    son.__pri_func()

    运行结果

    Traceback (most recent call last):
      File "D:/python_workshop/python6/revise/私有属性和方法.py", line 37, in <module>
        son.__pri_func()
    AttributeError: 'SonClass' object has no attribute '__pri_func'
    私有方法一

    哪种方式好

    两种不同的编码约定(单下划线和双下划线)来命名私有属性,问题就来了:到底哪种方式好呢?

    大多数而言,你应该让你的非公共名称以单下划线开头,但是,如果你清楚你的代码会涉及到子类,并且有些内部属性应该在子类中隐藏起来,那么才考虑使用双下划线方案

    六. @property和@属性名.setter

    实例属性,除了访问和修改之后,增加其他逻辑处理,如合法性等

    @property      #获取属性值:实例.属性名
    def age(self):
        return self._age
    
    @age,setter    #给属性赋值时添加了逻辑处理
    def age(self.age):
        if age in range(0, 121 ):
            self._age = age
        else:
            print("输入的年龄不符合要求哦!!")

    实例

    class People:
    
        #age是people类的属性名
        @property
        def age(self):
            return self._age
    
        @age.setter
        def age(self, age):
            if age in range(0, 121):
                self._age = age
                print(self._age)
            else:
                print("年龄不符合要求")
    
    p = People()
    p.age = 134

    运行结果:

    年龄不符合要求

    注意:

    不能写成return self.age和self.age = age,原因如下

    class People:
        '''
        ==========================================
         @property和@属性名.setter可以用来对属性的值进行一定的逻辑处理。
         但是:
        @property和@属性名.setter的小坑
        ===========================================
        在以下代码中,setter函数表示:当你使用self.age时就会自动的去调用setter
        所以在@age.setter对应的函数中,else操作中,有使用self.age。
        所以,这里的self.age相当于又去调用了setter,即又去调用了自己。就进入了一直在调用自己的状态。
        于是,就会报错:递归次数超限制。
        这个是个坑!!!
        如何解决这个问题呢?如果设置可以爬出这个坑呢??
    
        @property
        def age(self):
            return self.age
        @age.setter
        def age(self,age):
            if age not in range(0,121):
                print("age is not valid data")
            else:
                self.age = age
        ============================================
        ================以下是爬坑策略====================
        为了不要重复的来调用自己,也就是在@age.setter对应的函数当中,不要使用self.age
        所以用了另外一个变量名:self._age。这样子就不会一直调用。
        ====代码不同之处 一:@property对应的函数中,return self._age =======
        ====代码不同之处 二:@age.setter对应的函数中,else:self._age = age =======
    
        对外部使用者而言,还是age属性,即可以通过实例名.age来设置值。
        对类内部而言,就是_age属性了。
        以下是代码部分
        '''
    
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
    
        @property
        def age(self):
            return self._age
    
        @age.setter
        def age(self,age):
            if age not in range(0,121):
                print("age is not valid data")
            else:
                self._age = age
    
    
    
    p = People("jian","female")
    p.age = 100
    print(p.age)
    p.age = 122
    print(p.age)

     

  • 相关阅读:
    UGUI优化干货总结
    C#合成解析XML与JSON
    镜头跟随玩家移动
    Unity 5 Skybox 旋转
    多线程实现资源下载
    自定义配置文件的使用及加载-txt
    linux下mysql主从复制搭建
    常用模块-正则re
    Elasticsearch分布式搜索
    redis主从复制原理与优化-高可用
  • 原文地址:https://www.cnblogs.com/my_captain/p/9243168.html
Copyright © 2020-2023  润新知