zoukankan      html  css  js  c++  java
  • Python随笔10

    面向对象最重要的是类和实例,类是抽象的,是具有某些相同属性和方法的集合;实例就是根据类创建出来的一个个对象

    对象=属性+方法

    类的定义:

    class 类名(object) :

      语句

    其中object是指类继承与哪个类,(object)可不写,所有的类都继承与object类

    self参数:

      类中的方法无论是有参还是无参,默认都有第一个参数self,称为实例的引用,它也是方法和函数的区别(除此之外没有任何区别)。这个self参数,你可以将其命名为任意参数,但是最好是默认为self。它相当于Java中的this,在你将类实例化之后赋予一个对象,self参数就是这个对象本身。比如你有一个类Class和这个类的一个实例MyClass,当你调用这个对象的方法MyClass.getName(arg1,arg2)时,其实就是相当于MyClass.getName(MyClass,arg1,arg2)

    init方法:

      在类的一个对象被创建时,会立即运行一个初始化方法init方法,这个方法就相当于Java中的构造函数。在定义时需要注意init前后各有两条下划线__init()__,定义的时候第一个参数还是self。有init方法的类在创建实例化对象的时候必须给它传入和init方法中相匹配的参数,否则函数会报错。子类不能重写父类的构造方法,如果子类的构造方法中用到了父类的构造方法里面的属性,应该考虑继承。

    类的实例化:

      一个类Person()创建之后就会产生一个类对象,通过p = Person()可以创建一个Person类的实例。可以直接通过p来调用类的方法和属性(私有属性不能直接调用)。如果Person类有构造方法,在创建类的实例时,需传入对应的参数。

     类的私有属性:

      类的私有属性一般用两个下划线表示__i,类的实例不能直接访问,需要通过一些方法去访问和处理这些私有属性。这种方式保证了代码的将壮性。

      访问类的私有变量: 

    class Person():
        def __init__(self,name,age):
            self.__name =name
            self.__age = age
        def getName(self):
            return self.__name
        def getAge(self):
            return self.__age
        def setName(self,name):
            self.__name = name
        def setAge(self,age):
            self.__age = age
    
    p = Person("Tom",18)
    print(p.__name)
    print(p.__age)

      这段代码中Person类中的__name和__age属性都是私有属性,如果想直接访问这里面的属性,p.__name和p.__age,会报错

    Traceback (most recent call last):
      File "D:/PythonDemo/hello.py", line 171, in <module>
        print(p.__name)
    AttributeError: 'Person' object has no attribute '__name'

      这是因为,Python将私有变量变为了,_Person__name和_Person__age,但是不要用p._Person__name这样的方式去直接访问私有变量,因为不同版本的解释器会把__name变为不同的变量名。需要写一些方法去访问和改变私有变量。上面代码中的getName()、getAge()、setName()、setAge()方法,是用来访问和改变这些私有变量的。

    p = Person("Tom",18)
    print(p.getAge())
    print(p.getName())
    p.setName("Jerry")
    print(p.getName())
    p.setAge(22)
    print(p.getAge())

      结果为:

    18
    Tom
    Jerry
    22

    封装、继承和多态:

      类的属性和方法都是放在内部的,我们直接可以在外部使用这些方法去访问类的内部数据,不需要在外面重新写方法,也不需要知道实现的细节,这就叫封装,封装还有一个好处就是可以增加类的方法,比如getAge(),外部同样不用知道方法的细节,但是可以去访问类的数据。

      继承:当我们定义一个类时,可以从某个类继承,这个被继承的类叫做父类(SupperClass或者BaseClass)、新类叫做子类(SubClass),所有的类都继承于Object类。比方说定义一个Man()类继承于Person()类,写法应该是class Man(Person):      子类可以继承父类的方法和属性,比如Person类中有eat()方法,则Man()类中不必再写eat()方法,可以直接使用eat()方法,同样,子类也可以重写父类的方法,在子类的实例调用这个方法时,总是会调用子类的方法。

    class Person():
        def __init__(self,name,age):
            self.name =name
            self.age = age
        def eat(self):
            return "i can eat"
    
    class Man(Person):
        pass
    
    m = Man("Tom",12)
    print(m.name)
    print(m.age)
    print(m.eat())

      输出为:

    Tom
    12
    i can eat

      可以看到子类能直接使用类的属性和方法

      再来看子类重写父类的方法“

      

    class Person():
        def __init__(self,name,age):
            self.name =name
            self.age = age
        def eat(self):
            return "i can eat"
    
    class Man(Person):
        def eat(self):
            return "i eat more"
    
    m = Man("Tom",12)
    print(m.name)
    print(m.age)
    print(m.eat())

      输出为:

    Tom
    12
    i eat more

      可以看到,调用的是子类的方法

      如果一个类同时继承多个类,从左到右依次继承,对于继承的方法,也是从左到右依次查找,调用先查找到的方法。比如:

    class People:
        name = ""
        age = 0
        __weight = 0
    
        def __init__(self, n, a, w):
            self.name = n
            self.age = a
            self.__weight = w
    
        def speak(self):
            print("%s说:我今年%d岁,体重是%d公斤" % (self.name,self.age,self.__weight))
    
    
    class Student(People):
        grade = 0
    
        def __init__(self, n, a, w, g):
            People.__init__(self, n, a, w)
            self.grade = g
    
        def speak(self):
            print("%s说:我今年%d岁,读%d年级" % (self.name, self.age, self.grade))
    
    
    class Speaker:
        topic = ""
        name = ""
    
        def __init__(self, n, t):
            self.name = n
            self.topic = t
    
        def speak(self):
            print("%s说,我今天演讲的主题是%s" % (self.name, self.topic))
    
    
    class Sample(Speaker, Student):
        a = ""
    
        def __init__(self, n, a, w, g, t):
            Student.__init__(self, n, a, w, g)
            Speaker.__init__(self, n, t)
    
    test = Sample("小明", 20, 55, 3, "Python")
    print(test.speak())

      Sample(Speaker,Student)类继承于Speaker()和Student(),那么输出的结果为:

    小明说,我今天演讲的主题是Python

      如果把继承的顺序变为Sample(Student,Speaker),那么输出的结果为:

    小明说:我今年20岁,读3年级

      同时从”People.__init__(self, n, a, w)“也可以看出,子类在写构造方法时,可以直接使用父类.__init__(self,arg1,arg2...)的方式继承父类的构造方法里的属性

      多态:Python本身就是一种多态类的语言,如果某些类具有相同的方法,我们可以把它们看作同一类型的。如果Cat类和Dog类都继承于Animal类,它们都有behaviour()方法。我们可以把Animal、Cat、Dog看成Animal、Cat、Dog类型的数据,同时Cat和Dog也是Animal类型的数据,但是反过来就不成立了。我们写一个函数叫做beh,有方法behaviour(),参数类型为Animal类型,这样我们就可以往里面传入Animal、Cat和Dog类型的参数,同时如果我们新建一个类Bird(Animal)继承于Animal,也不必修改beh函数。

    class Animal:
        def behaviour(self):
            print("Animal can run")
    
    class Cat(Animal):
        def behaviour(self):
            print("Cat can miaomiaomiao")
    
    class Dog(Animal):
        def behaviour(self):
            print("Dog can wangwangwang")
    
    lst = [Animal(),Cat(),Dog()]
    for items in lst:
            print(items.behaviour())
    print("===============================")
    def beh(animal):
        animal.behaviour()
    print(beh(Animal()))
    print(beh(Cat()))
    print(beh(Dog()))

      结果为:

    Animal can run
    None
    Cat can miaomiaomiao
    None
    Dog can wangwangwang
    None
    ===============================
    Animal can run
    None
    Cat can miaomiaomiao
    None
    Dog can wangwangwang
    None

      我们只需关注,这个这个参数是Animal类型的就行了,至于具体的是属于Cat类型还是属于Dog类型,则需要看传入的参数是什么,而且当我们新增一个类Bird继承于Animal时,不需要去修改这个函数,只需要保证这个函数的正确性即可,这个就是多态便利性的一个体现。

    
    
    

      

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/bigbigtong/p/10089235.html
Copyright © 2011-2022 走看看