zoukankan      html  css  js  c++  java
  • Python入门之面向对象编程(二)python类的详解

    本文通过创建几个类来覆盖python中类的基础知识,主要有如下几个类

    • Animal :各种属性、方法以及属性的修改
    • Dog :将方法转化为属性并操作的方法
    • Cat :私人属性讲解,方法的继承与覆盖
    • Tiger :子类定义时调用父类方法(super的使用)

    Animal

    python中的一个类中有属性和方法,而二者都分为很多种类型,如下所示

    • 属性分为普通属性和类属性
    • 方法分为普通方法、类方法、静态方法。
    • 具体定义方法和使用见下面的代码和注释,各个属性和方法的使用习惯等见最后的 print_animal 函数打印出的结果

    下面是类的定义

    class Animal:
        
        # 这里是属性定义
        actually = "animal" # 类属性
        
        def __init__(self, name, age): # 定义实例时,放在括号里的才要指定
            self.name = name # 普通属性,要在__init__方法中定义
            self.age = age
        
        # 下面是方法的定义
        def sleep(self): # 普通方法
            print(self.name, "is sleeping")
            
        def eat(self, food): # 普通方法,另带参数
            print(self.name, "is eating", food)
        
        @classmethod
        def sentence(cls, adv): # 类方法,使用装饰器变成类方法
            print("I am", adv, "an", cls.actually)
        
        @staticmethod
        def other(person, do): # 静态方法
            print(person, "is", do+"ing")
        
        @staticmethod
        def print_animal():
            print("这是之后定义子类的父类,主要讲解最基本的属性、方法以及属性的修改")
            print("类属性actually:属于整个类,每个实例都有的属性,内容相同,创建实例时不需要指定,类和实例都可以调用")
            print("普通属性name age:属于各个实例,用于存储实例数据")
            
            print("普通方法sleep eat:由对象调用,至少一个参数self")
            print("类方法sentence:由类、实例调用,至少一个参数cls,可以引用类属性")
            print("静态方法other:类中的普通函数,可由类、实例调用")
            
            print("修改类属性:用类调用修改,所有实例都更改;用实例调用修改不影响类和其他实例")
            print("修改普通属性:直接赋值即可")

    创建实例

    # 创建实例调用Animal类
    adams = Animal(name="Adams",age=2) # 创建实例
    adams.actually # 调用类属性
    # 'animal'
    Animal.actually # 类调用类属性
    # 'animal'
    adams.name # 调用普通属性
    # 'Adams'
    
    adams.sleep() # 调用普通方法
    # Adams is sleeping
    adams.eat("meat") # 有参数的普通方法
    # Adams is eating meat
    
    adams.sentence("really") # 实例调用类方法
    # I am really an animal
    Animal.sentence("actually") # 类调用类方法
    # I am actually an animal
    
    adams.other("Tim", "play") # 实例调用静态方法
    # Tim is playing
    Animal.other("Mary", "watch") # 类调用静态方法
    # Mary is watching
    
    Animal.actually = "Animal" # 修改类属性
    adams.actually
    # 'Animal'
    adams.actually = "animal"
    Animal.actually
    # 'Animal'
    adams.age = 3 # 普通属性这样就改过来了
    
    Animal.print_animal()

    Dog

    Dog类是Animal的一个子类,主要讲解三个装饰器进行方法向属性的转换。

    转换有两个主要的好处

    • 一是调用没有参数的方法时不再需要加括号,这样的方法就可以当做属性来看
    • 二是这样定义的属性赋值时可以进行判断,防止无效属性的产生

    这样的转换有两种方式

    • 一种是通过@property装饰器,这个装饰器系列一共三个,如果只是想调用这个方法可以只使用@property这个装饰器
    • 一种是通过property函数

    下面是一个例子,一些说明可以在最后面定义的print_dog方法中查看

    class Dog(Animal): # 类的继承
        
        # 只使用@property装饰器与普通函数做对比
        def eating(self):
            print("I am eating")
        
        @property # 用这个装饰器后这个方法调用就可以不加括号,即将其转化为属性
        def running(self): 
            if self.age >= 3 and self.age < 130:
                print("I am running")
            elif self.age > 0 and self.age <3:
                print("I can't run")
            else:
                print("please input true age")
                
        # 三种装饰器,可以获取、设置、删除这样定义的属性
        @property
        def country(self):
            return self._country # 注意这个属性之前从来没有定义过,是在下面的setter中定义的
        
        @country.setter # 用 函数名.setter 的装饰器
        def country(self, value): # 设置这个属性的值
            self._country = value
            
        @country.deleter
        def country(self):
            print("The attr country is deleted")
            
            
        # 用property函数实现和装饰器相同的功能
        def get_city(self):
            return self._city
        
        def set_city(self, value):
            self._city = value
            
        def del_city(self, value):
            del self._city
            
        city = property(get_city, set_city, del_city, "where it is in")
            
        @staticmethod
        def print_dog():
            print("这是Animal的一个子类,主要讲解三个装饰器进行方法向属性的转换")
            print("类继承,创建实例时仍要指定父类的普通属性")
            print("@property装饰器将方法转化为属性方式调用,此时的方法必须只有一个self参数")
            print("使用@property后可以看做一个属性(country),用property函数可以达到相同的效果(city)")
            print("注:city中property第四个参数只是一个说明,用Dog.city.__doc__来调用,即返回 where it is in")

    创建实例

    david = Dog("David", 2) # 创建实例
    
    # 只用@property的情形
    david.eating() # 调用普通方法
    # I am eating
    david.running # 用过@property装饰器后不需要加括号
    # I can't run
    
    dean = Dog("Dean", 4)
    dean.running # 在@property的属性中进行判断
    # I am running
    
    
    # @property等三个装饰器
    david.country = "America"
    print(david.country)
    del david.country # 如果这里的不出现_country则这样就可以删除,但是用self.country则真的变成了属性,所以为了区别多定义了一个_country
    del david._country # 如今需要再把这个中间变量删除掉才可以
    # 无法再调用 david.country
    
    # 不用装饰器,用函数的形式
    david.city = "Beijing"
    print(david.city) # Beijing

    Cat

    这里定义了Cat类和它的子类Blackcat,主要说明两个主题:私人属性、方法的继承与覆盖

    • 私人属性的使用是受到一定限制的,这里主要说明在哪些地方可以用,哪些地方不能调用
    • 因为子类继承父类时,会将父类的所有方法都继承过来,但是如果在子类中定义了一个和父类同名的方法,则会将父类的方法覆盖下去,__init__也是如此

    定义类

    class Cat(Animal):
        
        def __init__(self, weight): # 覆盖了父类的__init__,所以定义实例时不需要指定name和age
            self.__weight = weight
            self._weight = weight + 1
            self.weight = self._weight + 1
        
        def get_myweight(self):
            print("My weight is", self._weight, "kg")
        
        def get_trueweight(self):
            print("Actually the cat's weight is",self.__weight)
        
        @staticmethod
        def print_cat():
            print("这个类是Animal类的子类,也是Blackcat类的父类")
            print("Cat类和Blackcat类结合,主要用于讲解私人属性、方法的继承与覆盖")
            
            print("weight是普通属性,可以在外部访问,即用类调用属性获得,可以被子类内部调用")
            print("_weight这样前面加一个下划线表示希望你不要在外部访问它,但是还是可以访问的,可以被子类内部调用")
            print("__weight这样加两个下划线的是不允许外部访问的,只可以在类中被调用,不可以被子类内部调用")
            
            print("__init__在子类中定义则覆盖了父类中的__init__,不需要指定父类中的属性,也无法调用父类的属性")
            print("在子类中实现和父类同名的方法,也会把父类的方法覆盖掉")
            
    class Blackcat(Cat):
        
        def get_weight(self):
            print("My weight is", self.weight)
        
        def get_weight_again(self): # 可以
            print("Actuall my weight is", self._weight)
            
        def get_true_weight(self): # 这个方法因为无法调用self.__weight所以这个方法无法使用
            print("My weight is exactly", self.__weight)
            
        def get_trueweight(self): # 覆盖了Cat父类中定义的方法
            print("My weight is exactly", self._weight+1)

    创建实例

    # 测试私人变量的外部访问
    cole = Cat(5)
    cole.weight
    # 7
    cole._weight
    # 6
    cole.get_trueweight() # 在类中引用__weight,用这个方法返回
    # Actually the cat's weight is 5
    cole._Cat__weight # 非要访问也可以,其实是python解释器把__weight改成了_Cat__weight
    # 5
    
    # 测试私人变量的子类调用
    cain = Blackcat(5)
    cain.get_weight()
    # My weight is 7
    cain.get_weight_again()
    # Actuall my weight is 6
    # cain.get_true_weight() # 报错
    
    # 测试方法的继承与覆盖
    cain.get_myweight() # 
    # My weight is 6 kg
    cain.get_trueweight() # 子类中同名函数覆盖父类
    # My weight is exactly 7

    Tiger

    Tiger 和 Whitetiger类中主要讲解super的用法。super用于在子类中调用父类方法及属性。我们上面讲过,子类实例可以直接使用父类的方法,而在子类的定义中,肯定不能直接将父类的方法和属性当成已经定义的而拿过来用,因为那些属性和方法都是父类的,self指向的是父类而不是子类,所以用self调用不了这些方法和属性。所以super就是一个用来创建父类的self以调用父类方法和属性的函数

    super(Whitetiger, self) 表示Whitetiger类的父类的self,它就可以调用父类的方法和属性了

    创建实例

    class Tiger:
        
        def __init__(self, name):
            self.name = name
            
        def eat(self):
            return "I am eating"
        
        def myname(self):
            return "my name is " + self.name
    
    class Whitetiger(Tiger):
        
        # 继承父类中的属性,再添加
        def __init__(self, name, height): # 调用父类中的name也要写在这里
            # 注意这里继承属性需要把所有属性全都继承过来
            super(Whitetiger, self).__init__(name) # 用super调用函数的参数也都要写全
            
            # Tiger.__init__(self, name) # 也可以这样不用super
            # 但是当Whitetiger的代码需要修改,继承的父类改变,这样写就需要改很多地方,所以最好用super
            
            self.height = height
        
        # 简单调用父类方法
        def eatmore(self):
            return super(Whitetiger, self).eat() + " more"
        
        # 定义这个时要使用父类中的属性name,必须在__init__中将name属性继承过来才能使用这个方法
        def realname(self):
            return "Actually " + super(Whitetiger, self).myname()

    创建实例

    wtony = Whitetiger("Tony",100)
    wtony.eatmore() # 'I am eating more'
    wtony.realname() # 'Actually my name is Tony'

    参考

  • 相关阅读:
    jmeter录制rabbitmq消息-性能测试
    plsqll连接Oracle的两种方式
    Badboy录制脚本时,提示脚本错误的解决方法
    Decorator
    PyObject and PyTypeObject
    Python LEGB (Local, Enclosing, Global, Build in) 规则
    Python Namespace
    Method Resolve Order (MRO)
    Source Code Structure
    Bound Method and Unbound Method
  • 原文地址:https://www.cnblogs.com/JetpropelledSnake/p/8947474.html
Copyright © 2011-2022 走看看