美文网首页
Python语法学习五之面向对象

Python语法学习五之面向对象

作者: Cehae | 来源:发表于2019-01-10 21:10 被阅读0次

一、面向对象1

1-1、定义类

语法:

class 类名:
    方法列表
# 定义类
class Car:

    def getCarInfo(self):
        # 定义属性,和Java等语言差别很大。
        print('车轮子个数:%d, 颜色%s' % (self.wheelNum, self.color))

    def move(self):
        print("车正在移动...")

    def toot(self):
        print("车在鸣笛...嘟嘟..")
1-2、创建对象
# 创建对象
BMW = Car()
BMW.color = '黑色'
BMW.wheelNum = 4

BMW.getCarInfo()
BMW.move()
BMW.toot()

print(BMW.color)
print(BMW.wheelNum)

注意:

  • BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法。
  • 第一次使用BMW.color = '黑色'表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改
  • BMW是一个对象,它拥有属性(数据)和方法(函数)
1-3、魔法函数
  • 在python中方法名如果是_ _ xxxx _ _(self)的,那么就有特殊的功能,因此叫做“魔法”方法
  • 当使用print输出对象的时候,只要自己定义了 _ _ str _ _(self)方法,那么就会打印从在这个方法中return的数据
1-3-1、构造方法: _ _ init _ _(self)
# 定义类
class Car:

    # 构造方法
    def __init__(self):
        print "__init__方法"
        self.wheelNum = 8
        self.color = '蓝色'

    def getCarInfo(self):
        # 定义属性,和Java等语言差别很大。
        print('车轮子个数:%d, 颜色%s' % (self.wheelNum, self.color))

    # 方法
    def move(self):
        print("车正在移动...")

    def toot(self):
        print("车在鸣笛...嘟嘟..")


# 创建对象
BMW = Car()

BMW.getCarInfo()

注意:

  • init()方法,在创建一个对象时默认被调用,不需要手动调用

  • init(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么init(self)中出了self作为第一个形参外还需要2个形参,例如init(self,x,y)

  • init(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去

1-3-2、_ _ str_ _(self)方法
# 定义类
class Car:

    # 构造函数
    def __init__(self, newWheelNum, newColor):
        self.wheelNum = newWheelNum
        self.color = newColor

    # 类似Java中的toString()方法
    def __str__(self):
        msg = "嘿。。。我的颜色是" + self.color + "我有" + str(self.wheelNum) + "个轮胎..."
        return msg

    def move(self):
        print('车在跑,目标:夏威夷')


BMW = Car(4, "白色")
print(BMW)
1-4、self

魔法函数中的self参数

  • 所谓的self,可以理解为自己
  • 可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思
  • 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可

二、面向对象2

2-1、私有属性

如果有一个对象,当需要对其进行修改属性时,有2种方法

    对象名.属性名 = 数据 ---->直接修改
    对象名.方法名() ---->间接修改

为了更好的保存属性安全,即不能随意修改,一般的处理方式为

    将属性定义为私有属性
    添加一个可以调用的方法,供调用
class People(object):

    def __init__(self, name):
        # 声明私有属性,类似Java中的private
        self.__name = name

    def getName(self):
        return self.__name

    def setName(self, newName):
        if len(newName) >= 5:
            self.__name = newName
        else:
            print("error:名字长度需要大于或者等于5")


xiaoming = People("dongGe")
print(xiaoming.__name)
# 执行报错
2-2、_ _ del _ _(self)方法
  • 创建对象后,python解释器默认调用_ _ init _ _()方法;
  • 当删除一个对象时,python解释器也会默认调用一个方法,这个方法为 _ _ del _ _()方法。当对象被销毁,例如内存被释放或程序结束时,会自动被调用,类似OC的dealloc()方法。
  • del 对象:类似OC的release()方法,让引用计数 -1,此时引用计数为1
import time


class Animal(object):

    # 初始化方法
    # 创建完对象后会自动被调用
    def __init__(self, name):
        print('__init__方法被调用')
        self.__name = name

    # 析构方法
    # 当对象被销毁,例如内存被释放或程序结束时,会自动被调用,类似OC的dealloc()方法
    def __del__(self):
        print("%s对象被干掉了..." % self.__name)

    def move(self):
        print("%s对象在移动" % self.__name)


# 引用计数为1
cat = Animal("波斯猫")
# 引用计数为2
cat1 = cat

# 类似OC的release()方法,让引用计数 -1,此时引用计数为1
del cat

# 调用完del方法后,cat指针指向的对象引用计数 -1,cat指针被释放,再次使用会报错
# del cat
# cat.move()
# 报错,cat指针已经被销毁了

# 类似OC的release()方法,让引用计数 -1,此时引用计数为0,对象释放,会在此时调用_ _ del _ _方法。如果注释下面代码,则cat对象会在程序结束后释放。
del cat1

print("程序2秒钟后结束,所以内存中的对象都会被释放")
time.sleep(2)
2-3、单继承
  • 子类在继承的时候,在定义类时,小括号()中为父类的名字
  • 父类的属性、方法,会被继承给子类
  • 私有的属性,不能通过对象直接访问,但是可以通过方法访问
  • 私有的方法,不能通过对象直接访问
  • 私有的属性、方法,不会被子类继承,也不能被访问
  • 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
class Animal(object):
    def __init__(self, name="动物", color="白色"):
        self.__name = name
        self.color = color

    def __test(self):
        print self.__name
        print self.color

    def test(self):
        print self.__name
        print self.color


class Dog(Animal):

    def dogTest1(self):
        print self.__name  # 不能访问到父类的私有属性
        print self.color

    def dogTest2(self):
        self.__test()  # 不能访问父类中的私有方法
        self.test()


A = Animal()
print(A.__name)  # 程序出现异常,不能访问私有属性
print(A.color)

A.__test()  # 程序出现异常,不能访问私有方法
A.test()

D = Dog(name="旺财", color="黄色")
D.dogTest1()
D.dogTest2()
2-4、多继承
  • Python和C++一样支持多继承
# 定义一个父类
class A:
    def printA(self):
        print('----A----')


# 定义一个父类
class B:
    def printB(self):
        print('----B----')


# 定义一个子类,继承自A、B
class C(A, B):
    def printC(self):
        print('----C----')


obj_C = C()
obj_C.printA()
obj_C.printB()
obj_C.printC()
  • 有多个父类的同名方法时,调用同名方法时,方法的调用顺序和多继承的顺序有关系
  • pass关键字来进行占位,让代码不要报错先能正常运行
#! /usr/bin/env python
# -*- coding: utf-8 -*-

class base(object):
    def test(self):
        print('----base test----')


class A(base):
    def test(self):
        print('----A test----')


# 定义一个父类
class B(base):
    def test(self):
        print('----B test----')


# 定义一个子类,继承自A、B
class C(A, B):
    # pass关键字来进行占位,让代码不要报错先能正常运行
    pass

    # def test(self):
    #     print('----C test----')


obj_C = C()
obj_C.test()

print(C.__mro__)  # 可以查看C类的对象搜索方法时的先后顺序。注意和继承的父类顺序有关系
# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.base'>, <type 'object'>)
2-5、重写父类方法与调用父类方法
2-5-1、重写父类方法

所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法。

class Cat(object):
    def sayHello(self):
        print("Cat--sayHello")


class Bosi(Cat):

    def sayHello(self):
        print("Bosi--sayHello")


bosi = Bosi()

bosi.sayHello()
# Bosi--sayHello
2-5-2、调用父类的方法

*方法1(Python2)

   def __init__(self, name):
       # 调用父类的__init__方法1(Python2)
       Cat.__init__(self, name)
  • 方法2(Python2)
    def __init__(self, name):
        # 调用父类的__init__方法2(Python2)
        super(Bosi, self).__init__(name)
  • 方法3(Python3)
    def __init__(self, name):
        # 调用父类的__init__方法3(Python3)
        super().__init__(name)

示例

# coding=utf-8
class Cat(object):
    def __init__(self, name):
        self.name = name
        self.color = 'yellow'


class Bosi(Cat):

    def __init__(self, name):
        # 调用父类的__init__方法1(python2)
        # Cat.__init__(self, name)

        # 调用父类的__init__方法2(python2)
        super(Bosi, self).__init__(name)

        # 调用父类的__init__方法3(python3)
        # super().__init__(name)

        self.color = 'green'


def getName(self):
    return self.name


bosi = Bosi('xiaohua')

print(bosi.name)
print(bosi.color)
2-6、多态

多态的概念是应用于Java和OC这一类强类型语言中,而Python崇尚“鸭子类型”。所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。简单来说就是父类指针指向子类对象。

class F1(object):
    def show(self):
        print 'F1.show'

class S1(F1):

    def show(self):
        print 'S1.show'

class S2(F1):

    def show(self):
        print 'S2.show'

def Func(obj):
    print obj.show()

s1_obj = S1()
Func(s1_obj) 

s2_obj = S2()
Func(s2_obj)
2-7、类属性和实例属性
  • 实例属性:也就是对象属性,某一个对象所拥有的属性,通过对象可以访问到各自的实例属性。
  • 类属性:顾名思义就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,和Java/C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象或者实例对象访问。
2-7-1、类属性
class People(object):
    name = 'Tom'  #公有的类属性
    __age = 12     #私有的类属性

p = People()

print(p.name)           #正确,可以通过实例对象来访问类属性。
print(People.name)      #正确,可以通过类对象来访问类属性。

print(p.__age)            #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age)        #错误,不能在类外通过类对象访问私有的类属性
2-7-2、实例属性(对象属性)
class People(object):
    address = '山东' #类属性

    def __init__(self):
        self.name = 'xiaowang' #实例属性
        self.age = 20 #实例属性

p = People()
p.age =12 #实例属性

print(p.address) #正确,可以通过实例对象访问类属性

print(p.name)    #正确,可以通过实例对象访问自己的实例属性
print(p.age)     #正确,可以通过实例对象访问自己的实例属性

print(People.address) #正确,可以通过类对象访问类属性

print(People.name)    #错误,不能通过类对象访问实例属性
print(People.age)     #错误,不能通过类对象访问实例属性
2-7-3、通过实例(对象)去修改类属性的坑!!!
  • 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。看下面例子:
class People(object):
    country = 'china'  # 类属性

print("1" + People.country)

p = People()
print("2" + p.country)

p.country = 'japan'  # 一定要注意,这句代码相当于是给p对象添加一个实例属性!!!类似下面
p.name = 'cehae' #给p对象添加一个name实例属性

print("3" + p.country)  # 实例属性会屏蔽掉同名的类属性,此时访问的是上面添加的country实例属性

print("4" + People.country)
print("5" + p.country)

del p.country  # 删除实例属性
print("6" + p.country)  # 删除实例属性后,此时访问的是类属性
图片.png
2-8、类方法和静态方法
2-8-1、类方法

是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。

class People(object):
    country = 'china'

    # 类方法,用classmethod来进行修饰
    @classmethod
    def getCountry(cls):
        return cls.country

    @classmethod
    def setCountry(cls, country):
        cls.country = country

p = People()
print p.getCountry()  # 可以用实例对象来调用类方法
# china
print People.getCountry()  # 可以用类对象来调用类方法
# china
p.setCountry('japan')  # 可以用实例对象来调用类方法
People.setCountry('us')  # 可以用类对象来调用类方法

print p.getCountry()  # 可以用实例对象来调用类方法
# us
print People.getCountry()  # 可以用类对象来调用类方法
# us
2-8-2、静态方法

静态方法是指类中无需实例参与即可调用的方法(不需要self参数),在调用过程中,无需将类实例化,直接在类之后使用.号运算符调用方法。

通常情况下,静态方法使用@staticmethod装饰器来声明。

示例代码:

class ClassA(object):

    @staticmethod
    def func_a():
        print('Hello Python')

if __name__ == '__main__':
    ClassA.func_a()
    # 也可以使用实例调用,但是不会将实例作为参数传入静态方法
    ca = ClassA()
    ca.func_a()

这里需要注意的是,在Python 2 中,如果一个类的方法不需要self参数,必须声明为静态方法,即加上@staticmethod装饰器,从而不带实例调用它。

而在Python 3中,如果一个类的方法不需要self参数,不再需要声明为静态方法,但是这样的话只能通过类去调用这个方法,如果使用实例调用这个方法会引发异常。

class ClassA(object):


    def func_a():
        print('Hello Python')

if __name__ == '__main__':
    ClassA.func_a()
    # 以下使用实例调用会引发异常
    ca = ClassA()
    ca.func_a()

异常信息:
func_a() takes 0 positional arguments but 1 was given
因为func_a没有声明为静态方法,类实例在调用func_a时,会隐式地将self参数传入func_a,而func_a本身不接受任何参数,从而引发异常。
2-8-3、静态方法/类方法/实例方法的总结

Python静态方法/类方法/实例方法的总结1
Python静态方法/类方法/实例方法的总结2

图片.png
  • 1.实例方法:第一个参数强制为实例对象,可以通过这个实例对象访问实例属性,可以通过实例对象的_ _ class _ _属性访问类属性。只能使用实例对象调用实例方法。

  • 2.类方法:类方法的第一个参数强制为类对象,可以通过这个类对象访问类属性,由于没有传入实例对象,不能访问实例属性。可以使用类对象和实例对象来调用类方法。

  • 3.静态方法:没有默认的第一个参数,其实跟类没什么关系,只是绑定在类命名空间下的函数而已。可以使用类对象和实例对象来调用静态方法。

  • 4.同时出现三者同名的方法,调用时以最后声明的为准!!!

class People(object):
    country = 'china'

    # 实例方法,Python2中实例方法必须带有self参数
    def getCountry(self):
        print "实例方法"
        return People.country

    # 静态方法,用staticmethod来进行修饰
    @staticmethod
    def getCountry():
        print "静态方法"
        return People.country

    # 类方法,用classmethod来进行修饰
    @classmethod
    def getCountry(cls):
        print "类方法"
        return cls.country


p = People()
print p.getCountry()
print People.getCountry()
2-9、延伸:Java/OC中的类方法/实例方法,类属性/对象属性
  • Java/OC中的静态方法就是类方法,静态属性就是类属性。
  • Java/OC中的实例方法也称对象方法。

Java类方法和实例方法
OC类方法和实例方法
OC静态变量

相关文章

网友评论

      本文标题:Python语法学习五之面向对象

      本文链接:https://www.haomeiwen.com/subject/bxrzrqtx.html