python(三) 函数_面向对象

一、函数

当我们发现有一些代码需要重复使用,你想怎么解决?

函数:是组织好的,可重复使用的,用来实现单一,或相关联功能的代码块。 函数能提高应用的模块性,和代码的重复利用率。

如我们前面使用的print() range()函数,但你也可以自己创建函数,这被叫做用户自定义函数。

1.1 、函数的定义

函数 用关键字 def修饰,后接函数标识符名称和圆括号() 和一个: 冒号
函数内容: 要用一个tap 或四个空格缩进

如:定义一个打印函数

# 函数名 :我命名为了pr,函数内容里面只有一句打印语句

def pr():
    print("你好,这是一个函数")

# 函数定义完 不会自己执行,只有在调用的时候才会执行

# 调用函数 如下:直接写函数名()
pr()

函数名命名规范:
  由字母、数字、下画线 _ 组成,其中数字不能打头,一般小写
  不能是 Python 关键字,但可以包含关键字
  不能包含空格

1.2 、函数的参数

函数是能够重复使用 而且不单单针对一个常量,所以我们可能处理很多未知数据,那这些未知的数据 我们又无法确定 那就可以用 参数,

参数一般写在 函数的括号里面,然后在调用的时候传进行 最后在函数内容里使用
函数在定义的时候 可以有参 或 无参

有参 可以分为 :必传 ,可传

def fun(a,b=0):
    pass

我们可以看到上面这个函数 a参数是必传,也就是在调用fun这个函数的时候 必须传一个值给a,b是可传 可不传 当你不传的时候b就默认为0

从调用看 参数分为:
位置传参

def fun01(a,b,c,d=1):
    print(a)
    print(b)
    print(c)
    print(d)

fun01(1,2,3)

如上 当我们调用函数时,发现 a=1,b=2,c=3,d=1,我们传参的时候没有指定传给谁 他会按位置顺序一 一 匹配

指定传参

def fun01(a,b,c,d=1):
    print(a)
    print(b)
    print(c)
    print(d)

fun01(b=1,c=2,a=3)

如上 当我们调用这个函数时,发现打印出来 3、1、2、1 因为我们在传参的时候指定参数名等于对应的值

可变参数
*args:接收到的所有按照位置参数方式传递进来的参数,是一个元组类型
**kw:接收到的所有按照指定参数方式传递进来的参数,是一个字典类型

def fun02(*args):
    print(args[1])

fun02(2,3,4)

我们执行上面代码会打印出来一个3出来 ,相等于 传了多个参数他会把这多个参数装进一个元组传进去 如果你想取任意一个值 只需要取对应索引

def fun03(**kw):
    print(kw)

fun03(a=1,b=3)
>>> {'a': 1, 'b': 3}

**kw 我们可以看到 我们必须要传一个 一对参数进去 键值 键和值都可以自定义

1.3 、返回值:return

当我们调用一个函数并传入参数时 ,我们希望得到一个他加工回来的返回值给我们,
这个返回值 可以有 也可以没有,没有相当于返回 None,没有情况比较注重过程

def fun04(a):
    print(a)
    return 20
	
fun04(7)

我们看到fun04这个函数 有一个参数a 他的函数体里 只有两句一个是打印这个参数,一个是返回 20 ,但在控制台 我们只看到 输出了 7 ,因为你在调用函数的时候 print(a)这个代码 就是要输出一个7到控制面板,但是return 20 ,他会返回一个20给调用的结果,因为你没有输出到控制台 所以他不会显示 你可以用 print(fun04(7)) 调用这个函数 他会输出一个7和20

:函数体里面 在执行的过程一旦遇到return 就会结束这个函数 ,return 后面在写任何代码不会执行

练习:
1.定义一个函数 求两个数之间的和
2.定义一个函数,求三个数的最大值
3.定义一个函数,输入任意三个数字是否能构成三角形



二、面向对象

  面向对象思想是一种程序设计思想(Object Oriented Programming,简称OOP),这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。

举例
  洗衣服:
  面向过程:把衣服脱下来-->找一个盆-->放点洗衣粉-->加点水-->浸泡10分钟-->揉一揉-->清洗衣服-->拧干-->晾起来
  面向对象:把衣服脱下来-->打开全自动洗衣机-->扔衣服-->按钮-->晾起来
区别:
  面向过程:强调步骤。
  面向对象:强调对象,这里的对象就是洗衣机。
特点
  面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。
  面向对象的语言中,包含了三大基本特征,即封装、继承和多态。

类和对象
环顾周围,你会发现很多对象,比如桌子,椅子,同学,老师等。桌椅属于办公用品,师生都是人类。那么什么是类呢?什么是对象呢?

什么是类
类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。
现实中,描述一类事物:
  属性:就是该事物的状态信息。
  行为:就是该事物能够做什么。
举例:小猫。
  属性:名字、体重、年龄、颜色。
  行为:走、跑、叫。

什么是对象
对象:是一类事物的具体体现。对象是类的一个实例(对象并不是找个女朋友),必然具备该类事物的属性和行为。
现实中,一类事物的一个实例:一只小猫。
举例:一只小猫。
  属性:tom、5kg、2 years、yellow。
  行为:溜墙根走、蹦跶的跑、喵喵叫。

类与对象的关系
  类是对一类事物的描述,是抽象的。
  对象是一类事物的实例,是具体的。
  类是对象的模板,对象是类的实体。

类的定义
事物与类的对比
现实世界的一类事物:
  属性:事物的状态信息。
  行为:事物能够做什么。

class描述事物也是如此:
  成员变量:对应事物的属性,类的全局变量
  成员方法:对应事物的行为,类中的方法

一定要记住面向对象最为核心的3大特征:
  1.封装
  2.继承
  3.多态

2.1 类的定义格式

定义了一个类

class MyClass:

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

    def run(self):
        print("{name} is running".format(name=self.name))


a = MyClass("拜登",70)
a.run()


我们通过分析上面的代码 来学习 类的定义

class Myclass:

我们分析第一行代码,我们通过一个关键字 calss 来定义一类 ,起名为 MyClass,
类的命名:一般遵循大驼峰式,首字符大写,后面每一个单词的首字符大写

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

我们看到有一个方法叫 __init__ 这是一个初始化方法,又叫类的 构造方法,当你对类进行实例化的时候,用来初始化实例的属性,name 和 age都是实例的属性
什么是实例 就是你创建出的对象, 就是你现在能看到的self 代表类的实例,类方法必须包含此参数,且为第一个参数

    def run(self):
        print("{name} is running".format(name=self.name))

我们又看到一个方法 run 这个是这个类的一个普通方法,实例化对象后能够做的行为,并不是所有的类都有的

a = MyClass("拜登",70)
a.run()

类实例化 是什么那 就是 a = MyClass("拜登",70) 这行代码,我们对类进行了实例化,创建了一个对象a,在实例化的过程中,我们给a对象赋予了两个属性就是 name = "拜登"和age=70,然后我们又用这个对象让他调了run这个方法

self
我们可以看到类里面每一个方法都有一个self参数,它并不是默认参数,这个参数在方法被调用时是不需要传参的,这与之前所学过函数内容相违背, self就是执行方法的对象

我们用一个id方法查看内存地址 ,来研究一下

class MyClass:

    def __init__(self, name, age):
        print("这是在__init__方法中",id(self))
        self.name = name
        self.age = age

    def run(self):
        print("{name} is running".format(name=self.name))


a = MyClass("拜登",70)
a.run()
print(id(a))

执行后的结果

这是在__init__方法中 2133936776024
拜登 is running
2133936776024

我们可以看到self 的地址和 a的地址一模一样 ,那我们可以证明 self 就是a, 类对函数被定义后 任何属于这个类的对象 都是可以使用 这个函数的,所以 谁来调用这个函数,谁就会被绑定self

对象属性的访问和修改
只能通过对象来进行

class MyClass:

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

    def run(self):
        print("{name} is running".format(name=self.name))


a = MyClass("拜登",70)
a.run()

print(a.age)
a.age = 20
print(a.age)

最后在段代码 我们 输出了对象的age属性,然后又更改为了20 在输出了

练习面向对象: 请编程 把下面student表数据保存 输出每一个人的各个科目和分数,并计算每个学生的总的分数。

姓名 英语 数学 语文
曹操 75 61 95
刘备 62 43 62
貂蝉 86 23 62

2.2 封装

我们创建一个类,有些属性,有些方法,我们不希望被其他人使用,因为那样很容易就产生错误,那么这时,我们就需隐藏实现的细节,只对外公开我们想让他们使用的属性和方法,这就叫做封装。就好比把一些东西用一个盒子封装起来,只留一个口,内部让你看不见。

在python里,如果属性和方法前面是双下划线,那么这个属性和方法就变成了私有的属性

class Dog:

    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def __run(self):
        print("run")


a = Dog("哈士奇",15)

a.__run()
print(a.__name,a.__age)

我们看到 属性 __name , __age 和方法 __run() 以双下划线开头,这样的方法和属性,类的对象是无法使用的,通过这种方法,就可以将不希望外部访问的属性和方法隐藏起来。
属性隐藏起来,并非不让外部使用,而是在使用时收到控制,比如年龄,如果年龄属性定义成age,那么就会出现这样的情况

a.age = 1000

你见过哪个动物的年龄有10000岁呢,这显然是有问题的,但age属性暴露出来了,别人在使用时就可能会犯这样的错误,所以,为了防止这样的错误发生,就可以将age属性设置成私有的,然后提供一个set_age方法,来设置给age 并且判断一下

class Dog:

    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def set_age(self, age):
        if age > 100 or age < 1:
            raise Exception("年龄范围错误")
        self.__age = age

    def get_age(self):
        return self.__age

    def __run(self):
        print("run")

a = Dog("哈士奇",15)

a.set_age(5)
print(a.get_age())

2.3 继承

一个类可以继承一个或者继承多个父类,新建的类被称之为派生类或者子类,被继承的类是父类,可以称之为基类,超类,继承是实现代码重用的重要方式。

单继承

class Car(object):
    def __init__(self, speed, brand):
        self.speed = speed
        self.brand = brand

    def run(self):
        print("{brand}在行驶".format(brand=self.brand))

# 燃油车
class Gasolinecar(Car):
    def __init__(self, speed, brand, price):
        super().__init__(speed, brand)
        self.price = price


class Audi(Gasolinecar):
    pass


honda = Gasolinecar(130, '本田', 13000)
honda.run()

audi_car = Audi(100, '奥迪', 10000)
audi_car.run()

print(issubclass(Audi, Gasolinecar))        # 判断Audi是Gasolinecar的子类
print(issubclass(Gasolinecar, Car))

  继承,意味着子类将“拥有”父类的方法和属性,同时可以新增子类的属性和方法。在Gasolinecar类里,我没有写run方法,但是Gasolinecar的父类定义了run方法,因此,Gasolinecar也有这个方法,因此这个类的对象honda可以使用run方法。
  Audi类没有定义任何方法,但是它继承了Gasolinecar,因此,Gasolinecar有的属性和方法,它都拥有,这里就包括了__init__方法。
  super()可以用来调用父类的方法,Gasolinecar多传了一个price属性,其父类的__init__方法里有两个参数,因此,可以先调用父类的__init__方法初始化speed, brand,然后在初始化price

多继承
  大部分面向对象的编程语言(除了C++)都只支持单继承,而不支持多继承,因为多继承不仅增加编程复杂度,而且容易导致莫名其妙的错误。
  Python虽然支持多继承,但不推荐使用多继承,推荐使用单继承,这样可以保证编程思路更清晰,也可以避免不必要的麻烦。
  当以一个子类有多个直接父类时,该子类会继承得到所有父类的方法,但是如果其中有多个父类包含同名方法会发生什么?此时排在前面的父类中的方法会“遮蔽”后面父类中的方法。

class Person():
    def person_walk(self):
        print("走路")


class Wolf():
    def wolf_run(self):
        print("奔跑")


class WolfMan(Person, Wolf):

    def __init__(self):
        pass

a = WolfMan()

a.person_walk()
a.wolf_run()

2.4 多态

  面向对象的多态依赖于继承, 因为继承,使得子类拥有了父类的方法, 子类的方法与父类方法重名时是重写, 同一类事物,有多重形态, 这就是面向对象概念里的多态,多态使得不同的子类对象调用相同的 类方法,产生不同的执行结果,可以增加代码的外部调用灵活度。

class Base():
    def print(self):
        print("base")


class A(Base):
    def print(self):
        print("A")

a = A()
a.print()

父类和子类都有print方法,那么子类A的对象a调用print方法时,调用的是谁的print方法呢?
答案是子类的print方法,如果A类没有定义print方法,那么a.print()调用的是父类的print方法,但是A类定义了print方法,这种情况称之为重写,A类重写了父类的print方法。

继承时,子类“拥有”父类的方法和属性,但这种拥有不是真实意义上的拥有

class Base():
    def print(self):
        print("base")


class A(Base):
    pass


print(id(Base.print))
print(id(A.print))

Base.print 和 A.print 的内存地址是相同的,这说明他们是同一个方法。执行A.print时,python会寻找print方法,它会先从A类的定义中寻找,没有找到,然后去A的父类里寻找print方法,如果还是找不到,就继续向上寻找。

这便是子类拥有父类属性和方法的真相

多态表现:同一类事物,有多重形态

class Animal:
    def run(self):
        raise NotImplementedError

class People(Animal):
    def run(self):
        print("人在行走")


class Pig(Animal):
    def run(self):
        print("猪在跑")


p1 = People()
p1.run()

p2 = Pig()
p2.run()

People和 Pig 都继承了Animal,都是动物,是同一类事物,他们都有run方法,但是最终的运行结果却不一样,这就是多态,同一类事物有多种形态。

原文地址:https://www.cnblogs.com/niunai/p/15066692.html