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  # 修改p1age属性

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)
'''

更多推荐