(八)python中的面向对象编程

简介: 把有形和无形的事物抽象成“对象”,如书本 乐器,自然语言 时间等。编程解决现实中问题,第一步就是将现实世界中的对象和类如实反映到程序中。将抽象后的数据和函数封装在一起,就构成了类。一个类被定义好后,它就可以被实例化为一个具体的对象---就像一些Python自带的库函数一样。

1.面向对象编程与Python

   把有形和无形的事物抽象成“对象”,如书本 乐器,自然语言 时间等。


编程解决现实中问题,第一步就是将现实世界中的对象和类如实反映到程序中。将抽象后的数据和函数封装在一起,就构成了类。一个类被定义好后,它就可以被实例化为一个具体的对象---就像一些Python自带的库函数一样。


  Python是一门纯粹的面向对象的语言。在python中,一切皆对象。数字、字符串、元组、列表、字典、函数、方法、类、模块等都是对象。


2.Python中的类

   类是对一组具有相同属性与方法的对象的抽象。一个类有一些列的属性和方法,在python中,可以把属性看做类内定义的一个或几个变量(比如列表中的元素),而方法则相当于类内定义的一系列函数(如列表的append函数)。

ls=[]   # 定义一个空列表
ls.append(2)
print(ls)   # 输出 [2]

我们可以自己定义类

class Journalist:
    """
    Take this as an example
    """
    def __init__(self,name):
        self.name=name
    def get_name(self):
        return self.name
    def speed(self,speed):
        d={}
        d[self.name]=speed
        return d

上面代码:第一行class Journalist 类似之前用 def 声明函数一样,是在声明一个类,其关键词为class。通常,类的名称要用大写字母开头-----如果是两个单词组合的话,最好每个单词都用大写字母开头,便于提高代码可读性,如HongKongJournalist。


类里面的代码,定义的就是这个类的 方法 ,方法的定义方式和一半的函数几乎相同。


   区别:所有的函数都包括一个参数 self。注意:类的所有方法,其参数列表都必须包括self,并且默认作为第一个参数。这里可以理解为C++中的this指针。



def _init_(self,name)这个方法比较特殊----命名方式很特比,开头和结尾都是双下划线,这就是这个类的构造函数,又叫初始化函数。初始化:让一个类的实例对象在生成的时候有一个基本的状态。在Python的类中,要用类构件一个实例对象,就必须调用初始化函数。


    在初始化函数中,self.name=name的含义就是要建立实例的一个属性。这个属性的名字是name,C++定义的类中可以声明成员变量-----而我们已经知道python中的变量是不用声明的,因此在python中我们使用这样直接赋值的方式来建立实例的属性。


   def get_name(self) 和 del color(self,color)是类的另外两个方法---除了第一个函数参数必须是self之外,它们的定义昂视根一般的函数完全一样,像self.name这样的调用方法,只能在类中使用。


3.建立类的实例对象

class Journalist:
    """
    Take this as an example
    """
    def __init__(self, name):
        self.name = name
    def get_name(self):
        return self.name
    def speed(self, speed):
        d = {}
        d[self.name] = speed
        return d
if __name__ == "__main__":
    western=Journalist('Wallace')
    print(western.name)
    name=western.get_name()
    print(name)
    his_speed=western.speed(100)
    print(his_speed)

4.类的方法详细介绍

在上面例子中,初始化函数的self作为默认参数,虽然在定义方法时要显式写出来,但在调用是不需要给它传值。而name则需要传值------Journalist('Wallace')就是为初始化函数中的name参数传值。(“传值”的说法不是很严谨——python只允许传引用。)


    self作用:是我们所建立的实例对象本身。当用实例调用方法时,解释器会把实例传递给方法,因此不需要显示给self传参。


在调用方法时,可通过给方法传递参数改变实例对象的属性的值——his_speed=western.speed(100)。


通过类建立一个实例对象,再通过实例来调用它的属性和方法。


5.类的属性与数据

注意是类的属性而非实例对象的属性,类的属性又叫静态变量 或 静态数据。等价于C++这样写:

#include<string>
using std::string;
class Journalist {
public:
    static string name;
};
Journalist::name="Wallace";
class Journalist:
    """
    Take this as an example
    """
    name = 'Wallace'
    height=[]
print(Journalist.name)
Journalist.speed=100
print(Journalist.speed)
hongkong=Journalist()
print(hongkong.name)
hongkong.name="Zhangbaohua"
print(hongkong.name)
print(Journalist.name)
hongkong.height.append(160)
print(hongkong.height)
print(Journalist.height)

结果如右

image.png

当类中变量引用的是可变对象的时候,类属性和实例属性都能直接修个这个对象,从而影响另一方的值。

通过类增加的属性可以影响到实例对象。

给实例对象添加的属性无法影响到类。

6.关于方法的跟多细节

  通过要用实例对象来调用方法,对于下面这个类,用对象来调用方法。

class Elder:
    def get_name(self):
        print("Toad")
he = Elder()
print(he.get_name())  # 输出 Toad

类中的方法就是一个函数,只不过这个函数的第一个参数必须是self。这个self参数表示调用方法的实例对象。使用实例对象调用方法时,python解释器会把实例对象作为第一个参数传给该方法,实际上我们还可以显示的给方法传参:

print(Elder.get_name(he))  # 输出 Toad

还有一类方法,并不以self为第一个参数——现在考虑之前定义的Journalist类:

class Journalist:
    """
    Take this as an example
    """
    name = 'Wallace'
    def __init__(self):
        self.name = "Zhangbaohua"
    @classmethod
    def get_class_name(cls):
        return cls.name

上面新定义的方法get_class_name,它只有一个参数cls,并没有参数self,上面还有一个@classmethod标记修饰——即所谓的类方法。它有一个参数cls(这里的参数叫什么都可以),作用是返回参数的name属性。它既可以被类本身调用,也可以被实例对象调用:

hongkong = Journalist()
print(Journalist.get_class_name())  # 输出 Wallace
print(hongkong.get_class_name())  # 输出 Zhangbaohua

除了类方法,还有一种类似的方法:静态方法,参见如下代码

import random
def get_num():
    a = random.randint(1926, 10000)
    return a
class Elder:
    def __init__(self):
        self.life = get_num()
    def get_name(self):
        print("Toad")

   在类中使用了类外面的函数get_num()——类和类外函数的耦合,在编码上并不是一种很好的习惯:这种做法给程序的维护带来了潜在的麻烦。而所谓的“静态方法”,就是把get_num()这样的函数放进类中。


   使用了@staticmethod 装饰器后,现在get_num是函数的一个静态方法——它实际上相当于一个独立的函数,跟类本身并没有什么关系,即我们用一种简单粗暴的方法解决了上面的问题——用静态方法,把函数“包装”进了类。


7.面向对象编程的其他概念

抽象:数据抽象(某类对象的特性和状态)和行为抽象(某类对象的功能或行为特性)。


封装:即类(class),其中的属性和方法都是类的成员。


假设我们用C++语言来定义一个clock类,如下:

class Clock {
public:
    Clock();  // C++ 中的初始化函数,相当于 Python 中的 __init__
    void setTime(int newH,int newM,int newS);//在 C++ 和 JAVA 等语言中,函数定义需要写明参数的类型和返回值类型,这一点跟 Python 不一样
    void showTime();
private:
    int hour,minute,second;
};

public和private关键字,这个定义的效果:外界的程序不能直接访问三个成员变量,只能通过2个函数来间接查看或者修改三个变量的值。这样就可以实现对成员访问权限的合理控制,让不同类之间的相互影响(耦合)减少到最低限度,进而增强数据的安全性,并简化程序编写工作。


  举例:对于Clock类,如果不做封装的话外界的程序直接对3个变量进行访问,假设有人要把表示时间的变量的值设置成一个根本不可能出现的值(如设置成999小时999分钟),这就可能让程序出错。而进行封装之后,外界想要重新设置时间就必须通过setTime()函数——这样我们就可以在函数中增加检查输入合法性的代码,避免不合法数据的恶意输入。


   python也支持数据的封装,也就是“私有化”,并且写法比C++简单。同样是上面的Clock类,用python写如下:

class Clock:
    def __init__(self):
        self.__hour = 0
        self.__minute = 0
        self.__second = 0
    def showTime(self):
        print(self.__hour, self.__minute, self.__second)

我们只要在一个想要私有化的属性前面加上双下划线_就可以将其私有化,等同于C++中的private关键字。这样一来,当我们想要在外界直接访问私有属性,就会报错:

C:\DATA\GitHub\jisuankeWork\gitlab\python_programming\python3\new_add\oop_in_py (new_add)
λ python test.py
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    print(c.__hour)
AttributeError: 'Clock' object has no attribute '__hour'

私有属性只能通过类内的方法来访问,即“封装”。不光是私有属性,还可以定义私有方法,定义的方法跟私有属性相同:

class Clock:
    def __init__(self):
        self.__hour=0
        self.__minute=0
        self.__second=0
    def showTime(self):
        print(self.__hour,self.__minute,self.__second)
    def __getSecond(self): # 私有方法
        return self.__second

继承与多态


继承:新建一个继承了原有类的新类,具有原有类的新类,具有原有类的所有特征的同时,又具有自身的新特性。通过类的这种的这种层次结果,可以很好地反应出特殊概念与一般概念的对应关系。


父类/基类:被其他类继承的类


子类/派生类:继承自一个父类的类


在python中,继承可以通过这样的写法实现:

class P:
    pass
class C(P):
    pass

类c是继承自类p的一个子类——如果父类定义了一些属性和方法,则子类就会拥有父类定义的所有内容。

    事实上,我们自己定义的任何一个类,都是继承自python中内置的基类object。如上面的类P,我们可以在交互式命令行下,用内置方法_base_查看它的基类:

>>> class P:
...     pass
...
>>> P.__base__
<class 'object'>
>>>

多态:广义上指同一段程序,可以直接处理多种类型对象的能力。如打乒乓球、打篮球中的“打”,就是对多种运动行为的抽象。

  在C++中类似python不用声明一个变量类型的写法:

auto i=1; //注意必须在定义变量时初始化,形如auto i;的写法不允许!

从类型系统的角度看,C++和JAVA术语静态类型语言,而Python是一种动态类型语言,变量的类型是在解释器运行的时候通过类型推导所确定的(需要注意的是解释器实际上仍然会对代码进行编译)。


如,我们可以这样定义一个函数:

def print_length(item):
    print(len(item))

然后我们就可以把任何一种用len求长度的对象传给print_length函数,得到正确的结果。

1. print_length("123")  # 输出 3
2. print_length([1,2])  # 输出 2

如果是C++之类的语言,在定义函数时需要用到函数重载或者模板机制,对于Python来说显然方便多。

8.HR管理

题目:

image.png

1
相关文章
|
1月前
|
Java 程序员 C++
Python 面向对象详解!
本文详细介绍了Python中的面向对象编程(OOP),包括类、对象、继承、封装、多态和抽象等核心概念。通过具体示例,解释了如何使用类定义对象的属性和方法,以及如何通过继承实现代码重用。文章还探讨了封装和多态的重要性,并介绍了私有属性和抽象类的使用方法。最后,总结了OOP的四大支柱:封装、抽象、继承和多态,强调了这些概念在Python编程中的应用。适合Java程序员扩展Python编程知识。
71 2
|
1月前
|
Python
Python面向对象(2)
【10月更文挑战第14天】
Python面向对象(2)
|
3月前
|
Python
你真的会面向对象吗!解密Python“魔术方法”
你真的会面向对象吗!解密Python“魔术方法”
40 0
|
1月前
|
设计模式 程序员 C语言
Python面向对象
【10月更文挑战第13天】
Python面向对象
|
1月前
|
Java C# Python
Python学习七:面向对象编程(中)
这篇文章是关于Python面向对象编程的中级教程,涵盖了析构函数、对象的三大特征(封装、继承、多态)、类属性与实例属性、以及类方法与静态方法的对比。
23 2
|
1月前
|
设计模式 安全 JavaScript
Python学习八:面向对象编程(下):异常、私有等
这篇文章详细介绍了Python面向对象编程中的私有属性、私有方法、异常处理及动态添加属性和方法等关键概念。
24 1
|
2月前
|
前端开发 Python
Python编程的面向对象有哪些(二)
Python编程的面向对象(二)—类的多态
|
2月前
|
IDE Java 开发工具
Python类与面向对象
Python类与面向对象
|
2月前
|
存储 Java 程序员
30天拿下Python之面向对象编程
30天拿下Python之面向对象编程
18 3
|
2月前
|
Java Python
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
【9月更文挑战第18天】在 Python 中,虽无明确的 `interface` 关键字,但可通过约定实现类似功能。接口主要规定了需实现的方法,不提供具体实现。抽象基类(ABC)则通过 `@abstractmethod` 装饰器定义抽象方法,子类必须实现这些方法。使用抽象基类可使继承结构更清晰、规范,并确保子类遵循指定的方法实现。然而,其使用应根据实际需求决定,避免过度设计导致代码复杂。