零基础人工智能第六周总结
Day1
7属性
7.1类属性
也叫类变量。在类中方法外定义的属性。
1)通过 类名.属性名 或 实例名.属性名 访问
class Person:
"""人的类"""
home = "earth" # 定义类属性
print(Person.home) # 通过类名访问类属性
p1 = Person() # 创建一个实例对象
print(p1.home) # 通过实例名访问类属性,(如果实例没有覆盖这个类属性的值)
2)通过 类名.属性名 添加与修改类属性
class Person:
"""人的类"""
Person.home = "earth" # 添加类属性
print(Person.home) # earth
Person.home = "mars" # 修改类属性
print(Person.home) # mars
若使用 实例名.属性名 则会创建或修改实例属性,因此不建议类属性和实例属性同名。
class Person:
"""人的类"""
home = "earth"
p1 = Person()
p2 = Person()
print(Person.home) # earth
print(p1.home) # earth
print(p2.home) # earth
print("通过 类名.属性名 修改 类属性")
Person.home = "mars"
print(Person.home) # mars
print(p1.home) # mars
print(p2.home) # mars
print("通过 实例名.属性名 会创建 实例属性")
p1.home = "venus"
print(Person.home) # mars
print(p1.home) # venus
print(p2.home) # mars
3)所有该类的实例共享同一个类属性
class Person:
"""人的类"""
home = "earth" # 定义类属性,所有实例共享
p1 = Person() # 创建一个实例对象
p2 = Person() # 创建另一个实例对象
print(p1.home) # earth
print(p2.home) # earth
Person.home = "mars" # 修改类属性
print(p1.home) # mars
print(p2.home) # mars
7.2实例属性
也叫实例变量。在类__init__方法中定义的属性。通过 self.属性名定义。
1)通过 实例名.属性名 访问
class Person:
"""人的类"""
def __init__(self, name, age):
self.name = name # 定义实例属性
self.age = age # 定义实例属性
p1 = Person("张三", 18) # 创建一个实例对象
print(p1.name, p1.age) # 张三 18
p2 = Person("李四", 81) # 创建一个实例对象
print(p2.name, p2.age) # 李四 81
print(Person.name) # 报错
2)通过 实例名.属性名 添加与修改实例属性
class Person:
"""人的类"""
pass
p1 = Person() # 创建一个实例对象
p1.name = "张三" # 添加实例属性
p1.age = 18 # 添加实例属性
print(p1.name, p1.age) # 张三 18
p1.age = 25 # 修改实例属性
print(p1.name, p1.age) # 张三 25
3)每个实例独有一份实例属性
class Person:
"""人的类"""
def __init__(self, name):
self.name = name # 定义实例属性
self.age = 0 # 定义实例属性
p1 = Person("张三") # 创建一个实例对象
print(p1.name, p1.age) # 张三 0
p1.age = 18 # 修改p1的age属性
print(p1.name, p1.age) # 张三 18
p2 = Person("李四") # 创建另一个实例对象
print(p2.name, p2.age) # 李四 0
8方法
Python的类中有三种方法:实例方法、静态方法、类方法。
8.1实例方法
- 实例方法在类中定义,第一个参数为self,代表实例本身。
- 实例方法只能被实例对象调用。
- 可以访问实例属性、类属性、类方法。
class Person:
"""人的类"""
home = "earth"
def __init__(self, name):
self.name = name
def instance_method(self):
print(self.name, self.home, Person.home)
p = Person("张三")
p.instance_method() # 张三 earth earth,此时p中没有home实例属性,会去查找home类属性
Person.home = "venus" # 修改类属性
p.home = "mars" # 定义实例属性
p.instance_method() # 张三 mars venus
8.2类方法
- 类方法在类中通过 @classmethod 定义,第一个参数为cls,代表类本身。
- 类方法可以被类和实例对象调用。
- 可以访问类属性。
- 在不创建实例的情况下调用,通过类名直接调用,非常方便,适合一些和类整体相关的操作。
class Person:
"""人的类"""
home = "earth" # 定义类属性
@classmethod
def class_method(cls):
print(cls.home)
Person.class_method() # 通过类调用类方法
p1 = Person() # 创建一个实例对象
p1.class_method() # 通过实例对象调用类方法
8.3静态方法
- 静态方法在类中通过 @staticmethod 定义
- 不访问实例属性或类属性,只依赖于传入的参数
- 可以通过类名或实例调用,但它不会访问类或实例的内部信息,更像是一个工具函数,只是为了方便组织代码,把它放在了类里面。
class Person:
"""人的类"""
home = "earth" # 定义类属性
@staticmethod
def static_method():
print("static method")
Person.static_method() # 通过类调用静态方法
p1 = Person() # 创建一个实例对象
p1.static_method() # 通过实例对象调用静态方法
8.4在类外定义方法
并非必须在类定义中进行方法定义,也可以将一个函数对象赋值给一个类内局部变量。
# 在类外定义的函数
def f1(self, x, y):
print(x & y)
class C:
f = f1
C().f(6, 13) # 4
8.5特殊方法
方法名中有两个前缀下划线和两个后缀下划线的方法为特殊方法,也叫魔法方法。上文提到的 __init__() 就是一个特殊方法。这些方法会在进行特定的操作时自动被调用。
几个常见的特殊方法:
1)__new__()
对象实例化时第一个调用的方法。
2)__init__()
类的初始化方法。
3)__del__()
对象的销毁器,定义了当对象被垃圾回收时的行为。使用 del xxx 时不会主动调用 __del__() ,除非此时引用计数==0。
4)__str__()
定义了对类的实例调用 str() 时的行为。
5)__repr__()
定义对类的实例调用 repr() 时的行为。 str() 和 repr() 最主要的差别在于目标用户。 repr() 的作用是产生机器可读的输出(大部分情况下,其输出可以作为有效的Python代码),而 str() 则产生人类可读的输出。
6)__getattribute__()
属性访问拦截器,定义了属性被访问前的操作。
9 动态添加属性与方法
9.1动态给对象添加属性
class Person:
def __init__(self, name=None):
self.name = name
p = Person("张三")
print(p.name) # 张三
p.age = 18
print(p.age) # 18
9.2动态给类添加属性
class Person:
def __init__(self, name=None):
self.name = name
p = Person("张三")
print(p.name) # 张三
Person.age = 0
print(p.age) # 0
9.3动态给实例添加方法
1)添加普通方法
class Person:
def __init__(self, name=None):
self.name = name
def eat():
print("吃饭")
p = Person("张三")
p.eat = eat
p.eat() # 吃饭
2)添加实例方法
给对象添加的实例方法只绑定在当前对象上,不对其他对象生效,而且需要传入 self 参数。需要使用 types.MethodType(方法名,实例对象) 来添加实例方法。
import types
class Person:
def __init__(self, name=None):
self.name = name
def eat(self):
print(f"{self.name}在吃饭")
p = Person("张三")
p.eat = types.MethodType(eat, p)
p.eat() # 张三在吃饭
9.4动态给类添加方法
给类添加的方法对它的所有对象都生效,添加类方法需要传入 cls 参数,添加静态方法则不需要。
class Person:
home = "earth"
def __init__(self, name=None):
self.name = name
# 定义类方法
@classmethod
def come_from(cls):
print(f"来自{cls.home}")
# 定义静态方法
@staticmethod
def static_function():
print("static function")
Person.come_from = come_from
Person.come_from() # 来自earth
Person.static_function = static_function
Person.static_function() # static function
9.5动态删除属性与方法
- del 对象.属性名
- delattr(对象,属性名)
9.6__slots__限制实例属性与实例方法
Python允许在定义类的时候,定义一个特殊的 __slots__ 变量,来限制该类的实例能添加的属性。使用 __slots__ 可以限制添加实例属性和实例方法,但类属性、类方法和静态方法还可以添加。__slots__仅对当前类生效,对其子类无效。
import types
class Person:
__slots__ = ("name", "age", "eat")
def __init__(self, name=None):
self.name = name
def eat(self):
print(f"{self.name}在吃饭")
def drink(self):
print(f"{self.name}在喝水")
p = Person("张三")
# 添加实例属性
p.age = 10
print(p.age) # 10
# 添加实例方法
p.eat = types.MethodType(eat, p)
p.eat() # 张三在吃饭
# 添加实例属性
p.weight = 100 # AttributeError: 'Person' object has no attribute 'weight'
# 添加实例方法
p.drink = types.MethodType(drink, p) # AttributeError: type object 'type' has no attribute 'MethodType'
Day2
‘''
class Person:
def __init__(self,name = None):
self.name=name
p1 = Person('张三')
print(p1.name)
p1.age = 0
print(p1.__dict__)
p2 = Person()
print(p2.name)
p2.name = '李四'
print(p2.name)
# 类对象的添加
Person.age = 20
print(Person.age)
print(p1.age)
print(Person.__dict__)
# 添加普通方法
class Person:
def __init__(self, name=None):
self.name = name
def eat():
print('eat')
p = Person('张三')
p.eat = eat #
p.eat()
import types
# 添加实例方法
class Person:
def __init__(self, name=None):
self.name = name
def eat(self):
print(f'{self.name} is eating ')
p = Person('张三')
p.eat = types.MethodType(eat, p)
p.eat()
# 动态的添加类方法 静态方法
class Person:
home = 'earth'
def __init__(self, name=None):
self.name = name
@classmethod
def come_from(cls):
print(f'come_from {cls.home}')
@staticmethod
def staticfunc():
print(f'staticfunc')
Person.come_from = come_from
p1 = Person()
# p1.come_from()
Person.come_from() # 推荐使用类对象来调用类方法
# del p1.name
# print(p1.name)
class Person:
__slots__ = ('name','age','eat')
p = Person()
p.name = '王五'
print(p.name)
p.age = 30
print(p.age)
# p.height = 181
def eat(self):
print(f'{self.name} is eating ')
p.eat = types.MethodType(eat, p)
p.eat()
def study(self):
print(f'{self.name} is study')
p.study = types.MethodType(study, p)
'''
from symtable import Class
'''
在装饰器的世界里,types.MethodType 扮演着一个“急救员”的角色。它主要解决一个棘手的场景:当你动态地将一个装饰后的函数(或普通函数)赋值给某个具体的实例时,如何确保它能够正确地接收 self 参数。
'''
'''
内存浪费:每个实例都有一个字典,字典本身占用空间较大(哈希表开销)。
安全隐患/维护困难:写错属性名(如 p.nme = "李四")不会报错,而是偷偷创建了一个新属性,导致 bug 难以排查。
继承中的 __slots__ 陷阱(面试常考)
子类默认继承父类的 __slots__,但子类自己的 __slots__ 会与父类合并(取并集)。
如果子类没有定义 __slots__,那么子类实例会自动获得 __dict__,失去限制效果!
如果你在 __slots__ 中包含了某个方法名(如 'speak'),那么你可以在 __init__ 中将它绑定好,但不能在运行时动态绑定一个不在列表中的新方法。
如果你期望一个类既有固定属性,又允许少数例外情况动态添加,可以将 '__dict__' 加入 __slots__(但这样会失去内存节省的优势,不推荐)。
当你在类中定义 __slots__ = ('name', 'age') 时,Python 会移除实例的 __dict__,并改用固定长度的数组(类似于 C 语言的结构体) 来存储这些属性。
super() 函数是 Python 中用于调用父类(超类)方法的内置函数。它主要用于解决多重继承中的问题,如方法解析顺序(MRO)和重复调用(钻石继承)等问题。
'''
'''
查漏补缺:
Python 中的私有属性通过双下划线(__)前缀实现,主要用于提示属性仅供类内部使用,但并不能完全阻止外部访问。
单下划线 _attr:仅是约定俗成的弱私有,表示属性是类内部使用的,但外部仍可访问
双下划线 __attr:触发名称改写机制,模拟强私有,外部访问会报错,但仍可通过 _ClassName__attr 访问
isinstance() 是 Python 内置的类型检查函数,用于判断一个对象是否是指定类或其子类的实例。相比 type(),它会考虑继承关系,因此在面向对象编程中更灵活。
values() 方法用于返回字典中所有值的视图对象,可用于遍历、查询或动态反映字典的当前状态。values() 是字典对象的内置方法,用于获取字典中所有的值,而不需要关心键。
在Python中,可以在运行时为对象添加新的属性,这种特性让代码更加灵活,常用于配置管理、插件系统、元编程等场景。
动态属性指的是具备以下能力:
在对象初始创建后为其添加新属性
动态修改现有属性
通过编程方式创建属性
setattr() 添加或修改属性 运行时属性赋值 动态属性赋值
getattr() 获取属性值 动态属性访问 安全的属性获取
hasattr() 检查属性是否存在 条件性属性检查 属性存在性检查
delattr() 删除属性 动态属性删除 属性移除
高级动态属性技术
使用 __dict__ 进行属性管理
Python 对象将属性存储在一个特殊的 __dict__ 字典中,这使得可以直接操作对象属性。
setattr() 添加/修改属性 无 无报错
getattr() 获取属性 属性值 引发 AttributeError
hasattr() 检查属性 布尔值 无错误
delattr() 移除属性 无 引发 AttributeError
类方法是定义在类中的方法,通过装饰器@classmethod来标识。它的第一个参数是cls(表示类本身),而不是实例对象。类方法可以访问类的属性,并且可以在没有实例的情况下被调用。
类方法的优点使用场景
访问类级别的属性和方法:类方法可以轻松访问和修改类级别的属性和方法。它们能够操作类本身,而不需要创建实例。这在需要对类级别数据进行操作时非常有用。
实现多个构造函数:有时候,我们需要提供多种不同方式来创建类的实例。使用类方法可以实现这样的多个构造函数,称为工厂方法(Factory Method),这提供了更多实例化对象的灵活性。
静态方法是Python中定义在类中的一种特殊方法类型,它不与类的实例绑定,也不与实例的属性直接交互,通常通过 @staticmethod 装饰器来声明。与普通方法和类方法不同,静态方法既不需要传递类对象(cls)也不需要传递实例对象(self)作为第一个参数。
1、不需要实例化: 静态方法可以直接通过类名调用,不需要创建类的实例。它们属于类而不属于实例。
2、不依赖实例属性: 静态方法不会访问或修改类的实例属性。它们与实例无关,只在类的命名空间中起作用。
3、不涉及实例属性的逻辑: 如果一个方法不需要访问或修改实例的属性,它可以作为静态方法。
4、在类中组织功能性代码: 静态方法适合于在类中组织功能性代码,这些方法与类和实例无关,但是在逻辑上与类相关。
5、代码模块化: 有助于将代码模块化,使得相关逻辑或操作聚集在一起,便于维护和管理。
6、不依赖于实例属性:静态方法不访问或修改实例属性,因此它们与实例无关。这使得它们在不涉及实例状态的情况下执行特定的功能性操作
7、代码模块化和组织:静态方法有助于将功能性代码组织到类的命名空间中,使相关逻辑集中在一起。这提高了代码的模块化程度,使代码更易于维护和管理。
8、类的命名空间:静态方法属于类的命名空间中,但不依赖于类的实例化。它们提供了一个合适的位置来定义与类相关的功能性操作。
9、擅长独立函数:静态方法可以看作类的独立函数,它们不依赖于类的实例和属性,更类似于全局函数,但是具有类的命名空间。
10、可以方便地被继承和覆盖:与普通函数一样,静态方法可以被子类继承和覆盖,这提供了灵活性,子类可以重新实现静态方法以满足自己的需求。
11、代码可读性和组织性:合理使用静态方法有助于提高代码的可读性和组织性。它们可以把逻辑相关的操作放在一起,从而更清晰地表达类的功能。
类方法通常用于操作类级别的属性或执行与类相关的操作。
类实例方法常用于操作实例特定的属性或执行与实例相关的操作。
静态方法适用于在类中组织功能性代码,它们与类和实例无关,但又属于类的逻辑范畴。
用通俗的话讲,你可以把类想象成一家公司的总部,把实例(对象)想象成分布在全国各地的分公司。
基于这个比喻,这三者的区别就非常清晰了:
实例方法(普通方法):分公司经理。手里管着自家分店的账本(self),只能动自己店的资金(实例属性)。(你写的 deposit、withdraw 就属于这一类)
类方法(@classmethod):公司总部的 CEO。他不在乎某个分店怎么样,他管的是全公司的整体数据(cls),比如总共有多少家分店。他甚至可以直接下令“开一家新分店”(工厂模式)。(你写的 create_account、get_bank_info 就属于这一类)
静态方法(@staticmethod):公司雇佣的外包顾问。他挂着公司的牌子(代码写在类里),但完全不碰公司内部的任何机密数据(既不需要 self,也不需要 cls)。他只是利用自己的专业技能,帮忙算算账、审核一下金额合不合法。(你写的 is_valid_amount、format_currency 就属于这一类)
'''
Day3
'''
面向对象的三个重要特征
封装、继承、多态
'''
'''
class Student:
def __init__ (self, name):
self.__name = name
self.age = 18
def get_name(self):
return self.__name
s= Student('张三')
# print(s.__name)
print(s._age) # 不推荐 类外部访问受保护属性-
print(s.get__name())#推荐访问私有属性的方法
print(s._Student__name)#不推荐
class Student:
def __init__(self, name):
(self.__name) = name
def __private_method(self):
print('private method')
def do_somenthing(self):
self.__private_method()
s1 = Student('李四')
s1.do_somenthing()
#s1.__private_method()#不可以直接在外界调用 需要特定的接口来调用
'''
#@property 将方法的调用方式改成属性的调用方式
#装饰的方法不要和变量重名,否则可能导致无限递归。
'''
classPerson:
@property
def name(self):
return self.name #递归调用自己
p = Person()
p.name
'''
#可以设置只读属性 将方法名设置为去掉双下划线的私有属性名,方法中返回私有属性。
#属性是静态特征,方法是动态特征 无需.方法名()
#读写属性
'''
将方法名设置为去掉双下划线的私有属性名,属性名.setter
#创建实例的时候init之前执行new开辟空间,(自动)执行,,魔法方法制动执行。。绑定在self的实例属性
#类方法等需要手动执行
#做了装饰器,重名不会冲突,不同场景下调用不同方法
#定义一个book类价格私有属性price读写模式实现这个类的定义
class Book:
def __init__(self, title, author, price):
self.title = title
self.author = author
self.__price = price
#读
@property
def price(self):
return self.__price
#写
@price.setter
def price(self, value):
self.__price = value
def __str__(self):
return f"Book('{self.title}', '{self.author}', {self.__price})"
book = Book("三体", "刘慈欣", 59.9)
print(book)
#打印book地址原因:只要自己定义了__str__(self)方法(打印实例相关信息),那么就会打印从在这个方法中return的数据__str__方法需要返回一个字符串,当做这个对象的描写
# 2. 读取价格(通过 @property)
print(book.price) # 59.9 ← 像访问属性一样
# 3. 修改价格(通过 @price.setter)
book.price = 45.0 # ✅ 正常修改
print(book.price) # 45.0
# 5. 直接访问私有属性(不推荐,但可行)
print(book._Book__price) # 45.0 ← Python 的"伪私有",改名了而已
# 6. 真正阻止访问(没有 getter 时)
# print(book.__price) # ❌ AttributeError!
'''
'''
| 魔法方法 | 触发时机 | 示例 |
| :-------------------- | :--------- | :-------------- |
| `__new__(cls, ...)` | 创建对象(构造方法) | 单例模式、元类 |
| `__init__(self, ...)` | 初始化对象 | `obj = Class()` |
| `__del__(self)` | 对象被销毁时 | 析构,清理资源 |
"""
class Demo:
def __new__(cls):
print("1. 创建对象")
return super().__new__(cls)
def __init__(self):
print("2. 初始化对象")
def __del__(self):
print("3. 对象销毁")
d = Demo() # 1. 创建对象 2. 初始化对象
del d # 3. 对象销毁
"""
| 魔法方法 | 触发时机 | 用途 |
| :--------------- | :---------------------- | :--------- |
| `__str__(self)` | `print(obj)`、`str(obj)` | 用户友好的输出 |
| `__repr__(self)` | `repr(obj)`、交互式显示 | 开发者调试、精确表示 |
"""
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
def __repr__(self):
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p) # (3, 4) ← __str__
print(repr(p)) # Point(3, 4) ← __repr__
"""
| 魔法方法 | 触发时机 | 说明 |
| :-------------------- | :-------------- | :---------- |
| `__eq__(self, other)` | `self == other` | 等于 |
| `__ne__(self, other)` | `self != other` | 不等于(通常自动推导) |
| `__lt__(self, other)` | `self < other` | 小于 |
| `__le__(self, other)` | `self <= other` | 小于等于 |
| `__gt__(self, other)` | `self > other` | 大于 |
| `__ge__(self, other)` | `self >= other` | 大于等于 |
"""
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other):
return self.score == other.score
def __lt__(self, other):
return self.score < other.score
s1 = Student("A", 85)
s2 = Student("B", 90)
print(s1 < s2) # True
print(s1 == s2) # False
"""
| 魔法方法 | 触发时机 | 说明 |
| :-------------------------- | :-------------- | :-- |
| `__add__(self, other)` | `self + other` | 加法 |
| `__sub__(self, other)` | `self - other` | 减法 |
| `__mul__(self, other)` | `self * other` | 乘法 |
| `__truediv__(self, other)` | `self / other` | 真除法 |
| `__floordiv__(self, other)` | `self // other` | 地板除 |
| `__mod__(self, other)` | `self % other` | 取模 |
| `__pow__(self, other)` | `self ** other` | 幂运算 |
| 魔法方法 | 触发时机 |
| :---------------------- | :------------- |
| `__radd__(self, other)` | `other + self` |
| `__rmul__(self, other)` | `other * self` |
| ... | ... |
"""
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __rmul__(self, scalar): # 3 * v
return self * scalar
def __str__(self):
return f"({self.x}, {self.y})"
v = Vector(1, 2)
print(v + Vector(3, 4)) # (4, 6)
print(v * 2) # (2, 4)
print(3 * v) # (3, 6) ← __rmul__
"""
| 魔法方法 | 触发时机 | 说明 |
| :------------------------------ | :----------------- | :---- |
| `__len__(self)` | `len(obj)` | 返回长度 |
| `__getitem__(self, key)` | `obj[key]` | 获取元素 |
| `__setitem__(self, key, value)` | `obj[key] = value` | 设置元素 |
| `__delitem__(self, key)` | `del obj[key]` | 删除元素 |
| `__contains__(self, item)` | `item in obj` | 成员判断 |
| `__iter__(self)` | `for x in obj` | 迭代器 |
| `__next__(self)` | `next(iterator)` | 下一个元素 |
"""
class MyList:
def __init__(self):
self.data = []
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __iter__(self):
return iter(self.data)
def append(self, value):
self.data.append(value)
ml = MyList()
ml.append(1)
ml.append(2)
ml.append(3)
print(len(ml)) # 3
print(ml[0]) # 1
ml[0] = 10
for x in ml:
print(x) # 10, 2, 3
"""
| 魔法方法 | 触发时机 | 说明 |
| :------------------------------- | :----------------- | :------- |
| `__getattr__(self, name)` | `obj.name` 找不到时 | 动态属性 |
| `__getattribute__(self, name)` | `obj.name` 每次访问 | 拦截所有属性访问 |
| `__setattr__(self, name, value)` | `obj.name = value` | 设置属性 |
| `__delattr__(self, name)` | `del obj.name` | 删除属性 |
| `__dir__(self)` | `dir(obj)` | 属性列表 |
"""
class LazyObject:
def __getattr__(self, name):
"""访问不存在的属性时调用"""
print(f"动态创建属性: {name}")
setattr(self, name, f"value_of_{name}")
return getattr(self, name)
obj = LazyObject()
print(obj.foo) # 动态创建属性: foo → value_of_foo
print(obj.foo) # value_of_foo(已存在,不再调用)
"""
| 魔法方法 | 触发时机 | 说明 |
| :-------------------- | :--------- | :------- |
| `__call__(self, ...)` | `obj(...)` | 把对象当函数调用 |
"""
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
c = Counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3
"""
| 魔法方法 | 触发时机 | 说明 |
| :------------------------------------------ | :---------- | :--- |
| `__enter__(self)` | `with` 语句进入 | 返回资源 |
| `__exit__(self, exc_type, exc_val, exc_tb)` | `with` 语句退出 | 清理资源 |
"""
class MyFile:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'r')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
print("文件已关闭")
with MyFile('test.txt') as f:
print(f.read())
# 文件已关闭
"""
| 魔法方法 | 触发时机 | 说明 |
| :------------------------------- | :---------------------- | :---- |
| `__get__(self, instance, owner)` | `instance.attr` | 获取属性值 |
| `__set__(self, instance, value)` | `instance.attr = value` | 设置属性值 |
| `__delete__(self, instance)` | `del instance.attr` | 删除属性 |
"""
class Descriptor:
def __get__(self, instance, owner):
print(f"获取 {instance} 的属性")
return instance._value
def __set__(self, instance, value):
print(f"设置 {instance} 的属性为 {value}")
instance._value = value
class MyClass:
attr = Descriptor() # ← 描述符
def __init__(self):
self._value = None
obj = MyClass()
obj.attr = 10 # 设置 <__main__.MyClass object> 的属性为 10
print(obj.attr) # 获取 <__main__.MyClass object> 的属性 → 10
"""
| 魔法方法 | 触发时机 | 说明 |
| :---------------- | :------------------- | :--------- |
| `__int__(self)` | `int(obj)` | 转整数 |
| `__float__(self)` | `float(obj)` | 转浮点数 |
| `__bool__(self)` | `bool(obj)`、`if obj` | 转布尔 |
| `__str__(self)` | `str(obj)` | 转字符串 |
| `__repr__(self)` | `repr(obj)` | 转表示字符串 |
| `__hash__(self)` | `hash(obj)` | 哈希值(用于字典键) |
"""
class Money:
def __init__(self, amount):
self.amount = amount
def __int__(self):
return int(self.amount)
def __bool__(self):
return self.amount > 0
m = Money(100.5)
print(int(m)) # 100
print(bool(m)) # True
"""
| 场景 | 魔法方法 |
| :-------- | :----------------------------------------------- |
| 创建/初始化/销毁 | `__new__`、`__init__`、`__del__` |
| 打印/显示 | `__str__`、`__repr__` |
| 比较大小 | `__eq__`、`__lt__`、`__gt__` ... |
| 加减乘除 | `__add__`、`__sub__`、`__mul__`、`__truediv__` |
| 容器操作 | `__len__`、`__getitem__`、`__setitem__`、`__iter__` |
| 属性控制 | `__getattr__`、`__setattr__`、`__getattribute__` |
| 调用对象 | `__call__` |
| with 语句 | `__enter__`、`__exit__` |
| 类型转换 | `__int__`、`__float__`、`__bool__` |
| 描述符 | `__get__`、`__set__`、`__delete__` |
'''
'''
class BankAccount:
"""银行账户类:演示三种封装级别"""
# 类属性(公开)
bank_name = "中国人民银行"
def __init__(self, owner, balance):
self.owner = owner # ← 公开属性
self._balance = balance # ← 保护属性(单下划线)
self.__password = "123456" # ← 私有属性(双下划线)
# ========== 公开方法 ==========
def deposit(self, amount):
"""存款"""
if amount > 0:
self._balance += amount
print(f"存入 ¥{amount},当前余额:¥{self._balance}")
else:
print("存款金额必须大于0")
def withdraw(self, amount, password):
"""取款"""
if not self.__check_password(password):
print("密码错误!")
return
if amount > self._balance:
print("余额不足!")
return
self._balance -= amount
print(f"取出 ¥{amount},当前余额:¥{self._balance}")
# ========== 保护方法(约定) ==========
def _log_transaction(self, msg):
"""记录交易日志(子类可重写)"""
print(f"[LOG] {msg}")
# ========== 私有方法 ==========
def __check_password(self, pwd):
"""校验密码(内部使用,不暴露)"""
return pwd == self.__password
# ========== @property 控制访问 ==========
@property
def balance(self):
"""余额只读"""
return self._balance
@property
def password_hint(self):
"""密码提示"""
return "密码是6位数字"
# ========== 使用演示 ==========
account = BankAccount("小明", 1000)
# 1. 公开属性:随意访问
print(account.owner) # 小明
account.owner = "大明" # ✅ 可以修改
# 2. 保护属性:可以访问,但不建议
print(account._balance) # 1000(能访问,但约定不要直接改)
# account._balance = 999999 # ❌ 不要这样!
# 3. 私有属性:不能直接访问
# print(account.__password) # ❌ AttributeError!
print(account._BankAccount__password) # 123456(Name Mangling,能但不建议)
# 4. 通过公开方法操作(正确方式)
account.deposit(500) # 存入 ¥500,当前余额:¥1500
account.withdraw(200, "123456") # 取出 ¥200,当前余额:¥1300
account.withdraw(200, "000000") # 密码错误!
# 5. @property 只读
print(account.balance) # 1300
# account.balance = 500 # ❌ AttributeError: can't set attribute
# 6. 私有方法不能调用
# account.__check_password("123") # ❌ AttributeError!
'''
'''
class Demo:
def __init__(self):
self.__secret = "机密" # 双下划线
d = Demo()
# Python 自动改名:_类名__属性名
print(d._Demo__secret) # 机密 ← 可以访问,但不推荐
# 真的不能访问吗?
print(dir(d))
# ['_Demo__secret', '__class__', ...] ← 改名了!
# 这样不会冲突
class A:
def __init__(self):
self.__x = 1 # _A__x
class B:
def __init__(self):
self.__x = 2 # _B__x
a = A()
b = B()
print(a._A__x) # 1
print(b._B__x) # 2
'''
'''
class Temperature:
"""温度类:完整的封装示例"""
ABSOLUTE_ZERO = -273.15
def __init__(self, celsius=0):
self.__celsius = celsius # 私有存储
# ===== 摄氏度(读写)=====
@property
def celsius(self):
return self.__celsius
@celsius.setter
def celsius(self, value):
if value < self.ABSOLUTE_ZERO:
raise ValueError(f"不能低于绝对零度 {self.ABSOLUTE_ZERO}°C")
self.__celsius = value
# ===== 华氏度(读写,自动转换)=====
@property
def fahrenheit(self):
return self.__celsius * 9 / 5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
self.celsius = (value - 32) * 5 / 9 # ← 复用 celsius 的 setter 校验!
# ===== 开尔文(只读)=====
@property
def kelvin(self):
return self.__celsius + 273.15
# 没有 setter = 只读!
t = Temperature(25)
# 读
print(t.celsius) # 25
print(t.fahrenheit) # 77.0
print(t.kelvin) # 298.15
# 写
t.celsius = 30
print(t.fahrenheit) # 86.0
t.fahrenheit = 100 # ← 自动转换为摄氏度
print(t.celsius) # 37.777...
# t.kelvin = 300 # ❌ AttributeError: can't set attribute
# t.celsius = -300 # ❌ ValueError: 不能低于绝对零度
'''
"""
在Python中,可以使用raise关键字手动抛出异常,包括内置异常和自定义异常类,并通过try-except结构捕获处理
"""
#实例化就是是将一个抽象的类具体化为对象的过程。在面向对象编程中,类是一种抽象的模板,描述了对象的属性和方法,而对象是类的具体实例,每个对象都有独立的内存空间和属性值
#继承
#先定义一个book 类title price
#定义 storybook 定义类属性 type1添加一个新方法 讲故事
#定义 tenichbook
#定义 cookbook
class Book:
"""图书基类"""
def __init__(self, title, price):
self.title = title
self._price = price # 保护属性,子类可访问
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("价格不能为负数!")
self._price = value
def info(self):
return f"《{self.title}》¥{self._price}"
def __str__(self):
return self.info()
class StoryBook(Book):
"""故事书"""
book_type = "故事书" # ← 类属性
def __init__(self, title, price, author):
super().__init__(title, price) # ← 调用父类构造
self.author = author
def tell_story(self):
"""讲故事"""
return f"从前有座山,山里有座庙... 《{self.title}》真精彩!"
def info(self):
"""重写父类方法"""
base = super().info() # ← 调用父类 info
return f"{base} | 作者:{self.author} | 类型:{self.book_type}"
class TechBook(Book):
"""技术书"""
book_type = "技术书"
def __init__(self, title, price, language, level):
super().__init__(title, price)
self.language = language # 编程语言
self.level = level # 难度等级
def learn(self):
"""学习"""
return f"正在学习《{self.title}》,{self.language} {self.level}级别"
def info(self):
base = super().info()
return f"{base} | 语言:{self.language} | 难度:{self.level} | 类型:{self.book_type}"
class CookBook(Book):
"""烹饪书"""
book_type = "烹饪书"
def __init__(self, title, price, cuisine):
super().__init__(title, price)
self.cuisine = cuisine # 菜系
def cook(self, dish):
"""做菜"""
return f"按照《{self.title}》做 {self.cuisine} 菜:{dish},完成!"
def info(self):
base = super().info()
return f"{base} | 菜系:{self.cuisine} | 类型:{self.book_type}"
# ========== 测试 ==========
# 故事书
story = StoryBook("小王子", 39.9, "圣埃克苏佩里")
print(story)
print(story.tell_story())
print()
# 技术书
tech = TechBook("Python编程", 89.0, "Python", "入门")
print(tech)
print(tech.learn())
print()
# 烹饪书
cook = CookBook("川菜大全", 68.0, "川菜")
print(cook)
print(cook.cook("麻婆豆腐"))
print()
# 多态:统一处理
books = [story, tech, cook]
print("=== 图书馆藏书 ===")
for book in books:
print(book) # 各自调用自己的 info()
Day4
#继承
'''
子类(派生类)继承父类(基类)中的属性和方法,实现代码重用。
子类可以新增自己特有的方法,也可以重写父类的方法。
子类不能继承父类的私有属性和私有方法,因为存在名称改写,
但是可以通过改写后的名称直接访问父类的私有成员,
不过,这种做法违背了封装原则,不建议使用。
子类可以在类中使用 super().方法名() 或 父类名.方法名() 来调用父类的方法
方法解析顺序(mro—Method Resolution Order)。可使用 类名.__mro__ 访问类的继承链来查看方法解析顺序。
从左向右从下往上的顺序
'''
#animal 类 天上飞的 海里游的 地下跑的 包含前三者属性的具体动物
'''
class Animal:
"""动物基类"""
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
return f"{self.name},{self.age}岁"
def eat(self):
return f"{self.name} 在吃东西"
class Fly(Animal):
"""天上飞的"""
def fly(self):
return f"{self.name} 在天上飞"
class Swim(Animal):
"""海里游的"""
def swim(self):
return f"{self.name} 在海里游"
class Run(Animal):
"""地下跑的"""
def run(self):
return f"{self.name} 在地上跑"
# ========== 具体动物:鸭子(会飞、会游、会跑)==========
class Duck(Fly, Swim, Run):
"""鸭子:继承飞、游、跑三种特性"""
def __init__(self, name, age, color):
super().__init__(name, age) # 调用 Animal.__init__
self.color = color
def quack(self):
return f"{self.name}:嘎嘎嘎~"
def show_abilities(self):
"""展示所有能力"""
abilities = [
self.fly(),
self.swim(),
self.run(),
self.eat(),
self.quack()
]
return "\n".join(abilities)
# ========== 测试 ==========
donald = Duck("唐老鸭", 3, "白色")
print("=== 基本信息 ===")
print(donald.info()) # 唐老鸭,3岁
print(f"颜色: {donald.color}")
print("\n=== 各项能力 ===")
print(donald.fly()) # 唐老鸭 在天上飞
print(donald.swim()) # 唐老鸭 在海里游
print(donald.run()) # 唐老鸭 在地上跑
print(donald.eat()) # 唐老鸭 在吃东西
print("\n=== 展示全部 ===")
print(donald.show_abilities())
print("\n=== MRO 继承顺序 ===")
print(Duck.__mro__)
'''
'''
基类(Base Class)是面向对象编程中被其他类继承的类,包含可被派生类复用的属性和方法。
基类的基本概念
基类,也称为父类或超类,是在继承体系中位于上层的类,定义了多个实体的共性特征和行为。
派生类通过继承基类,可以获得基类的成员(属性和方法),并在此基础上扩展或重写功能,从而实现代码复用和系统的层次化设计
__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
class Animal:
species = '动物'
def __init__(self, name):
self.name = name
print('父类的初始化方法')
def run(self):
print('runing...')
class FlyAnimal(Animal):
species1 = '鸟类'
def fly(self):
print('flying...')
class UndergroundAnimal(Animal):
def __init__(self,name1,speed,name):
self.name1 = name1
self.speed = speed
Animal.__init__(self, name)
def getspeed(self):
print(f'{self.name1}可以跑{self.speed}')
class Chick(FlyAnimal,UndergroundAnimal):
species2 = 'Chick'
def __init__(self,name1,speed,name):
FlyAnimal.__init__(self, name)
UndergroundAnimal.__init__(self, name1,speed,name)
chick = Chick(name1='大公鸡',speed=10,name = '父类')
chick.fly()
chick.run()
chick.getspeed()
print(chick.__dict__)
Python 抽象类是一种不能被实例化的类,用于定义子类必须实现的方法接口,从而保证代码规范和可维护性。
抽象类的概念
在 Python 中,抽象类(Abstract Class)是一种特殊的类,它可以包含抽象方法和具体方法。
抽象方法只声明方法签名而不提供具体实现,子类必须实现这些方法才能被实例化。抽象类通常用于定义接口或规范,确保不同子类遵循统一的行为模式
一、继承的注意事项与最佳实践注意点说明
显式调用super ()始终在子类init中调用super ().init()
私有属性name 会被名称修饰,子类不能直接访问
方法重写重写时保持方法签名一致(参数名和个数)
多重继承 尽量少用,容易引起混乱(菱形继承问题)
LSP原则子类应该可以替换父类(里氏替换原则)
组合优于继承 如果"继承"关系不明确,考虑使用组合
'''
Day5
'''
不同的实例对象(同一个父类)在同一个方法中表现出的不同的行为
'''
'''
class Animal():
def eat(self):
pass
def bark(self):
pass
class Dog(Animal):
def eat(self):
print('吃肉')
def bark(self):
print('汪汪叫')
class Cow(Animal):
def eat(self):
print('吃草')
def bark(self):
print('哞哞')
class Chick(Animal):
def eat(self):
print('吃稻谷')
def bark(self):
print('咯咯')
dog = Dog()
cow = Cow()
chick = Chick()
def get_behavior(animal):
animal.eat()
animal.bark()
# get_behavior(dog)
# get_behavior(cow)
# get_behavior(chick)
'''
'''
class Hero:
def __init__(self,name):
self.name = name
def q(self):
print(f'{self.name}的一技能')
def w(self):
print(f'{self.name}的二技能')
def e(self):
print(f'{self.name}的三技能')
sun = Hero('Sunsx')
luban = Hero('Luban')
jing = Hero('Jing')
class Player:
def __init__(self,id):
self.id = id
def release_q(self,hero):
print(f'{self.id}正在释放一技能')
hero.q()
def release_w(self,hero):
print(f'{self.id}正在释放二技能')
hero.w()
def release_e(self,hero):
print(f'{self.id}正在释放三技能')
hero.e()
me = Player(1111100)
me.release_q(sun)
me.release_w(sun)
me.release_e(sun)
'''
'''
重写(Override)是指子类重新定义继承自父类的方法,实现不同的具体行为,同时保持方法名称、参数列表和返回类型与父类一致。
定义与特征
重写是面向对象编程中的一个核心概念,允许子类对父类的方法进行重新实现,以实现多态性。重写的方法必须满足以下条件:
方法名相同:子类方法与父类方法名称一致。
参数列表相同:包括参数类型和数量必须一致。
返回类型相同或协变:Java 5及以后版本允许返回类型为父类方法返回类型的子类。
访问权限不低于父类:子类方法的访问权限不能比父类方法更严格。
异常范围限制:重写方法不能抛出比父类方法更宽泛的检查异常,只能抛出相同或更小范围的异常
作用与优势
重写的主要作用是让子类可以根据自身需求实现特定行为,而不必完全沿用父类的方法。例如,父类定义了一个move()方法,子类可以重写该方法以实现不同的移动方式。
这样,在运行时调用方法时,会执行子类的实现,而不是父类的实现,实现了动态绑定和多态性
与重载的区别
重写(Override):发生在父类与子类之间,子类重新定义父类方法,实现多态性。方法名、参数列表和返回类型必须一致。
重载(Overload):发生在同一个类中,允许方法名相同但参数列表不同,返回类型可以相同或不同,由编译器在编译期决定调用哪个方法
'''
'''
智能游乐园门禁系统(基础多态)
场景描述:
你正在开发一个智能游乐园的门禁系统。游乐园里有多种游乐设施(如过山车、旋转木马、碰碰车),每种设施的“欢迎语”和“安全须知”都不同。你需要设计一个统一的广播系统,当游客靠近时,系统能根据当前设施自动播放对应的语音提示。
练习要求:
定义一个父类 Ride(游乐设施),包含一个 welcome() 方法。
定义三个子类:RollerCoaster(过山车)、Carousel(旋转木马)、BumperCar(碰碰车),分别重写 welcome() 方法,输出各自独特的欢迎语。
编写一个 Announcer(广播员)类,提供一个 announce(ride) 方法,接收任意游乐设施对象并调用其 welcome() 方法。
实例化不同设施并传入 Announcer,验证多态效果。
'''
'''
class Ride:
def welcome(self):
return f'欢迎来到游乐园\n'
class RollerCoaster(Ride):
def welcome(self):
return f'欢迎体验过山车\n'
class Carousel(Ride):
def welcome(self):
return f'感受旋转\n'
class BumperCar(Ride):
def welcome(self):
return f'享受碰撞\n'
class Announcer:
def announce(self,ride):
print(f'现在进行广播\n')
print(ride.welcome())
a = RollerCoaster()
b = Carousel()
c = BumperCar()
d = Announcer()
d.announce(a)
d.announce(b)
d.announce(c)
'''
'''
from abc import ABC, abstractmethod
# ========== 抽象父类:游乐设施 ==========
class Ride(ABC):
"""游乐设施抽象基类(不能被实例化)"""
@abstractmethod
def welcome(self):
"""
抽象方法:子类必须重写此方法
返回该设施的欢迎语和安全须知
"""
pass
# ========== 子类:具体设施(必须实现 welcome) ==========
class RollerCoaster(Ride):
"""过山车"""
def welcome(self):
return "🎢 欢迎乘坐过山车!请系好安全带,双手握紧扶手,身体后仰,出发!"
class Carousel(Ride):
"""旋转木马"""
def welcome(self):
return "🎠 欢迎乘坐旋转木马!请扶稳坐好,儿童需由成人陪同,木马旋转时请勿站立。"
class BumperCar(Ride):
"""碰碰车"""
def welcome(self):
return "🚗 欢迎驾驶碰碰车!请系好安全带,踩油门前进,碰撞时注意保护头部,不要故意撞击他人。"
# ========== 广播员(多态的触发者) ==========
class Announcer:
@staticmethod
def announce(ride):
"""对任意游乐设施进行广播(多态)"""
print("📢 广播员开始播报:")
print(ride.welcome())
print("-" * 40)
# ========== 测试 ==========
if __name__ == "__main__":
# # 尝试实例化抽象类会报错(无法实例化)
# generic_ride = Ride() # TypeError: Can't instantiate abstract class Ride with abstract method welcome
roller_coaster = RollerCoaster()
carousel = Carousel()
bumper_car = BumperCar()
announcer = Announcer()
announcer.announce(roller_coaster)
announcer.announce(carousel)
announcer.announce(bumper_car)
'''
'''
class Ride:
def welcome(self):
pass
class RollerCoaster(Ride):
def __init__(self,name):
self.name = name
def welcome(self):
print(f'欢迎来到{self.name},祝您玩得愉快')
class Carousel(Ride):
def __init__(self,name):
self.name = name
def welcome(self):
print(f'欢迎来到{self.name},祝您玩得愉快')
class BumperCar(Ride):
def __init__(self,name):
self.name = name
def welcome(self):
print(f'欢迎来到{self.name},祝您玩得愉快')
rollercoaster = RollerCoaster('过山车')
carousel = Carousel('旋转木马')
bumperCar = BumperCar('碰碰车')
class Announcer:
def __init__(self,id):
self.id = id
def announce(self,ride):
ride.welcome()
announcer1 = Announcer(1001)
ride = [rollercoaster,carousel,bumperCar]
for r in ride:
announcer1.announce(r)
'''
更多推荐

所有评论(0)