Python基础(五)面向对象

一、类(class)

1.1 类的简介

  • 目前所有学习的对象都是Python内置的对象。
  • 对象是类的实例(instance)。
  • 我们自定义类都需要使用大写字母开头,使用大驼峰命名法来对类命名。
  • 使用 isinstance()函数来检查对象是否是某个类的实例。
class MyClass():
    pass


mc = MyClass()
print(isinstance(mc, MyClass))

1.2 对象的创建流程

  • 类也是一个对象,是用来创建对象的对象。
  • 类是type类型的对象,定义类实际上就是定义了一个type类型的对象。
  • 创建对象的流程:
    • 创建一个变量mc。
    • 在内存中创建一个新对象。
    • 将对象的id赋值给变量mc。

1.3 类的定义

  • 类和对象都是对现实生活中的内容中的抽象。
  • 实际上所有是事物都由两部分构成:
    • 数据(属性)
    • 行为(方法)
  • 定义语法

class 类名([ 父类 ]):

        公共的属性...

        # 初始化方法

        def __init__(self,....):

                ...

        # 其他方法

        def method(self,...):

                ...

  • 在类的代码块中,我们可以定义变量和函数
    • 变量会称为该类实例的公共属性,所有该类实例都可以通过 对象.属性 的形式访问;
    • 函数会称为该类实例的公共方法,所有该类实例都可以通过 对象.方法名 的形式调用。
  • 注意:
    • 方法调用时,第一个参数由解析器自动传递,所有定义方法时至少要定义一个形参self。

1.4 属性和方法

  • 实例为什么能访问到类中的属性和方法:
    • 类中定义的属性和方法都是公共的,任何实例都可以访问。
  • 属性和方法查找的流程
    • 当调用一个对象的属性时,解析器会先在当前对象中寻找是否由该属性:
      • 如果有,直接返回当前对象的属性。
      • 如果没有,则区当前对象的类中寻找:
        • 如果有,返回类对象的属性值,
        • 如果没有,报错。
  • 类对象和实例对象中都可以保存属性(方法)
    • 如果这个属性(方法)是所有实例共享的,则应该将其保存到类对象中
    • 如果这个属性(方法)是某个实例独有,则应该保存早实例对象中
class Person():
    name = ""

    def say_hello(self):
        print("你好我是 %s" % self.name)


p1 = Person()
p2 = Person()
p1.name = "Tom"
p2.name = "Jerry"
p1.say_hello()
p2.say_hello()

# 输出结果
# 你好我是 Tom
# 你好我是 Jerry
  • self 表示调用方法的实例对象本身。(*类似于Java中的this*)

1.5 类的特殊方法__init__

  • 在类中可以定义一些特殊方法(魔术方法)。
  • 特殊方法都是以__(双下划线)开头,__(双下划线)结尾的方法。
  • 特殊方法不需要自己手动调用,会在特殊的时刻自动调用。
  • 比如__init__(self ,...) 在对象创建后自动调用,去初始化属性。(*类似于Java中的构造器*
class Person():

    #  构造方法
    def __init__(self, name):
        print("调用__init__方法")
        self.name = name

    def say_hello(self):
        print("你好我是 %s" % self.name)


p1 = Person("Tom")


  • p1=Person() 创建对象的流程
    • 创建变量p1
    • 在内存中创建一个Person类的新对象
    • __init__(self) 方法执行
    • 将对象id赋值给变量p1

1.6 练习

# 自定义一个表示狗的类
# 属性:name、age、gender、height
# 方法:eat()、run()

class Dog():

    def __init__(self, name: str, age: int, gender: str, height: int):
        self.name = name
        self.age = age
        self.gender = gender
        self.height = height

    def run(self):
        print(self.name, "running")

    def eat(self):
        print(self.name, "eating")


d1 = Dog("旺财", 2, "boy", 8)
d1.run()
d1.eat()

二、封装

2.1 简介

  • 面向对象的三大特性之一,确保对象数据的安全性。
  • 让内部的数据无法直接被外部访问或修改,增加数据的安全性。

2.2 隐藏类中的属性

  • 可以为对象的属性使用双下划线开头,__属性名
  • 双下划线开头的属性是对象的隐藏属性,隐藏属性只能在类内部访问没无法通过对象。
  • 其实隐藏属性只不过是Python自动为属性改了一个名字
    • 实际上是将名字修改为了 _类名__属性名
class Dog():

    def __init__(self, name: str):
        self.__name = name

    def set_name(self, name: str):
        self.__name = name

    def get_name(self):
        return self.__name


d1 = Dog("旺财")
print(d1.get_name())
d1._Dog__name = "小白"
print(d1.get_name())

# 输出结果
# 旺财
# 小白
  • 所以__开头的属性,实际上在外部依然可以访问 。防君子不防小人。
  • 一般情况下我们会将一些私有属性(不被外部访问的属性)以_开头。

2.3 property装饰器

  • getter方法装饰器:@property,把get方法,转换成对象的属性。
    • 使用property装饰的方法名,跟属性名必须一样。
  • setter方法装饰器:@属性名.setter
  • @property必须写在@属性名.setter 之前,否则会报错。
class Dog():

    def __init__(self, name: str):
        self._name = name

    # property装饰器,用来将一个get方法,转换成对象的属性
    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name


d1 = Dog("旺财")
print(d1.name)
d1.name = "小白"
print(d1.name)

# 输出结果
# 旺财
# 小白

三、继承

3.1 简介

  • 面向对象的三大特性之一,保证对象的可扩展性。
  • 通过继承可以获取到其他类中的属性和方法。
  • 在定义类时,可以在类名后括号里指定当前类的父类(超类、基类、super)
    • 子类(衍生类)可以直接继承父类中的所有属性和方法。
  • 通过继承可以让子类避免重复编写跟父类相同的代码。
  • 若省略父类,则默认继承父类object。object是所有类的父类。
    • issubclass() 检查一个类是否是另一个类的子类。
class Animal():
    def run(self):
        print("动物跑")

    def sleep(self):
        print("动物睡觉")


class Dog(Animal):
    def bark(self):
        print("汪汪汪")


class Husky(Dog):
    def komatik(self):
        print("哈士奇拉雪橇")


h1 = Husky()
h1.run()
h1.sleep()
h1.bark()
h1.komatik()

3.2 方法重写(override)

  • 子类中存在与父类同名的方法,通过子类实例调方法时,调用的是子类的方法。
  • 当调用对象方法时:
    • 去对象中寻找该方法:
      • 存在,直接调用。
      • 不存在,去父类中寻找:
        • 存在,调用父类的方法。
        • 不存在,去父类的父类中寻找。直到找到object,还没有则报错。
class A():
    def test(self):
        print("AAA")


class B(A):
    def test(self):
        print("BBB")


class C(B):
    def test(self):
        print("CCC")


c = C()
c.test()

# 输出结果
# CCC

3.3 super

  • 有时候希望可以在子类中直接调用父类的方法。
  • super() 可以用来获取当前类的父类,并且通过super()返回对象调用父类方法时,不需要传输self。
class Animal():

    def __init__(self, name):
        self._name = name

    def run(self):
        print("动物跑")

    def sleep(self):
        print("动物睡觉")

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name


class Dog(Animal):

    def __init__(self, name, age):
        super().__init__(name)
        self._age = age

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def bark(self):
        print("汪汪汪")

    def run(self):
        print("动物跑")


d = Dog("旺财", 5)
print(d.name, d.age)

3.4 多重继承

  • Python是支持多重继承的,即一个类同时指定多个父类
    • 可以在类名()里添加多个类,实现多重继承。
    • 多重继承的子类会获取所有父类中的方法。
  • 实际开发中没有特殊情况,应该尽量避免多重继承
  • 类名.__bases__  此属性可以用来获取当前类的所有父类。
  • 如果多个父类中有同名的方法,则会按父类的顺序查找,前面的父类方法覆盖后面的。
class A(object):
    def test(self):
        print("AAA")


class B(object):
    def test(self):
        print("BBB")


class C(B, A):
    def test2(self):
        print("CCC")


print(C.__bases__)
c = C()
c.test()

# 输出结果
# (<class '__main__.B'>, <class '__main__.A'>)
# BBB

四、多态

  • 多态是面向对象的三大特性之一,保证了程序的灵活性。
  • 一个对象可以从不同的形态去呈现。
  • 例子:len()
    • 之所以一个对象能通过len()获取长度,是因为对象中具有特殊方法__len__
    • 只要对象中具有__len__特殊方法,就可以通过len()获取长度。
class B():

    def __init__(self, name):
        self._name = name

    def __len__(self):
        return 10

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

b = B("Jerry")
print(len(b))

4.1 属性和方法

属性

  • 类属性
    • 定义:直接在类中定义。(类似于Java的static属性
    • 访问:可以通过类、实例访问。
    • 修改:只可以通过类修改,实例对象无法修改。
  • 实例属性
    • 定义:在实例初始化时定义。
    • 访问修改:只能通过实例对象访问修改,类无法访问修改。

方法

  • 类方法
    • 定义:在类内部,使用@classmethod 修饰,第一个参数是cls(类似于Java的static方法
    • 调用:类和实例调用时,均自动传递cls。
  • 实例方法
    • 定义:在类中定义,第一个参数为self的方法
    • 调用:
      • 类调用时,不会自动传递self,必须手动传递。
      • 实例调用时,自动将实例对象作为self传入。
  • 静态方法
    • 定义:使用@staticmethod 修饰,不指定任何默认参数
    • 调用:可以被类和实例调用
    • 基本上是一个和当前类无关的方法,只是保存在类中的函数。
# 定义类
class A(object):
    count = 0

    # 类属性:直接在类中定义
    #   可以通过类或者类的实例访问到
    #   只能通过类对象来修改,无法通过实例对象修改

    def __init__(self):
        self.name = '孙悟空'
        # 实例属性:通过实例对象添加的属性
        #   只能通过实例对象来访问和修改,类对象无法访问修改

    def test(self):
        # 实例方法:在类中定义,第一个参数是self的方法都是实例方法
        #   当通过实例调用时,会将调用对象作为self传入
        #   当通过类调用时,不会自动传递self,此时必须手动传递self
        print("这是test=,实例方法")

    # 类方法:类内部使用@classmethod修饰方法
    @classmethod
    def test_2(cls):
        print("这是test2,类方法")

    # 静态方法:使用@staticmethod修饰的方法
    # 不需要指定参数,类和实例都可以去调用
    # 基本上是一个和当前类无关的方法,只是一个保存到当前类中的函数。
    @staticmethod
    def test_3():
        print("这是test_3,静态方法")


a = A()
#属性
print("A,", A.count)
print("a,", a.count)
# print("A,",A.name) # 报错,无法访问
print("a,", a.name)
#实例方法
a.test()
# A.test() # 报错,不会自动传self
A.test(a)  # 等价于 a.test()
#类方法
A.test_2()
a.test_2()
#静态方法
A.test_3()
a.test_3()

输出结果:

A, 0
a, 0
a, 孙悟空
这是test=,实例方法
这是test=,实例方法
这是test2,类方法
这是test2,类方法
这是test_3,静态方法
这是test_3,静态方法

五、垃圾回收

  • 在Python中有自动的垃圾回收机制,会自动将没有被引用的对象删除。
  • __del__(self) 在对象被回收之前自动调用。
class A():

    def __init__(self):
        self.name = 'A类'

    # 在对象被回收之前自动调用
    def __del__(self):
        print("A() 对象被删除了~", self)


a = A()
print(a.name)
a = None

# 输出结果
# A类
# A() 对象被删除了~ <__main__.A object at 0x0000029462A15A30>

六、特殊方法

  • 特殊方法,也被称为魔术方法,都是使用双下划线开头和结尾的。
  • 一般不需要手动调用,在特殊情况下自动执行。

__str__()方法

  • 调用:在对象使用print()函数打印时自动调用。(类似于Java中的toString()方法
  • 作用:将对象内容转化成字符串。
  • 返回:字符串。
class Person():
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def __str__(self):
        return "Person[name=%s ,age=%d]" % (self._name, self._age)

p1 = Person("Tom", 25)
p2 = Person("Jerry", 23)
print(p1)
print(p2)

输出结果

Person[name=Tom ,age=25]
Person[name=Jerry ,age=23]

__repr__()方法 

  • 调用:在对象使用repr()函数时自动调用。
  • 作用:指定对象在 ‘交互模式’ 中直接输出的结果。
  • 返回:字符串。

比较大小的特殊方法

  • object.__lt__(self,other)   小于
  • object.__le__(self,other)  小于等于
  • object.__eq__(self,other)  等于
  • object.__ne__(self,other)  不等于
  • object.__gt__(self,other)   大于
  • object.__ge__(self,other)  大于等于

以小于为例

  • 调用:在对象做小于比较时调用。
  • 作用:指定比较大小的数据。
  • 返回:布尔值
class Person():
    def __init__(self, name, age):
        self._name = name
        self._age = age


    def __lt__(self, other):
        return self._age < other._age


p1 = Person("Tom", 25)
p2 = Person("Jerry", 23)
print(p1 < p2) # False
print(p2 < p1) # True

 __bool__(self)

  • 调用:当对象转换成bool类型时被调用。
  • 作用:指定对象转换成bool类型时的布尔值。
  • 返回:布尔值

七、模块、包

7.1 简介

  • 将程序分解成一个个小的模块,写到多个文件中。
  • 特点:
    • 方便开发
    • 方便维护
    • 模块可以复用

7.2 模块的创建

模块的创建

  • 在python中一个py文件就是一个模块。
  • 注意:模块名要符合标识符规范。

模块的引用

  • 方式:
    • import 模块名 (py文件名)
    • import 模块名 as 模块别名
  • 在每个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
  • __name__属性为 __main__的模块就是主模块,程序的入口。

7.3 模块的使用

  • 在模块中可以定义变量、函数、类
  • 访问模块中的内容:模块名.变量、模块名.函数、模块名.类
  • 引入模块的部分内容:from 模块名 import 变量、函数 
    • 此方式引入的,调用时不需要带上模块名。

模块代码:

# 在模块中定义变量
a = 10
b = 20

# 在模块中定义函数
def test():
    print("test")

def test2():
    print("test2")

# 在模块中定义类
class Person():
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def __str__(self):
        return "Person[name=%s ,age=%d]" % (self._name, self._age)

    def __lt__(self, other):
        return self._age < other._age

调用代码:

from m import a, b, test, test2, Person

print(a)
print(b)
test()
test2()
p1 = Person("Tom", 25)
print(p1)
  • 当有部分代码只在当前文件作为主模块的时候才需要执行的情况时,而当模块被其他模块引入时,不需要执行的,此时我们就必须检查当前模块是否主模块
if __name__ == '__main__':
    p = Person("Jerry", 18)
    print(p)

7.4 包

  • 包是一个文件夹,包含了多个模块。
  • 包中必须要有一个__init__.py 这个文件,这个文件可以包含有包中的主要内容。
  • __pycache__ 是模块的缓存文件:
    • py代码在执行前,需要被解析器转换成机器码,然后再执行,
    • 为例提高运行性能,python在编译一次过后,将代码保存到一个缓存文件中,
    • 这样下次再加载这个模块(包)时,就不用再重复编译,而是直接加载缓存中编译好的代码即可。

7.5 Python标准库

  • 开箱即用。
  • 为了实现开箱即用的思想,Python提供了一个模块的标准库,
  • 在标准库中,有很多强大的模块可以直接使用,并且标准库会随Python安装一起安装。

sys模块

  • sys.argv :属性,当前命令所有参数的列表。
  • sys.modules:属性,当前程序引入的所有模块,形式是字典,key是模块名,value是模块对象。
  • sys.path:属性,模块的搜索路径的列表。
  • sys.platform :属性,当前python运行的平台:linux、win32、cygwin、darwin。
  • sys.exit():函数,退出程序。

pprint模块

  • pprint.pprint():可以用来对打印的数据简单的格式化。

os模块 对操作系统进行访问

  • os.environ:属性,获取到系统的环境变量
  • os.system():方法,可以用来执行操作系统的名字,相当于cmd。
os.system("notepad") # 打开记事本

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值