【python基础】4.函数和面向对象

发布时间 2024-01-04 11:19:48作者: asdio

函数

参数

形式参数和实际参数

形式参数:定义函数时的参数,是用来接收参数用的,在函数内部作为变量使用

实际参数:调用函数时的参数,是用来把数据传递到函数内部用的

形式参数变量和对象引用的传递

形式参数变量:接收实际参数的变量

对象引用的传递:把实际参数的引用传递给形式参数变量

在python中,所有的参数都是以对象的引用传递的

  • 不可变对象:数字、字符串、元组;如果在函数内部修改了参数的值,那么就会在函数内部创建一个新的对象,而不会影响到外部的对象

  • 可变对象:列表、字典;如果在函数内部修改了参数的值,那么就会在函数内部修改原来的对象,而不会创建一个新的对象

可选参数

可选参数:在调用函数时,可以不传递的参数

def func(a, b, c=10):
    print(a, b, c)

位置参数和命名参数

位置参数:按照位置顺序传递的参数
命名参数:按照参数名传递的参数

def func(a, b, c=10):
    print(a, b, c)

func(1, 2, 3) # 1 2 3
func(1, 2) # 1 2 10
func(1, 2, c=3) # 1 2 3
func(1, c=3, b=2) # 1 2 3

可变参数

可变参数:可以接收任意多个参数

  • *param:接收任意多个位置参数,会把这些参数当作一个元组传递给形式参数变量
  • **param:接收任意多个命名参数,会把这些参数当作一个字典传递给形式参数变量
def func(*args):
    print(args)

func(1, 2, 3) # (1, 2, 3)
func(1, 2, 3, 4) # (1, 2, 3, 4)

def func(a, b, **args):
    print(a, b, args)

func(1, 2, c=3, d=4) # 1 2 {'c': 3, 'd': 4}

强制命名参数

强制命名参数:必须使用命名参数传递的参数
在形式参数列表中,*后面的参数都是强制命名参数

def func(*, a, b):
    print(a, b)

func(1, 2) # TypeError: func() takes 0 positional arguments but 2 were given

func(a=1, b=2) # 1 2

函数

Lambda表达式

lambda arguments: expression:创建一个匿名函数,格式为lambda 参数列表: 返回值

func = lambda x: x ** 2
print(func(2)) # 4

函数装饰器Decorator

函数装饰器:用于在不修改原函数的情况下,为原函数添加新的功能

def decorator(func):
    def wrapper():
        print('before')
        func()
        print('after')
    return wrapper

@decorator
def func():
    print('func')

func() # before func after

面向对象

类和对象

类:用来描述具有相同属性和方法的对象的集合
对象:类的实例


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

    def say(self):
        print('My name is {}, I am {} years old.'.format(self.name, self.age))

p = Person('Tom', 18)
p.say() # My name is Tom, I am 18 years old.

属性

属性:类中定义的变量

  • 实例属性:通过实例对象添加的属性,只能通过实例对象访问
  • 类属性:通过类对象添加的属性,可以通过类对象和实例对象访问
class Person:
    name = 'Tom' # 类属性

    def __init__(self, age):
        self.age = age # 实例属性

  • 私有属性:以两个下划线开头的属性,只能在类内部访问
  • 共有属性:可以在类内部和外部访问
class Person:
    __name = 'Tom' # 私有属性

    def __init__(self, age):
        self.age = age # 共有属性

  • @property装饰器:将一个方法变成属性调用
class Person:
    def __init__(self, age):
        self.age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age < 0:
            age = 0
        self.__age = age

p = Person(18)
print(p.age) # 18
p.age = -1
print(p.age) # 0

方法

方法:类中定义的函数

  • 静态方法:使用@staticmethod装饰器修饰的方法,可以通过类对象和实例对象调用,静态方法中不需要传递类对象或实例对象
class Person:
    @staticmethod
    def func():
        print('func')

Person.func() # func
  • 类方法:使用@classmethod装饰器修饰的方法,可以通过类对象和实例对象调用,类方法中需要传递类对象

class Person:
    @classmethod
    def func(cls):
        print(cls)

Person.func() # <class '__main__.Person'>
  • 构造方法:使用__init__方法创建对象时会自动调用的方法,用来初始化对象
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
  • 析构方法:使用__del__方法销毁对象时会自动调用的方法,用来释放对象占用的资源
class Person:
    def __del__(self):
        print('del')    
  • __call__方法:使得对象可以像函数一样调用
class Person:
    def __call__(self):
        print('call')

p = Person()
p() # call

对象的复制

  • 引用:两个变量指向同一个对象,通过一个变量修改对象,另一个变量也会受到影响
  • 浅复制:复制对象,但是对象中的引用还是指向同一个对象
  • 深复制:复制对象,对象中的引用也会复制
import copy

class Person:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

p1 = Person('Tom', 18,{ 'English': 100, 'Math': 100 })
p2 = p1 # 引用
p3 = copy.copy(p1) # 浅复制
p4 = copy.deepcopy(p1) # 深复制

p1.name = 'Jack'
print(p2.name) # Jack
print(p3.name) # Tom
print(p4.name) # Tom

p1.score['English'] = 90
print(p2.score['English']) # 90
print(p3.score['English']) # 90
print(p4.score['English']) # 100

继承

继承:子类继承父类的属性和方法
派生类:子类,python支持多继承

声明类时,必须在其构造方法的参数列表中调用父类的构造方法,否则会报错

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

    def say(self):
        print('My name is {}, I am {} years old.'.format(self.name, self.age))

class Student(Person):
    def __init__(self, name, age, score):
        super().__init__(name, age)
        self.score = score

    def say(self):
        super().say()
        print('My score is {}.'.format(self.score))

s = Student('Tom', 18, 100)
s.say() # My name is Tom, I am 18 years old. My score is 100.

重载

重载:在同一个类中,方法名相同,参数列表不同的方法

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

    def say(self):
        print('My name is {}, I am {} years old.'.format(self.name, self.age))

    def say(self, score):
        print('My name is {}, I am {} years old, my score is {}.'.format(self.name, self.age, score))

p = Person('Tom', 18)
p.say(100) # My name is Tom, I am 18 years old, my score is 100.

运算符重载

运算符重载:对内置的运算符进行重载,使其可以作用于自定义的对象上

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

    def __add__(self, other):
        return self.age + other.age

p1 = Person('Tom', 18)
p2 = Person('Jack', 20)

ages =  p1+p2
print(ages) #38

functools.total_ordering装饰器

functools.total_ordering装饰器:可以通过重写__eq____lt__方法,自动重写其他比较方法

需要重写__eq____lt____gt____le____ge__中的一个或多个

from functools import total_ordering

@total_ordering
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.age == other.age

    def __lt__(self, other):
        return self.age < other.age

p1 = Person('Tom', 18)
p2 = Person('Jack', 20)

print(p1 == p2) # False
print(p1 < p2) # True