Python之面向对象基础

1.面向对象编程与面向过程编程

  面向对象编程,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。通过把真实的物体抽象成对象,然后赋予对象属性、方法等特性,然后去解决问题。

  面向过程编程,本质是面向结果编程,通过函数解决问题。

2. 面向对象基础

  a. 类:具有相同竖向和方法的一类事物

  b. 对象:具有具体属性的事物

  c. 静态属性:所有的对象共有的属性,可以直接调用

  d. 对象属性/方法:是属于某一个对象的,只能在实例化之后对象调用

 

class 类名:    # 类名首字母大写
    属性 = "功能"    # 类的属性:静态属性,不是必须要定义的,当多有的对象都用的时候去定义
    def __init__(self,参数):    # self是不需要传的
        #__init__这里是定义了一个该类对象共有的属性
        # 这里的属性是对象属性,
        self.key = 参数    # 这里self.key就相当于字典的key,参数就相当于value
    def 方法(self):  # 类里面的方法本质上就是函数--函数必须要传一个参数self
        pass

print(类名.属性)
# 实例化一个对象,对象就是实例
对象 = 类名("参数")    # 参数是传到__init__函数里

对象.函数名()    # 调用成功,传入的self就是对象,当用一个对象去调用对他的方法的时候,自动传入的一个参数,这个参数就是对象本身

   示例1:计算长方形的面积

class Rectangle:
    role = "retangle"
    def __init__(self,long,wide):
        self.long = long
        self.wide = wide
    def length(self):
        return 2*(self.long+self.wide)
    def area(self):
        return self.long*self.wide

rect = Rectangle(3,4)
ret_l = rect.length()
print(ret_l)
ret_a = rect.area()
print(ret_a)

   示例2:计算圆的面积

from math import pi
class Circle:
    rloe = "circle"
    def __init__(self,r):
        self.r = r
    def length(self):
        return 2*pi*self.r
    def area(self):
        return pi*self.r*self.r


val = Circle(10)
val_l = val.length()
print(val_l)
val_s = val.area()
print(val_s)

 

3. 命名空间

  a. 类的命名空间和对象的命名空间是分开的,且每个对象都有独立的命名空间,公用一个类的命名空间

  b. 调用静态属性:调用的就是类中的属性

  c. 调用动态属性:对象和类去调用的时候,表现出来的地址是不一样的,但实际是一样的

  d. 调用类的静态属性:类调用的就是类中的属性,对象调用先从自己内存空间里找名字,找到了就用自己的,没有找到就用类的,类中也没有的话就报错

  e. 调用类的动态属性:这个方法本身就存在类中,并不会存在对象的内存中,但是在对象调用类中的方法的时候,要依赖于一个地址薄去类中寻找对应的方法

  f. 类的外面可以添加静态属性或对象属性,动态属性(方法)不可以添加

  g. 关于对象的属性:
    *. 对象的属性就存在类的命名空间中
    *. 只能被对象调用修改
    *. 不能被类调用

class Birthday:    # 定义一个生日类,
    role = "birthday"   # 静态属性
    def __init__(self,year,month,day):  # 定义一些生日共有的属性
        self.year = year    # 对象属性
        self.month = month
        self.day = day

class Course:   # 定义一个课程类
    role = "course"     # 静态属性
    def __init__(self,name,period,teacher,price):
        self.name = name       # 对象属性
        self.period = period
        self.teacher = teacher
        self.price = price

class Person:   # 定义一个人类
    role = "person"     # 静态属性
    def __init__(self,name,haijiao_birth):
        self.name = name    # 静态属性
        self.birth = haijiao_birth

python = Course("python",5,"Teacher Li",200000)   # 实例化python到Course类中
john_birth = Birthday(1999,2,22)     # 实例化john_birth到Birthday类中
john = Person("john",john_birth)   # 实例化john到Person类中
print(john.birth.month)      # john.birth等价于Person类中的self.birth,而self.birth 等于 john_birth,所以就等价于john_birth.month
print(john_birth.month)    # 从类的外部去调用类内的对象属性
john_class = python      # 在外部添加对象属性,在john的小空间里
print(john_class.name)
print(john_birth.day)

 

4. 组合

  组合:一个类的对象是另一个类的属性,增强了代码的重用性

from math import pi
class Circle:
    def __init__(self,r):
        self.r = r

    def perimeter(self):
        return 2*pi*self.r

    def area(self):
        return pi*self.r*self.r

class Ring:
    def __init__(self,r_out,r_in):
        self.r_out = Circle(r_out)    # 组合
        self.r_in = Circle(r_in)

    def perimeter(self):
        return self.r_out.perimeter() + self.r_in.perimeter()

    def area(self):
        return self.r_out.area() - self.r_in.area()


val = Ring(10,5)
perimter = val.perimeter()
print(perimter)
area = val.area()
print(area)

 

5. 面向对象特性之封装

  a. 封装:将同一类方法属性封装到类中,通过构造方法,将数据封装到对象中

  b. 私有属性,私有方法(双下划线+属性名/方法名

class Teacher:
    __identifier = "Teacher"    # 私有静态属性
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd    # 私有属性
        self.__p()  # 调用私有方法

    def pwd(self):
        print(self.__pwd)

    def __p(self):  # 私有方法
        print(self.__pwd)


wu = Teacher("Wu","3714")
wu.pwd()
print(wu.__dict__)    # 打印属于wu的属性

# 类外调用私有属性(_类名__私有属性名)--不要去使用这个方法
print(wu._Teacher__pwd)

# 类外调用私有方法
wu._Teacher__p()

# 类外调用私有静态属性
print(Teacher._Teacher__identifier)

# 类外定义私有属性形式的属性,没有任何意义,就跟普通属性一样的

  c. 私有方法的意义:

    *. 有一些方法的返回值只是用来作为中间结果

    *. 父类的方法不希望子类继承

class Teacher:
    __identifier = "Teacher"
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd
        self.__p()

    def __p(self):
        return hash(self.__pwd)

    def judge(self,password):
        return hash(password) == self.__p()


wu = Teacher("wu","3714")
ret = wu.judge("3417")
print(ret)

 

   d. 私有属性

class Person:
    def __init__(self,name,height,weight):
        self.name = name
        self.__height = height
        self.__weight = weight

    def get_bmi(self):
        return self.__weight /(self.__height * self.__height)

    def change_weigth(self,new_weight):
        if new_weight > 20:
            self.__weight = new_weight
        else:
            print("体重过轻")

ha = Person("ha",1.81,94)
print(ha.get_bmi())
ha.change_weigth(80)
print(ha.get_bmi())

  示例

class Host:
    def __init__(self,owner,length,width):
        self.owner = owner
        self.__length = length
        self.__width = width
    def area(self):
        return self.__length * self.__width

host = Host("lu",50,30)
print(host.area())

   e. property方法:把类中的方法假装成一个属性

class Person:
    def __init__(self,name,height,weight):
        self.name = name
        self.__height = height
        self.__weight = weight

    @property
    def bmi(self):
        return self.__weight /(self.__height * self.__height)


lu= Person("lu",1.81,94)
print(lu.name,lu.bmi)    # 这里去调用的时候,就是相当于调用一个属性

     *. @要伪装的方法名.setter,这样就更加像属性

class Shop:
    discount = 0.75
    def __init__(self,name,price):
        self.name = name
        self.__price = price

    @property
    def price(self):
        return self.__price * Shop.discount

    @price.setter
    def price(self,new_price):
        self.__price = new_price

    @price.deleter  # 一般不会用到
    def price(self,):
        del self.__price

apple = Shop("apple",5)
print(apple.price)
apple.price = 6     # @price.setter,用了这个方法之后,就可以修改了
print(apple.price)
print(apple.__dict__)
del apple.price
print(apple.__dict__)

   f. staticmethod:静态方法,函数不需要依赖对象的属性和类的属性,就可以使用staticmethod装饰

class A:
    def __init__(self,name):
        self.name = name

    def ah(self):   # self就是形式参数,ah就是普通方法,绑定(对象)方法
        print("ah")

    @staticmethod   # 静态方法
    def func():
        print("func")

# a = A("a")
# A.func(a)   #和a.func()一样
A.func()

   g. 类方法:对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。

class A:
    role = "a"
    @classmethod
    def class_metood(cls):  #这里必须叫cls,默认的
        print(cls.role)

A.class_metood()
# A.role

 

   h. 小结

 

    *. 静态方法--没有必须传的参数,不需要用对象的属性和类的属性

    *. 类方法--必须传一个类,不能使用对象属性,但可以使用类属性

    *. 普通方法--必须传一个参数,可以使用对象的属性和类的属性

 

6. 面向对象特性之继承

  a. 继承:当两个类有相同的方法或属性的时候,把这些相同的方法属性封装到基类类中,只实现一次,其它类去继承

  b. 继承是A类是B类子类的关系,而组合是A类中有B类的关系

    *. 父类/超类/基类,子类/派生类

    *. object是所有类的基类,type是所有类的类型,metaclass可以指定类的类型

    *. 对象可以调用自己本类和父类所有的方法和属性,先调用自己的.

    *. 先抽象在继承
      抽象---从小类到大类
      继承---从大类到小类

  c. 单继承,多继承

class Animal:   # 父类
    def eat(self):
        pass
    def drink(self):
        pass
    def sleep(self):
        pass

class Bnimal:   # 父类
    def eat(self):
        pass

    def drink(self):
        pass

    def sleep(self):
        pass

class Dog(Animal):   # 单继承
    pass

class Cat(Animal,Bnimal):   # 多继承
    pass

print(Dog.__bases__)    # (查看所有父类)
print(Cat.__base__)     # (查看从左到右的第一个父类)

   d. super()方法

    *. 在继承中,子类可以继承父类所有的属性和方法,当父类和子类中有同名方法的时候,一定调用子类的。如果想使用父类的该方法的功能,需要借助super方法。

class A:
    def hahaha(self):
        print("A")

class C:
    def hahaha(self):
        print("C")

class B(A,C):
    def hahaha(self):
        # B.hahaha(self)    # 经典类的调用父类中方法的方式

        # super--新式类,当多个父类有同名方法时,先从前面找,优先使用第一个找到的
        # super(B,self).hahaha()   # 里面这里可以传,或者不传,
        super().hahaha()    # 一般不传,因为在子类里边,很容易就知道是哪个类
        print("B")

b = B()
b.hahaha()  # 调用了自己的hahaha()
super(B,b).hahaha()    # 相当于A.hahaha(),外部的时候,必须传参

  示例

class Animal:   #---父类
    def __init__(self,name):
        self.name = name
    def eat(self):
        print("%s is eating %s"%(self.name,self.food))
    def drink(self):
        print("%s is drinking %s" % (self.name, self.food))
    def sleep(self):
        print("%s is sleeping %s" % (self.name))


class Dog(Animal):#---单继承
    def __init__(self,name):
        self.food = "狗粮"
        super().__init__(name)
    def say(self):
        print("汪汪汪")

class Cat(Animal):
    def __init__(self,name):
        self.food = "猫粮"
        super().__init__(name)
    def say(self):
        print("喵喵喵")

wang = Dog("wang")
wang.eat()A

c = Cat("egon")
c.eat()

 

 

class Animal:
    def __init__(self,name,food):
        self.name = name
        self.food = food
        self.family = "大森林"
    def eat(self):
        print("%s is eating %s"%(self.name,self.food))
    def drink(self):
        print("%s is drinking"%(self.name))
    def sleep(self):
        print("%s is sleeping"%(self.name))
    def call(self):
        print("%s is calling %s" % (self.name,self.calling))

class Dog(Animal):#游泳
    def __init__(self,name):
        super().__init__(name, "骨头")
        self.calling = "汪汪汪"
        self.family = "小破屋"
    def swim(self):
        print("%s swimming"%self.name)

class Bird(Animal): #飞
    def __init__(self,name):
        super().__init__(name,"虫子")
        self.calling = "布谷"
    def fly(self):
        print("%s flying"%self.name)


erha = Dog("erha")
erha.call() #调用父类的方法
erha.swim() #调用自己的方法
print(erha.family)  #优先使用自己的
print("******************************")
cuckoo  = Bird("cuckoo")
cuckoo.call()
print(cuckoo.family)#因为他本身没有,所以直接用父类的

 

  e. 派生属性和派生方法

    *. 派生属性--在父类没有的基础上,子类自己有的属性

    *. 派生方法--在父类没有的基础上,子类自己的方法

class Animal:   #父类,人和动物都有的一些属性
    def __init__(self,name,blood,aggr):
        self.name = name
        self.blood = blood
        self.aggr = aggr

class Person(Animal):   #继承的语法,Person是子类,继承了父类Animal的属性
    def __init__(self,name,blood,aggr,money):
        super(Person,self).__init__(name,blood,aggr)    #在子类执行父类的方法
        self.money = money      #派生属性
    def attack(self,dog):   #派生方法
        dog.blood -= self.aggr

class Dog(Animal):  #继承的语法,Dog是子类,继承了父类Animal的属性
    def __init__(self,name,blood,aggr,breed):
        super().__init__(name,blood,aggr)
        self.breed = breed
    def attack(self, person):
        person.blood -= self.aggr



alex = Person("alex",2000,250,1000000)
erha = Dog("erha",2000,250,"金毛")

 

  f. 经典类,新式类

    *. 经典类和新式类的区别:

      1. 定义顺序

      2. 子类执行父类中的同名方法

      3. 继承问题
    *. python2里有经典类和新式类之分

      经典类--深度优先

      新式类--广度优先 

class A:  # 经典类
    pass
class B(object):  # 新式类
    pass

     *. 在python3中,object是所有类的基类 

 

  g. 钻石继承:python的新式类和经典类在继承顺序上的不同

class F:
    def test(self):
        print("F")

class E(F):
    pass
    def test(self):
        print("E")

class D(F):
    pass
    def test(self):
        print("D")

class C(E):
    pass
    def test(self):
        print("C")

class B(D):
    pass
    def test(self):
        print("B")

class A(B,C):
    pass
    def test(self):
        print("A")

a = A()
a.test()
A-B-D-C-E-F

 

class D():
    pass
    def test(self):
        print("D")

class C():
    pass
    def test(self):
        print("C")

class B(D):
    pass
    def test(self):
        print("B")

class A(B,C):
    pass
    def test(self):
        print("A")

a = A()
a.test()

# 这个的继承是A-B/C,B-D,C没有父类
# 这种情况下,A中没有时,先找B,B中没有时先找D,D里边没有的时候,就找C

 

7. 多态

  a. 多态指的是一类事物有多种形态,python天生支持多态,不同的类可以有一样的方法,但是功能是不一样。
  b. 鸭子模型
    对于一个对象来说,只要它能鸭子叫,就是鸭子,不管它是什么形态,这就是多态
    对于一个对象来说,只要能使用一个方法,就不管他是什么形态的

 

8. 抽象类和接口类

  a. 接口类:归一化设计

from abc import abstractmethod,ABCMeta

class Payment(metaclass=ABCMeta): # 接口类/抽象类,子类的规范(约束子类必须要有这个里的方法,不然就抛异常) @abstractmethod # 加了一个装饰器 def payment(self,money): raise NotImplemented class Applepay(Payment): def payment(self,money): print("apple 支付了 %d元"%money) class Alipay(Payment): def payment(self,money): print("支付宝 支付了 %d元"%money) class Wechatpay(Payment): def huaqian(self,money): print("微信 支付了 %d元"%money) def payment(pay_obj,money): pay_obj.payment(money) apple = Applepay() ali = Alipay() payment(apple,200) payment(ali,100) wechat = Wechatpay() wechat.payment(wechat,100) # 因为他没有payment方法,所以会报错 # TypeError: Can't instantiate abstract class Wechatpay with abstract methods payment

   b. 抽象类:抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

from abc import abstractmethod,ABCMeta

class Foo(metaclass=ABCMeta): # 抽象类 @abstractmethod def read(self): # 抽象类去实现了方法 f = open() f.read() f.close() def write(self): f = open() f.write() f.close() class File(Foo): def read(self): super().read() def write(self): super().write() class Disk(Foo): def read(self): super().read() def write(self): super().write()

 

  c. 对比

    a. 接口类不实现具体的方法,并且可以多继承;抽象类可以做一些基础实现,并且不推荐多继承

    b. 在抽象类中,我们可以对一些抽象方法做出基础实现;而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现

 

  d. 小结

    *. 编程思想:为子类做规范
      归一化设计:几个类都实现了相同的方法
      抽象类:最好单继承,且可以简单的实现功能
      接口类:最好多继承,且最好不实现具体功能

    *. 开放封闭原则:扩展是开放的,修改是封闭的

    *. 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程

    *. 接口隔离原则:使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

 

  

 

posted @ 2020-01-12 16:46  chitalu  阅读(209)  评论(0编辑  收藏  举报