(八)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)

结果如右

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

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

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

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函数,得到正确的结果。

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

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

8.HR管理

题目:

1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山顶夕景

小哥哥给我买个零食可好

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值