python——补充类

1.类

1.封装

- 封装是指隐藏类的实现细节,让使用者不用关心这些细节;

- 封装的目的是让使用者通过尽可能少的方法(或属性)操作对象

- Python的封装是假的(模拟的)封装

- 私有属性和方法

  - python类中以双下划线(`__`)开头,不以双下划线结尾的标识符为私有成员,私有成员只能使用方法来进行访问和修改
    - yi属性,在子类和类外部无法直接使用
    - 以`__`开头的方法为私有方法,在子类和类外部无法直接调用

class A:
    def __init__(self):
        self.__p1 = 100  # 私有属性
    def __m1(self):  # 私有方法
        print("__m1(self) 方法被调用")
    def showA(self):
        self.__m1()
        print("self.__p1 = ", self.__p1)
class B(A):
    def __init__(self):
        super().__init__()
    def showB(self):
        self.__m1()  # 出错,不允许调用
        print("self.__p1 = ", self.__p1)  # 出错,不允许调用
        # self._A__m1()  # 正常调用
        # print("self.__p1 =", self._A__p1)  # 正常访问

a = A()
a.showA()
a.__m1()       # 出错,不允许调用
v = self.__p1  # 出错,不允许调用
b = B()
b.showB()

# 访问私有属性
print(a._A__p1)  # 输出: 100
# 调用私有方法
a._A__m1()  # 输出: __m1(self) 方法被调用
# 不推荐了解就行

 2.多态

  • 什么是多态:

    • 字面意思"多种状态"

    • 多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态

  • 状态:

    • 静态(编译时状态)

    • 动态(运行时状态)

  • 多态说明:

    • 多态调用的方法与对象相关,不与类型相关

    • Python的全部对象都只有"运行时状态(动态)", 没有"C++语言"里的"编译时状态(静态)"

示例

class Shape:
    def draw(self):
        print("Shape的draw()被调用")

class Point(Shape):
    def draw(self):
        print("正在画一个点!")

class Circle(Point):
    def draw(self):
        print("正在画一个圆!")

def my_draw(s):
    s.draw()  # 此处显示出多态

shapes1 = Circle()
shapes2 = Point()
my_draw(shapes1)  # 调用Circle 类中的draw
my_draw(shapes2)  # Point 类中的draw

 3.魔术方法

Python中的魔术方法(Magic Methods)是一种特殊的方法,它们以双下划线开头和结尾,例如__init____str____add__等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。

  1. __init__(self, ...): 初始化对象,通常用于设置对象的属性。

  2. __str__(self): 定义对象的字符串表示形式,可通过str(object)print(object)调用。例如,您可以返回一个字符串,描述对象的属性。

  3. __repr__(self): 定义对象的“官方”字符串表示形式,通常用于调试。可通过repr(object)调用。

  4. __len__(self): 定义对象的长度,可通过len(object)调用。通常在自定义容器类中使用。

  5. __getitem__(self, key): 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,object[key]

  6. __setitem__(self, key, value): 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,object[key] = value

  7. __delitem__(self, key): 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,del object[key]

  8. __iter__(self): 定义迭代器,使对象可迭代,可用于for循环。

  9. __next__(self): 定义迭代器的下一个元素,通常与__iter__一起使用。

  10. __add__(self, other): 定义对象相加的行为,使对象可以使用+运算符相加。例如,object1 + object2

  11. __sub__(self, other): 定义对象相减的行为,使对象可以使用-运算符相减。

  12. __eq__(self, other): 定义对象相等性的行为,使对象可以使用==运算符比较。

  13. __lt__(self, other): 定义对象小于其他对象的行为,使对象可以使用<运算符比较。

  14. __gt__(self, other): 定义对象大于其他对象的行为,使对象可以使用>运算符比较。

  15. __call__(self, other) 是一个特殊的方法(也称为“魔法方法”),它允许一个对象像函数一样被调用。

参考代码

1.__init__(self, ...): 初始化对象

class MyClass:
    def __init__(self, value):
     self.value = value
​
obj = MyClass(42)

2.__str__(self): 字符串表示形式

class MyClass:
   def __init__(self, value):
      self.value = value
​
   def __str__(self):
      return f"MyClass instance with value: {self.value}"
​
​
obj = MyClass(42)
print(obj)  # 输出:MyClass instance with value: 42

3.__repr__(self): 官方字符串表示形式

class MyClass:
   def __init__(self, value):
      self.value = value
​
   def __repr__(self):
      return f"MyClass({self.value})"
    
   #def __repr__(self):
      #return f"Person(name={self.name}, age={self.age})"
​
​
obj = MyClass(42)
print(obj)  # 输出:MyClass(42)

4.__len__(self): 定义对象的长度

class MyList:
   def __init__(self, items):
      self.items = items
​
   def __len__(self):
      return len(self.items)
​
​
my_list = MyList([1, 2, 3, 4])
print(len(my_list))  # 输出:4

5.__getitem__(self, key): 索引操作

class MyDict:
   def __init__(self):
      self.data = {}
​
   def __getitem__(self, key):
      return self.data.get(key)
​
​
my_dict = MyDict()
my_dict.data = {'key1': 'value1', 'key2': 'value2'}
print(my_dict['key1'])  # 输出:value1

6.__setitem__(self, key, value): 赋值操作

class MyDict:
   def __init__(self):
      self.data = {}
​
   def __setitem__(self, key, value):
      self.data[key] = value
​
​
my_dict = MyDict()
my_dict['key1'] = 'value1'
print(my_dict.data)  # 输出:{'key1': 'value1'}

7.__delitem__(self, key): 删除操作

class MyDict:
   def __init__(self):
      self.data = {}
​
   def __delitem__(self, key):
      del self.data[key]
​
​
my_dict = MyDict()
my_dict.data = {'key1': 'value1', 'key2': 'value2'}
del my_dict['key2']
print(my_dict.data)  # 输出:{'key1': 'value1'}

8.__iter__(self): 迭代器

class MyIterable:
   def __init__(self):
      self.data = [1, 2, 3, 4]

   def __iter__(self):
      self.index = 0
      return self

   def __next__(self):
      if self.index >= len(self.data):
         raise StopIteration
      value = self.data[self.index]
      self.index += 1
      return value


my_iterable = MyIterable()
for item in my_iterable:
   print(item)
# 输出:1, 2, 3, 4

9.__call__(self, *args, **kwargs)
class MyCallable:
    def __call__(self, *args, **kwargs):
        print("Called with arguments:", args, kwargs)

# 创建类的实例
my_callable = MyCallable()

# 像调用函数一样调用实例
my_callable(1, 2, 3, key="value")

4.方法重写

如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法

在自定义类内添加相应的方法,让自定义类创建的实例像内建对象一样进行内建函数操作

class Shape:
    def draw(self):
        print("Shape的draw()被调用")

class Point(Shape):
    def draw(self):
        print("正在画一个点!")

class Circle(Point):
    def draw(self):
        print("正在画一个圆!")

def my_draw(s):
    s.draw()  # 此处显示出多态

shapes1 = Circle()
shapes2 = Point()
my_draw(shapes1)  # 调用Circle 类中的draw
my_draw(shapes2)  # Point 类中的draw

魔术方法重写:

class My_class:
    def __init__(self,x,y,item):
        self.x = x
        self.y = y
        self.item = item
    # 修改+ 运算符
    def __add__(self, other):
        return self.x + other.x, self.y + other.y
    # 修改实例对象的输出方式

    def __len__(self):
        return len(self.item)
data = [1,2,3]
d01 = My_class(1,2,data),
d02 = My_class(1,2,data),
print(len(d01))

5.super函数

super() 函数是用于调用父类(超类)的一个方法。

super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

super() 方法的语法:

1.super().[父类已被覆盖方法]

在子类方法中可以使用super().add()调用父类中已被覆盖的方法

可以使用super(Child, obj).myMethod()用子类对象调用父类已被覆盖的方法

class A:
    def process(self):
        print("A process")
class B(A):

    def process(self):
        print("B process")
        super().process() # 调用super()方法

class C(A):
    def process(self):
        print("C process")
        super().process() # 调用super()方法
class D(B,C):
    def process(self):
        print("D process")
        super().process() # 调用super()方法
d = D()
d.process()

2.super().init()

super().__init__() 是 Python 中用于调用父类(基类)构造函数的一种方式。它通常用于子类的构造函数中,以确保父类的构造函数被正确调用和初始化。这在继承(inheritance)中尤为重要,因为父类的初始化代码可能包含设置实例变量或执行其他重要的初始化任务。

class Parent:
    def __init__(self,name):
        self.name = name
class Child(Parent):
    def __init__(self,name,age):
        super().__init__(name)
        self.age = age
        print(name,age)
child = Child("小名",19)

2.迭代器和生成器

1.迭代器

  • 迭代器是访问可迭代对象的工具

  • 迭代器是指用 iter(obj) 函数返回的对象(实例)

  • 迭代器可以用next(it)函数获取可迭代对象的数据

迭代器函数iter和next

函数说明
iter(iterable)从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象
next(iterator)从迭代器iterator中获取下一个记录,如果无法获取一下条记录,则触发 StopIteration 异常

迭代器说明

  • 迭代器只能往前取值,不会后退

  • 用iter函数可以返回一个可迭代对象的迭代器

迭代器的用途

  • 迭代器对象能用next函数获取下一个元素

# 可迭代对象
L = list(range(10))
it = iter(L)
print(it)
print(type(it))
while 1:
    try:
        print(next(it))
    except:
        print("迭代结束!")
        break

 2.生成器

生成器是在程序运行时生成数据,与容器不同,它通常不会在内存中保留大量的数据,而是现用现生成。

  • yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。

  • 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

  • 每次使用 yield 语句生产一个值后,函数都将暂停执行,等待被重新唤醒。

  • yield 语句相比于 return 语句,差别就在于 yield 语句返回的是可迭代对象,而 return 返回的为不可迭代对象。

  • 然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。

生成器可以用算法动态的生成数据

生成器有两种

  1. 生成器函数

  2. 生成器表达式

生成器函数

含有yield 语句的函数是生成器函数,此函数调用回返回一个生成器对象,生成器也是可迭代对象

yield 语句的语法

yield 表达式
# 定义一个生成器对象生成器和迭代器一样可以配套for 循环使用
def myrange(stop):
    i = 0
    while i<stop:
        yield i
        i += 1
for x in myrange(10):
    print(x)
t=myrange(10)
print(next(t))
print(next(t))
print(next(t))

3.函数式编程

1.函数作为变量

定义:用一系列函数解决问题。

  • 函数可以赋值给变量,赋值后变量绑定函数。

  • 允许将函数作为参数传入另一个函数。

  • 允许函数返回一个函数。

语法:变量存储的是函数内存地址

函数式编程思想:

  • 封装-分 把不同的点分出来

  • 继承-隔 把相同的点融合在一起

  • 多态-做 实现不同的任务

def my_fun():
    print(11111)
# print(my_fun)

def fun01(f):
    print(22222)
    print(f)
    f()
fun01(my_fun)

 2.lambda函数与高阶函数

1、lambda函数

作用:

-- 作为参数传递时语法简洁,优雅,代码可读性强。

-- 随时创建和销毁,减少程序耦合度

说明:

-- 形参没有可以不填-- 方法体只能有一条语句,且不支持赋值语句。

变量=lambda 形参: 方法体    调用:变量(实参)

2、高阶函数

定义:将函数作为参数或返回值的函数。

常用:

(1)map(函数,可迭代对象)

  • 使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。

(2)filter(函数,可迭代对象)

  • 根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。

(3)sorted(可迭代对象, key=函数, reverse=True)

  • 排序,返回值为排序后的列表结果。reverse = True返回降序,reverse = False或者默认为升序

(4)max(可迭代对象, key = 函数)

  • 根据函数获取可迭代对象的最大值。

(5)min(可迭代对象,key = 函数)

  • 根据函数获取可迭代对象的最小值。

class Belle:
    list1 = []
    def __init__(self, name, score, age, height):
        self.name = name
        self.score = score
        self.age = age
        self.height = height
        Belle.list1.append(self)
    def __str__(self):
        return f"{self.name},{self.score},{self.age},{self.height}"
belle01 = Belle("阿珂",100,23,166)
belle02 = Belle("苏荃",92,32,162)
belle03 = Belle("双儿",90,25,164)
belle04 = Belle("小郡主",76,22,170)
belle05 = Belle("方怡",75,27,169)
belle06 = Belle("建宁",86,25,173)
belle07 = Belle("曾柔",67,24,176)

print(belle06)
print("----所有美女的姓名为:------------------------------------")
# 1、打印所有对象的名称,返回的是表达式
for i in map(lambda a:a.name,Belle.list1):
    print(i)

# 2、获取颜值大于80的美女对象,返回的是满足条件的对象
print("----颜值大于80的美女有:------------------------------------")
for i in filter(lambda a:a.score>80,Belle.list1):
    print(i)
# 3、获取年龄最大的对象,返回的是实例化对象
print("----年龄最大的美女是:------------------------------------")
print(max(Belle.list1,key = lambda a:a.age))

# 4、对年龄进行排序,返回的是实例化对象列表
print("----对所有美女的身高进行降序排列:------------------------------------")
# True 降序排列 False 升序排列
height_sort = sorted(Belle.list1,key=lambda a:a.height,reverse=True)
for i in height_sort:
    print(i)

 4.函数作为返回值

1.闭包closure

什么是闭包?

  • 闭包是指引用了此函数外部嵌套函数的变量的函数 闭包就是能够读取其他函数内部变量的函数。只有函数内部的嵌套函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数,同时这个函数又引用了外部的变量“。

  • 在本质上,闭包是将内部嵌套函数和函数外部的执行环境绑定在一起的对象。

闭包必须满足以下三个条件:

  • 必须有一个内嵌函数

  • 内嵌函数必须引用外部函数中变量

  • 外部函数返回值必须是内嵌函数。

思考全局变量和局部变量的区别

  • 全局变量

    • 一直存在,谁都可以访问和修改

  • 局部变量

    • 只是在调用时存在,只能在函数内部进行访问和修改

闭包的优缺点 优点

1. 逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑而单独编写额外逻辑。
2. 方便调用上下文的局部变量。
3. 加强封装性,是第2点的延伸,可以达到对变量的保护作用。

使用闭包的注意点(缺点)

1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
def give_money(money):
    print(f"当前有{money}")
    def child_buy(target,price):
        nonlocal money
        money -= price
        print(f"购买{target},花了{price},还剩{money}")
    return child_buy
tool = give_money(100)
tool("玩具",30)
tool("玩具",30)

2. 装饰器

什么是装饰器

  • 装饰器是一个函数,主要作用是来用包装另一个函数或类

装饰器的作用:

  • 在不修改被装饰的函数的源代码,不改变被装饰的函数的调用方式的情况下添加或改变原函数的功能。

函数装饰器的语法:

def 装饰器函数名(fn):
    语句块
    return 函数对象

@装饰器函数名 <换行>
def 被装饰函数名(形参列表):
    语句块

对比闭包和装饰器:

闭包:

def fun01():
    print("fun01执行了")
    return "你好"

def fun02(func):
    print("fun02执行了")

def print_func_name(func):
    # wrapper约定熟成的写法
    def wrapper(*args,**kwargs):
        # 旧功能
        # __name__获取函数名 内置属性
        print(func.__name__)
        # 新功能
        return func(*args,**kwargs)
    return wrapper
re = print_func_name(fun01)
re()

 装饰器:

def print_func_name(func):
    # wrapper约定熟成的写法
    def wrapper(*args,**kwargs):

        # __name__获取函数名 内置属性
        # 新功能
        print(func.__name__)
        # 旧功能
        return func()
    return wrapper
# 被装饰器函数
@print_func_name
def fun01():
    print("fun01执行了")
    return "你好"
@print_func_name
def fun02():

    print("fun02执行了")

fun02()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值