Python第九课 类和对象

Posted 笔触狂放

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python第九课 类和对象相关的知识,希望对你有一定的参考价值。

9.1 类的定义以及创建对象

类是对象的抽象,对象是类的具体。先有类才有对象,先对具体的事务进行分类,该事务才称为该分类的对象。类是由属性和行为组成,也就是变量和方法组成。

# 定义一个学生类
class Student:
    name="小明"
    age=20
    sex="男"
    phone="18170072135"

    def run(self):
        print("我在跑步")
    def say(self):
        print("我是一名优秀的开发者")

        
# 运行Student类
stu=Student()
stu.run()
stu.say()

self关键字是表示当前类对象的作用。

运行结果:

我在跑步

我是一名优秀的开发者

9.2 构造方法的定义和使用

python中提供了很多魔法方法,格式类似于:__变量名__

为类创建构造方法的是__init__方法,用于在创建类的对象的时候就对全局变量进行初始化赋予值

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

    def kick(self):
        print("我叫%s,多多指教!!!"%self.name)

p=Potato("土豆")
p.kick()

运行结果:我叫土豆,多多指教!!!

通过以上代码可发现,在python中全局变量是可以不用提前声明的,在调用过程中被创建。

9.3 公有属性和私有属性

在各种面向对象的编程语言中会区分公有属性和私有属性,例如Java中就通过定义public和private关键字来定义属性变量。在python中并没有使用任何关键字来定义变量。而是在变量的前面加上“__”双下划线,表示私有变量。

class Person:
    name="程序猿"
    #私有属性,外部不能直接访问
    __color="黄种人"
    
person=Person()
print(person.name)

那如果在外部需要访问私有属性怎么办?

print(person._Person__color)

就能输出访问私有变量

同理,私有变量也可以不需要提前声明,在init魔法方法中直接被隐藏定义。

class Person:
    name="程序猿"
    #私有属性,外部不能直接访问
    __color="黄种人"

    def __init__(self,sex):
        self.__sex=sex

    def getSex(self):
        return self.__sex

person=Person("男")
print(person.name)
print(person._Person__color)
print(person.getSex())

9.4 继承

编程语言是用来描述现实社会中一切事务,因此就存在分类和分类之间存在继承的关系,我们很容易理解的就是把所有人作为一类为人类,再细化一下可以分为男生类,女生类,男生类再细化一下可以分老年人,中年人,青少年等等。那么这种分类之间存在的关系是一种分类上的包含,对某一个中抽象的分类进行细化的过程,在编程语言中这种机制称为继承,语法结构如下:

class 类名(被继承的类):

……

被继承的类称为基类,父类或者超类,继承者称为子类,一个子类可以继承它的父类的任何属性和方法。

#继承关系
#父类
class Person:
    def hello(self):
        print("说哈喽")

# 子类
class Child(Person):
    name="子类"

# 创建父类自己的对象,调用自己的方法
p=Person()
p.hello()
# 创建子类的对象,调用父类的方法
c=Child()
c.hello()
#运行结果中发现父类和子类对象都能调用父类的方法

如果子类中定义了与父类中相同的方法和属性,则子类中的方法会自动覆盖父类的方法,这里称为叫子类重写父类的方法。那么父类对象调用的是父类的方法,子类对象调用的是重写父类后的方法。

#继承关系
#父类
class Person:
    def hello(self):
        print("说哈喽")

# 子类
class Child(Person):
    name="子类"
    # 子类重写父类的方法
    def hello(self):
        print("子类说哈喽")

# 创建父类自己的对象,调用自己的方法
p=Person()
p.hello()
# 创建子类的对象,调用父类的方法
c=Child()
c.hello()

在继承关系中,是先有父亲才有孩子,因此涉及数据的调用的时候,一定要注意这一点,例如:

#继承关系
#父类
class Person:
     # 定义构造方法初始化父类的年龄
    def __init__(self):
        # 假设父亲老王
        self.name="老王"
    def p_say(self):
        print("我是父亲,我叫%s"%self.name)
   

# 子类
class Child(Person):
    # 定义构造方法初始化子类的年龄
    def __init__(self,age):
        self.age=age
    def say(self):
        print("我是子类,我的年龄是%d岁"%self.age)

# 创建父类自己的对象,调用自己的方法
p=Person()
p.p_say()#我是父亲,我叫老王
# 创建子类的对象
c=Child(20)
c.say()#我是子类,我的年龄是20岁

通过以上运行发现父类可以通过构造方法初始化父亲自己的名字,子类在创建对象的时候传入了子类的年龄给子类自己的构造方法进行初始化年龄,因此各自通过对象调用方法显示年龄和名字。但因为子类是继承父类的,因此子类可以调用父亲的方法,子类代替父类说出父亲的名字:

# 创建子类的对象,调用父类的方法
c=Child(20)
c.say()
c.p_say()

但运行起来居然报错,提示的错误是子类调用父类的方法时,父类的名字没有被初始化,找不到name这个变量,那是因为name这个变量是在父类的构造方法中被初始化的,因此子类在调用父类的方法的时候,子类应该在创建自己对象之前,需要先初始化父类构造方法,这也很好理解,因为现有父亲才有儿子嘛。因此需要在子类构造方法中调用父类的构造方法。子类定义成一下代码即可:

# 子类
class Child(Person):
    # 定义构造方法初始化子类的年龄
    def __init__(self,age):
        Person.__init__(self)
        self.age=age
    def say(self):
        print("我是子类,我的年龄是%d岁"%self.age)

 这里也可以使用super关键字,这样我们在子类中就不需要明确表示父类是谁,python会自动寻找其父类:

# 子类
class Child(Person):
    # 定义构造方法初始化子类的年龄
    def __init__(self,age):
        super().__init__()
        self.age=age
    def say(self):
        print("我是子类,我的年龄是%d岁"%self.age)

super函数的优点在于不需要明确给出任何基类的名字,它会自动帮您找出所有基类以及对应的方法。由于你不用给出基类的名字,这就意味着如果需要改变继承关系,只要改变class语句里的父类即可,而不必在大量代码中去修改所有被继承的方法。

9.5 多重继承

python还支持多重继承,就是可以同时继承多个父类的属性和方法:

# 多重继承
class base1:
    def fool1(self):
        print("我是fool1,我在base1中……")

class base2:
    def fool2(self):
        print("我是fool2,我在base2中……")

# 定义子类,继承多个父类
class C(base1,base2):
    name="子类"

c=C()
c.fool1()#我是fool1,我在base1中……
c.fool2()#我是fool2,我在base2中……

多重继承很容易导致代码混乱,逻辑混乱,再不确定是否需要使用多重继承的时候,尽量避免使用。

9.6 组合

在操作不是同一个类别的类时,使用组合的方式,给定一个包含这些不同种类的类,创建对象即可。

# 组合
# 定义乌龟类
class Turtle:
    def __init__(self,x):
        self.num=x
# 定义鱼类
class Fish:
    def __init__(self,x):
        self.num=x
# 定义水池类
class Pool:
    def __init__(self,x,y):
        self.turtle=Turtle(x)
        self.fish=Fish(y)
    def print_num(self):
        print("水池里总共有乌龟%d只,小于%d条"%(self.turtle.num,self.fish.num))

# 执行
pool=Pool(1,10)
pool.print_num()
运行结果:水池里总共有乌龟1只,小于10条

9.7 类,类对象和实例对象

# 类对象
class D:
    count=0
#同一个类创建三个对象
a=D()
b=D()
c=D()
# 在内存中表示创建了三块相互独立的内存
print(a.count,b.count,c.count)#0 0 0
# 给c对象赋值
c.count=10
# 会发现只有c对象的变量值会发生变化,可以说明以上三个对象是相互独立的
print(a.count,b.count,c.count)#0 0 10
# 使用类对象进行赋值
D.count=100
# 前两个对象的count变量是没有赋值的,只有第三个对象的变量赋值为10
# 但通过类对象给count赋值后,这里表示给一个count的静态变量进行赋值为100
# 因此这里的a.count和b.count输出的是静态变量count的值,只有c.count被初始化了,打印的是c对象的全局变量count的值
print(a.count,b.count,c.count)#100 100 10

9.8 方法的绑定关系

其实这里说的绑定就是方法中传self和不传self的区别,在类中定义的方法不传self,则表示调用该方法不需要对象,也就是说直接使用类名就可以调用该方法,等价于Java中给方法加上static关键字的静态方法,但在python中该类的对象是不能在调这个方法。

# 绑定
class BB:
    def printBB():
        print("no zuo no die")
BB.printBB()

这种情况称为未绑定,也就是可认为该方法没有绑定对象。

这里介绍一个_dict_魔法方法,用于输出显示对象或者类所拥有的属性和方法。输出的结果是以字典的形式显示,字典中仅存在对象的属性,不显示类属性。

9.9 关于类和对象的内置函数

1.issubclass(class,classinfo)

该方法用于判断后者是否包含或者等于前者,也就是如果第一个参数对象是第二个参数对象的子类,则返回True,否则是False

class A:
    def a(self):
        print("a")
class B(A):
    def B(self):
        print("B")
print(issubclass(B,A))
print(issubclass(B,B))
print(issubclass(B,object))

结果都为True,一切对象的父类都是object。

2.isinstance(object,classinfo)

该方法用于判断某个对象是否是该类的对象,或者是该类的子类的对象

b=B()
print(isinstance(b,B))
print(isinstance(b,A))
print(isinstance(b,(A,B,C)))

结果都为True,A和B是继承关系,B类的对象都是AB类的一脉相传。

3.hasattr(object,name)

该方法用于判断某个属性是否是该类的对象的属性,这里私有属性不能被判断

class B(A):
    def __init__(self):
        self.bb=100
        self.__cc=10
    def B(self):
        print("B")
print(hasattr(b,"bb"))#True
print(hasattr(b,"__cc"))#False

4.getattr(object,name)

该方法用于获得某个对象的某个全局变量的属性值,私有变量不能获取

print(getattr(b,"bb")) #100

5.setattr(object,name,valse)

该方法给某个对象的某个全局变量进行赋值,如果不存在该全局变量则会重新创建该变量

setattr(b,"ddd",120)
print(getattr(b,"ddd"))#120

6.delattr(object,name)

该方法表示从某个对象中删除某个全局变量

delattr(b,"ddd")

7.property(fget,fset,fdel,doc)

该方法将获得变量的数据,赋予变量数据,删除变量三个方法进行封装起来,形成一个封装后的变量,直接使用该变量即可,这样在后期更新代码的时候,能更好的形成高内聚,低耦合。不需要大量的改动代码

class E:
    def __int__(self, size=10):
        self.size=size

    def getSize(self):
        return self.size

    def setSize(self,value):
        self.size=value

    def delSize(self):
        del self.size
#     定义组合变量
    x=property(getSize,setSize,delSize)

e=E()
print(e.x)
e.x=100
print(e.x)
del e.x

以上是关于Python第九课 类和对象的主要内容,如果未能解决你的问题,请参考以下文章

快学Scala 第九课 (伴生对象和枚举)

python第九课 面向对象

零基础学python第九课,列表元祖字典字符串

零基础学python第九课,列表元祖字典字符串

Python学习第九课——匿名函数

进阶第九课 Python模块之datetime