公司动态
python - 面向对象
一、前言在入门篇中主要是围绕python的基础语法来讲解的在这一篇里会主要讲解一些更深层次的内容比如我们实际编程中常用的函数、类有关于传参的一些知识点。二、知识点2.1函数函数是我们在实际编程中经常用到的一个知识点你可以理解它是一段固定的代码专门用来执行某种任务用。且可以根据你的入参返回不同的内容给你。函数以def开头下面用一段代码告诉你函数长什么样子举个例子你需要一个计算两数之和的代码那么可以写成以下这样def add(num1,num2): return num1 num2上面这段代码的意思是定义一个名字为add的函数它接收num1和num2两个参数在接收到参数后将num1和num2相加然后返回。关于函数有几个点是比较重要的参数、返回、调用2.1.1参数对于函数来说并不是一定要规定入参或者说在没有特殊情况的前提下函数能接收的入参是与括号中的形参数量相等的且如果传参时声明了参数名那么这个参数名必须在括号中能找到否则就会报错以代码为例以下的代码中分别有三个函数。其中func1是没有规定入参的那么它便不接受任何参数如果传参给他会报错。而func2它声明了一个叫var的入参那么它便只能接收一个参数且传参时如果带了参数名参数名必须为var。在func3中则有点不一样它跟func2的区别在于它已经给了var参数一个默认值了这种时候var参数是可传可不传的如果传参给var那么参数值会替代var的默认值。def func1(): print(我不需要入参) def func2(var): print(我需要一个名叫var的入参) def func3(vartest,var2): print(var入参已经有默认值了但是var2没有)当然除了以上的几种情况还有两种特殊的入参*args与**kwargs这两个是不定量参数也就是说他们不限制入参的数量你想传几个就传几个一般用在你并不确定需要多少入参的情况下。比如你想写一个计算输入参数之和的函数在你不知道用户一共会输入多少个参数的情况下就可以使用它们。需要注意的是*args和**kwargs并不是固定写法你也可以写成*param1/**parms2还是以代码为例下面这段代码中定义了一个func函数接收params和*args两个参数。实际传参时传了1、2、3、4、5其中params会接收第一个参数1剩下的2、3、4、5都会被不定量参数args所接收并封装成元组。当然由于args是不定量参数所以不传参给它也是可以的如果没有参数args就是一个空元组def func(params,*args): print(params) print(args) #实际调用时用args *args接收到参数后会用元组的形式进行封装 func(1,2,3,4,5) #输出1和(2,3,4,5)与*args不同**kwargs接收参数时形式有所变化数据格式也不一样看下图代码。下面的这段代码中kwargs将未定义的a、b、c三个参数接收并封装成了字典而定义了参数名的param或没有指定参数名的1则不进行处理。与args一样kwargs也可以不传参这样它就是一个空字典def func(params,**kwargs): print(params) print(kwargs) #实际调用时用kwargs **kwargs接收到参数后会用字典的形式进行封装在给kwargs传参时必须带参数名 func(1,2,3) #这样会报错因为没带参数名参数传不到kwargs上参数会溢出 func(1,a1,b2,c3) #输出1和{a:1,b:2,c:3} func(params1,a1,b2,c3) #输出1和{a:1,b:2,c:3}函数也可以作为入参示例def func(obj,num1,num2): print(obj(num1,num2)) def add(num1,num2): return num1 num2 func(add,3,4) #输出结果是7还有一个要注意的地方就是参数的先后顺序优先级为赋值参数 未赋值参数 *args **kwargs特殊参数可以参考下面这段代码def func(paramstest,params2,*args,**kwargs)2.1.2调用一般调用函数比较简单用函数名加上括号就行可以参考2.1.1传参处的代码。但是有一种嵌套函数的写法需要注意一下。下面这段代码中test_func1传参10调用func1函数并获得了func2函数的实例化对象。test_func2调用test_func1(实际上等于调用了func2)并传参5。最终结果为10515。这种写法也被称作闭包。def func1(num1): def func2(num2): return num1 num2 return func2 test_func1 func1(10) test_func2 test_func1(5) print(test_func2) # 最终输出值为151052.1.3返回值函数的返回值是函数执行完毕后将结果传递回调用者的机制。返回值允许函数输出计算结果或处理结果使得这些结果可以在函数外部使用。对于函数来说返回值不是必填的没有返回值函数一样能够正常运行只是不会返回任何值给对象。返回值的关键字为return当看到return后函数就会结束运行并返回。如下图代码def func(): print(我是return前的会输出) return print(我是return后的不会输出)有几种特殊的返回值要注意一下如果函数没有返回值最后赋值给对象时会赋值None而如果返回值什么都不填也会赋值None因此下面代码fun1、func2、func3三种写法最后的返回值其实是一样的。而返回值可以有多个当有多个返回值是会将他们打包成一个元组返回def func1(): print(我没有返回值) def func2(): print(我的返回值什么都不填为None) return def func3(): print(我的返回值是一个None) return None def fun4(): print(我有多个返回值) return 1,2,3 下面这三个都会输出None print(func1()) print(func2()) print(func3()) func4会输出(1,2,3) print(func4())2.1.4作用函数最大的特点是高复用性一般用于封装多次使用的代码。且在封装的时候会通过入参来控制代码达到不同的效果。也体现了它灵活的特点。这样做有几个好处1、减少重复代码封装好函数后只需要一行代码调用函数就可以达到跟原本多行代码一样的效果2、方便维护当函数功能有改动的时候不用去找所有跟这个函数相关的代码只需要改动函数本身就可以了2.2类类是面向对象编程中的一个很重要的概念可以把类想象成一个模板它规定了所有的汽车应该有什么功能长什么样子有哪些颜色/品牌所有的汽车厂商生产时都必须依据模板上的规定进行。类通过关键字class定义2.2.1类的三大特性类有三大特性封装、继承、多态封装封装是面向对象编程的一个核心概念它指的是将数据属性和操作数据的方法行为捆绑在一起并隐藏对象的内部实现细节只暴露必要的接口给外界使用提高数据的安全性虽然我一般也不考虑这种写法讲到封装需要提一个概念私有属性。在python中私有属性是通过在属性名前加双下划线来定义的。可以看下面的这段代码。当我们在外部直接访问私有属性时代码会直接报错。因为私有属性是只能在类内部访问的而访问color这个公共属性时是没有问题的class Car: def __init__(self,brand,color): self.__brand brand #私有属性 self.color color #公共属性 def get_brand(self): return self.__brand #只能这样访问私有属性 benchi Car(brand奔驰,colorblack) print(benchi.color) #输出black print(benchi.get_brand())#输出奔驰 print(benchi.__brand) #会报错提示找不到属性这里还要讲几个装饰器property讲函数设置为一个只读属性也就是让函数可以被以访问属性的方式调用property.setterset方法用来在修改指定属性时执行一些额外的逻辑property.getterset方法用来在修改指定属性时执行一些额外的逻辑看下面的这段代码先是实例化了一个对象radius设置为5。在类的内部把diameter设置为了一个只读的属性。第一次print的时候输出了10和5这是因为访问my_circle.diameter属性实际上相当于调用了my_circle.diameter()函数所以返回了radius*2输出了10而radius本身就等于5输出了5。而接下来的my_circle.diameter 20看似是对diameter属性赋值但是我们知道diameter本质上是个函数不是一个属性只是我们人为设置了它是一个属性。因此这句话其实相当于my_circle.diameter.setter(20)赋值的20会被当作参数传入。因此my_circle的radius属性就就被setter函数内部的self.radius diameter / 2改变从5变成了10。那么第二次输出的也就是20和10了。getter属性也是同样的道理就不再讲了。class Circle: def __init__(self, radius): self.radius radius property def diameter(self): return self.radius * 2 diameter.setter def diameter(self, diameter): self.radius diameter / 2 # 创建对象 my_circle Circle(5) # 使用属性修改器修改属性 print(my_circle.diameter,my_circle.radius) #输出10和5 my_circle.diameter 20 #调用了diameter的setter函数相当于my_circle.diameter.setter(20) print(my_circle.diameter,my_circle.radius) #输出20和10继承继承是指子类可以在不改变父类的前提下调用父类的函数和属性。一般用于要使用父类的某些属性/函数且需要在不影响父类的情况下做出一些修改继承有几个特性1、支持多继承子类可以继承多个父类但是在遇到多个父类有同样的属性名或函数名的时候可能导致方法冲突和混乱。个人不是很推荐这种写法2、方法重写当子类中有跟父类一样名称的函数时父类的函数将被覆盖但是不会影响原有的父类只在这个对象中生效当然并不是说遇到了一样的名称的函数就无法使用父类的同名函数了可以通过super()函数来处理。super()函数可以调用父类的函数如下图代码class Parent: def greet(self): print(Hello from Parent) class Child(Parent): def greet(self): print(Hello from Child) super().greet() # 调用父类的 greet 方法 child Child() child.greet() 输出结果 Hello from Child Hello from Parent 多态说到多态要先解释一下类和对象的关系对象是类的实例化概念也可以说是根据类创建出来的具体事务。打个比方现在有一个汽车类那么奥迪、宝马、奔驰各自都可以算是一个对象它们都是根据汽车类实例化而来。那么多态的概念可以这样理解类可以在大框架不变的前提下实例化出多种不同特性的对象。比如说奥迪、宝马、奔驰虽然在品牌、颜色、外形、价格等方面有区别属性不同但是它们都拥有汽车的基础功能刹车、加速、喇叭等封装好的函数。2.2.2魔法函数魔法函数有很多但是其实很多我也不怎么用最常见最好用的是__init__。__init__函数的作用是初始化如果你声明了这个函数在实例化对象时它就会被默认调用。具体可以参考上面的代码三、结尾到这里关于python的基础知识就基本讲完了掌握了这些知识后可以试着针对自己项目开发一些脚本来巩固自己学到的内容。这样能够加深自己的记忆和理解更好地掌握python这门技术。