当前位置:网站首页>(4) Function, Bug, Class and Object, Encapsulation, Inheritance, Polymorphism, Copy

(4) Function, Bug, Class and Object, Encapsulation, Inheritance, Polymorphism, Copy

2022-08-02 03:59:00 stealth rookie

目录

函数

函数的创建和调用

函数的参数传递

函数的返回值

函数的参数定义

变量的作用域

递归函数

Bug

Bug常见类型

常见异常类型

异常处理机制

类与对象

类和对象的创建

类属性、类方法、静态方法

动态绑定属性和方法

封装

继承

多继承

方法重写

object类

多态

动态语言与静态语言

特殊属性和特殊方法

类的浅拷贝与深拷贝

浅拷贝

深拷贝


函数

函数就是执行特定任何以完成特定功能的一段代码

优点:复用代码,隐藏实现细节,提高可维护性,提高可读性便于调试

函数的创建和调用

#例子
def addnum(a,b):   #创建
    c=a+b
    return c
result=addnum(10,20)   #调用
print(result) #30

函数的参数传递

1.位置实参:根据形参对应的位置进行实参传递

2.关键字实参:根据形参名称进行实参传递

函数的返回值

函数返回多个值时,结果为元组

1.如果函数没有返回值【函数执行完之后,不需要给调用处提供数据】return可以忽略不写

2.函数的返回值,如果是1个,直接返回类型

3.函数的返回值,如果是多个,返回的结果为元组

函数的参数定义

1.函数定义默认值参数

   函数定义时,给形参设置默认值,Arguments need to be passed only when they do not match the default values

def fun(a,b=10):
    print(a,b)
#函数调用
fun(100) #100,10 只传一个参数,b采用默认值
fun(20,30) #20,30 传两个值,30把10替换

2.个数可变的位置参数

    定义函数时,无法事先确定传递的位置实参个数,可用 * 定义个数可变的位置形参 ,结果为一  个元组

def fun(*args):
    print(args)
fun(10) #(10,)
fun(10,20,30) #(10,20,30)

3.个数可变的关键字形参

    定义函数时,无法事先确定传递的关键字实参个数,可用 ** 定义个数可变的关键字形参 ,结果为一 个字典

def fun(**args):
    print(args)
fun(a=10) #{'a':10}
fun(a=10,b=20,c=30) #{'a':10,'b':20,'c':30}

 注:A variable number of positional arguments can only be1个 (不能写成fun(*args,*a));

        A variable number of keyword arguments can only be 1个 (不能写成fun(**args,**a));

         在一个函数的定义过程中,You can have a variable number of positional arguments and a variable number of keyword arguments at the same time,But a variable number of positional parameters,To be placed before a variable number of keyword parameters.

4.函数参数总结 :

变量的作用域

程序代码能访问该变量的区域
根据变量的有效范围可分为:
        1.局部变量
        •在函数内定义并使用的变量,只在函数内部有效,局部变量使用global声明,这个变量
        就会就成全局变量
        2.全局变量
        •函数体外定义的变量,可作用于函数内外

递归函数

如果在一个函数的函数体内调用了该函数本身,这个函数就称为递归函数
(1) 递归的组成部分:
        递归调用与递归终止条件
(2) 递归的调用过程:
        1.每递归调用一次函数,都会在栈内存分配一个栈帧,
        2.每执行完一次函数,都会释放相应的空间
(3) 递归的优缺点:
        缺点:占用内存多,效率低下
        优点:思路和代码简单

Bug

Bug常见类型

常见异常类型

异常处理机制

#举例try...except...else
#如果try块中没有抛出异常,则执行else块;如果try中抛出异常,则执行except块
try:
    n1=int(input('输入一个整数:'))
    n2=int(input('输入另一个整数:'))
    result=n1/n2
except BaseException as e:
    print('error')
    print(e)
else:
    print('结果为',result)


#try...except...else...finally结构
#finally块无论是否发生异常都会被执行,能常用来释放try块中申请的资源

类与对象

 There are two kinds of thinking in programming:面向过程、面向对象

(面向过程,things are simple,Linear thinking solves;面向对象,事物复杂,Linear thinking cannot solve it;但是两者并不冲突,是相辅相成的,Object-oriented is easy to grasp the complex relationship between things from a macro perspective,Then use a process-oriented approach to specific processing)

类是多个类似事物组成的群体的统称.

(不同的数据类型属于不同类,使用内置函数type()查看)

Objects are similar distinct instances contained under a class,This instance is called an instance or object.

(例如100、33、56都是intSimilar different instances contained under the class.python中一切皆对象)

类和对象的创建

(1)类的创建

 

class Student:  #Student为类的名称(类名)由一个或多个单词组成,每个单词首字母大写,其余小写
    native_place='四川' #直接写在类里的变量,称为类属性
    def __init__(self,name,age): #__init__(self)初始化,可以添加属性;name, age为实例属性
        self.name=name  #self.name称为实例属性,进行了一个赋值,Assign the value of a local variable to an entity property
        self.age=age
#实例方法
    def info(self):
        print('我的名字叫:',self.name,'年龄是:',self.age)
#类方法
    @classmethod
    def cm(cls):
        print ('类方法')
#静态方法
    @staticmethod
    def sm():
        print('静态方法')

#在类中定义的称为方法,在类外定义的称为函数
#函数
def fun():
    print('python')

 (2)对象的创建

对象的创建又称为类的实例化,With an instance, you can call the content of the class

(一个Student类可以创建N多个Student类的实例对象,每个实例对象的属性值不同)

#创建Student类的实例对象
stu=Student('json',20)
print(stu.name) #实例属性
print(stu.age) #实例属性
stu.info() #实例方法  对象名.方法名()
Student.info(stu) #类名.方法名(类的对象)

 

类属性、类方法、静态方法

(1) 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享print(Student.native_place)

(2) 类方法:使用@classmethod修饰的方法,使用类名直接访问的方法Student.cm()

(3) 静态方法:使用@staticmethod修饰的方法,使用类名直接访问的方法Student.sm()

动态绑定属性和方法

 Python是动态语言,在创建对象之后,可以动态地绑定属性和方法

def show():
print('我是一函数,Functions defined outside the class’)

stu=Student('Jack',20)
stu.gender=’男’#动态绑定属性
print(stu.name,stu.age,stu.gender) #Jack 20 男
stu.show=show #动态绑定方法
stu. show()

封装

面向对象的三大特征:

(1)封装:提高程序的安全性
        •将数据(属性)和行为(方法)包装到类对象中.在方法内部对属性进行操作,在
         类对象的外部调用方法.这样无需关心方法内部的具体实现细节,thereby isolating the complex
         杂度.
       •在Python中There is no special modifier for private properties,If the property is not expected to be available outside the class object
        访问,前边使用两个“_”下划线.
(2)继承:提高代码的复用性
(3)多态:提高程序的可扩展性和可维护性 

#封装
class Student:
    def __init__(self,name,age):
        self.name=name
        self.__age=age #年龄不希望在类的外部被使用,所以加了两个_
    def show(self):
        print(self.name,self.__age)

stu = Student('张三',20)
stu.show()  #张三 20,调用了show()方法,show()输出了name和age,All are internally accessible to both

#在类外访问name与age
print(stu.name) #张三,可访问
# print(stu.__age) #报错,不可访问
#print(dir(stu)) 利用dir可获得stu中所有属性,其中包含了一个_Student__age属性
#print(stu._Student__age) #20,在类的外部,可以通过_Student__age进行访问

继承

1.如果一个类没有继承任何类,则默认继承object

2.python支持多继承

3.定义子类时,必须在子类构造函数中调用父类的构造函数

#继承
class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def info (self):
        print('姓名:{0},年龄:{1}'.format(self.name,self.age))
#定义子类
class Student(Person):
    def __init__(self,name,age,score):
        super().__init__(name, age)
        self.score=score
#测试
stu=Student('Jack',20,'1001')
stu.info()

#结果   姓名:Jack,年龄:20

多继承

方法重写

1.If the subclass is not satisfied with inheriting a property or method of the superclass,可以在子类中对其(方法体)进行重新编写

2.子类重写后的方法中,可以使用super().xxx()调用父类中被重写的方法

#方法重写
class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def info (self):
        print('姓名:{0},年龄:{1}'.format(self.name,self.age))
#定义子类
class Student(Person):
    def __init__(self,name,age,score):
        super().__init__(name, age)
        self.score=score
    def info (self):
        super().info()  #This is to call a method of the parent class(Do not use this statement,就不会输出name和age)
        print('学号:{0}'.format(self.score)) #这里直接输出了Person类的score
#测试
stu=Student('Jack',20,'1001') #传递实参
stu.info() #调用了Person类里的info()

object类

 1.object类是所有类的父类,因此所有类都有object类的属性和方法

2.内置函数dir()可以查看指定对象所有属性

3.object有个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数str()经常用于print()  方法,帮助我们查看对象的信息,All we often have__str__()进行重写

class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def info(self):
        print('姓名:{0},年龄:{1}'.format(self.name,self.age))
#重写__str__()
    def __str__ (self): 
        return '姓名:{0},年龄:{1}'.format(self.name,self.age)

p=Person('Jack',20)
print(dir(p)) #查看对象p中的所有属性
print(p) #默认调用__str__()这样的方法


多态

多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法. 

class Animal(object):
    def eat(self):
        print('动物要吃东西')
class Dog (Animal):
    def eat(self):
        print('狗吃肉')
class Cat(Animal):
    def eat(self):
       print('猫吃鱼')
class Person(object):
    def eat(self):
        print('人吃五谷杂粮')
def fun(animal):
    animal.eat ()
fun(Dog())
fun(Cat())
fun(Person())

#Dog、Cat继承于Animal,而Person继承于object,Write a function outside the classfun(),调用fun()not only output“狗吃肉;猫吃鱼”,还输出了“人吃五谷杂粮”,There is no inheritance relationship between these two categories,But still output“人吃五谷杂粮”.因为,传入一个对象,As long as that object contains eat()这个方法,它都会被调用

动态语言与静态语言

 静态语言和动态语言关于多态的区别:
1. 静态语言实现多态的三个必要条件:继承、方法重写、父类引用指向子类对象.
2. 动态语言的多态崇尚“鸭子类型”当看到一只鸟走起来像鸭子、游泳起来像鸭子、It also looks like a duck    子,那么这只鸟就可以被称为鸭子.在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为(方法的功能).

特殊属性和特殊方法

#特殊属性
class A:
    pass
class B:
    pass
class C(A,B):
    def __init__(self,name,age):
        self.name=name
        self.age=age
class D(A):
    pass
#创建C类对象
x=C('Jack',20) #x是C类型的一个实例对象
print(x.__dict__) #实例对象的字典属性
print(C.__dict__)
print('------------------------')
print(x.__class__) #输出对象所属的类,属于<class '__main__.C'>
print(C.__bases__) #C类的父类类型元素,加sJust output all parent classes,不加sjust output one
print(C.__mro__) #类的层次结构
print(A.__subclasses__()) #子类的列表

上述代码的结果为

#特殊方法
#例如
a=10
b=20
c=10+20 #Adds two objects of type integer,实际上的情况是c=a.__add__(b),a调用了__add__()方法与b相加
------------------------------------------------------------------------------------------
class Student:
    def __init__(self,name):
        self.name=name
    def __add__(self, other): #重写__add__(),如果没有这一步,stu1不能与stu2相加
        return self.name+other.name
    def __len__(self,name):
        return len(self.name)
stu1=Student('Jack')
stu2=Student('Lisa')

s=stu1+stu2 #实现了两个对象的加法运算(因为在Student类中编写__add__()特殊方法)
print(s)
print('-----------------------------------')
lst=[1,2,3,4]
print(len(lst)) #len()是内置函数,Used to calculate the length of the list
print(lst.__len__()) #This has the same effect as the above statement
print(len(stu1.name)) #Try to output an objectstu1的长度,报错,因为没有len(),If you want to get this length,可以重写__len__()

以上代码运行结果为

类的浅拷贝与深拷贝

变量的赋值操作:只是形成两个变量,实际上还是指向同一个对象

class CPU:
    pass
class Disk:
    pass
class Computer:
    def __init__(self,cpu,disk):
        self.cpu=cpu
        self.disk=disk

#(1)变量的赋值
cpu1=CPU()
cpu2=cpu1
print(cpu1,id(cpu1))
print(cpu2,id(cpu2))

#运行结果为
<__main__.CPU object at 0x00000165C193C1C0> 1536551010752
<__main__.CPU object at 0x00000165C193C1C0> 1536551010752
#两者id相同,They point to the same instance object

 

浅拷贝

python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝

(源对象与拷贝对象会引用同一个子对象 )

#(2)类有浅拷贝
disk=Disk() #创建一个硬盘类的对象
computer=Computer(cpu1,disk) #创建一个计算机类的对象
print(disk)

#浅拷贝
import copy
computer2=copy.copy(computer)
print(computer,computer.cpu,computer.disk)
print(computer2,computer2.cpu,computer2.disk)


输出的结果为 (The first two arecpu1和cpu2的id)

深拷贝

使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象

(源对象和拷贝对象所有的子对象也不相同 )

#深拷贝
import copy
computer3=copy.deepcopy(computer)
print(computer,computer.cpu,computer.disk)
print(computer3,computer3.cpu,computer3.disk)

输出结果为

 

 

 

 

原网站

版权声明
本文为[stealth rookie]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/214/202208020322317504.html