Python笔记3(杂笔记)

1.一个Python中“多态”案例中的“关于参数(局部变量)调用其他类的属性和方法的疑难分析

(总共有3部分)

(一)

 

 

上面代码中dog参数只要在方法中定义了就能直接使用并且能调用name属性和game方法是吗?
———————————
是的,你的理解是正确的!在 Python 中,只要 `dog` 参数被传入方法(`game_with_dog`),就可以直接使用它,并调用它的属性和方法(如 `dog.name` 和 `dog.game()`),前提是:  

1. `dog` 对象确实有这些属性和方法(即它所属的类定义了 `name` 属性和 `game()` 方法)。  
2. `dog` 是方法的参数(或局部变量),而不是类的属性,所以不需要 `self.dog`。  

---

详细解释:
1.`dog` 是方法的参数,可以直接使用
在 `Person` 类的 `game_with_dog` 方法中:
代码示例→
def game_with_dog(self, dog):  # dog 是参数
    print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name))  # 直接使用 dog.name
    dog.game()  # 直接调用 dog.game()
```
- `dog` 是方法的参数,Python ⭐️允许直接使用它,无需额外声明。
- 只要⭐️调用方法时传入的对象(如 `wangcai`)具有 `name` 属性和 `game()` 方法,代码就能正常运行。

 

是的,在代码 “def game_with_dog(self, dog):” 中⭐️⭐️dog 是方法的参数,它接收的是一个类的实例(对象),⭐️⭐️或者说dog是一个对象。

---

2. 为什么 `dog` 能调用 `name` 和 `game()`?
- `dog.name`:  
  - `Dog` 类和 `XiaoTianDog` 类都在 `__init__` 中定义了 `self.name = name`,所以它们的实例都有 `name` 属性。  
  - 因此,`dog.name` 可以正确访问。  

- `dog.game()`:  
  - `Dog` 类定义了 `game()` 方法,`XiaoTianDog` 继承并重写了它。  
  - 由于 `dog` 可能是 `Dog` 或 `XiaoTianDog` 的实例,调用 `dog.game()` 时会自动执行对应类的方法(多态)。  
⭐️dog确实是Dog/XiaoTianDog的示例:
因为→→→
⭐️⭐️⭐️
①xiaoming.play_with_dog(wangcai),即dog传入对象是wangcai→②而wangcai = XiaoTianDog("飞天旺财"),即wangcai是XiaoTianDog的示例对象→③所以最终dog就是XiaoTianDog的示例对象,能调用XiaoTianDog的game方法、即:dog.game();而XiaoTianDog继承了Dog所以拥有Dog的name属性,能调用Dog的name属性、即:dog.name
---

3. 为什么不需要 `self.dog`?
- `self.dog` 表示访问当前对象(`Person` 实例)的 `dog` 属性,但 `Person` 类并没有定义这个属性。  
- 这里的 `dog` 是方法的局部变量(参数),不是类的属性,所以直接使用即可。  

---
补:区分Python中的“函数和方法”、“属性和变量”
①函数和方法都是函数,定义在类内叫做方法,定义在类外或者单独使用叫做函数;
②属性和变量其实都是变量,定义在类内叫做属性,定义在类外或者单独使用叫做变量;

———

对比:如果 `dog` 是类的属性
假设 `Person` 类有一个 `dog` 属性:
代码示例→
class Person(object):
    def __init__(self, name, dog):  # 初始化时传入 dog
        self.name = name
        self.dog = dog  # 将 dog 存储为实例属性

    def play_with_dog(self):
        print("%s 和 %s 玩耍..." % (self.name, self.dog.name))  # 必须用 self.dog
        self.dog.game()
```
这时:
- `dog` 是 `Person` 的属性,必须通过 `self.dog` 访问。  
- 调用方式会变成:
  ```python
  wangcai = XiaoTianDog("飞天旺财")
  xiaoming = Person("小明", wangcai)  # 初始化时传入 dog
  xiaoming.play_with_dog()  # 方法内部用 self.dog
  ```

---

总结:
- 方法的参数(如 `dog`)可以直接使用,无需 `self.`。  
- 只要传入的对象有对应的属性和方法(如 `name` 和 `game()`),就可以调用。  
- 如果 `dog` 是类的属性(如 `self.dog`),则需要通过 `self.dog` 访问。  

你的理解完全正确!这是 Python 面向对象编程中方法参数和对象动态调用的典型用法。

 

———————————

(二)

这些代码里的dog.name、dog.game分别是什么意思?dog是哪来的是什么角色?,为什么dog不用self.dog就能直接调用name和game方法?

在给定的代码中,`dog.name` 和 `dog.game()` 的用法涉及到面向对象编程中的对象和方法调用。让我逐步解释:

1. `dog` 的来源和角色
`dog` 是 `Person` 类中 `game_with_dog` 方法的一个参数。当调用 `xiaoming.game_with_dog(wangcai)` 时,`wangcai`(一个 `XiaoTianDog` 实例)被传递给 `game_with_dog` 方法,此时方法内的 `dog` 参数就指向 `wangcai` 对象。

2. `dog.name` 和 `dog.game()` 的含义
- `dog.name`:访问 `dog` 对象的 `name` 属性。因为 `Dog` 类(以及继承它的 `XiaoTianDog` 类)在 `__init__` 方法中定义了 `self.name = name`,所以 `dog` 对象有 `name` 属性。
- `dog.game()`:调用 `dog` 对象的 `game` 方法。如果 `dog` 是 `XiaoTianDog` 实例(如代码中的 `wangcai`),则会执行 `XiaoTianDog` 类中重写的 `game` 方法(输出“飞到天上去玩耍”);如果是普通的 `Dog` 实例,则执行 `Dog` 类的 `game` 方法(输出“蹦蹦跳跳的玩耍”)。

3. 为什么不需要 `self.dog`?
- `dog` 是方法的参数,不是类的属性。`self.dog` 会尝试访问当前对象(`Person` 实例)的 `dog` 属性,但这里并没有定义这个属性。
- 直接使用 `dog` 是因为它是一个局部变量(参数),指向传入的 `Dog` 或 `XiaoTianDog` 实例。Python 中方法的参数可以直接在方法内使用,无需通过 `self`。

代码执行流程
1. `wangcai = XiaoTianDog("飞天旺财")`:创建一个 `XiaoTianDog` 实例,名字为“飞天旺财”。
2. `xiaoming = Person("小明")`:创建一个 `Person` 实例,名字为“小明”。
3. `xiaoming.game_with_dog(wangcai)`:调用 `Person` 的 `game_with_dog` 方法,传入 `wangcai` 对象。
   - 方法内打印:`小明 和 飞天旺财 快乐的玩耍...`(通过 `dog.name` 获取名字)。
   - 调用 `dog.game()`,即 `wangcai.game()`,执行 `XiaoTianDog` 的 `game` 方法,输出:`飞天旺财 飞到天上去玩耍...`。

总结
- `dog` 是方法的参数,指向传入的 `Dog` 或子类实例。
- `dog.name` 和 `dog.game()` 是动态调用的,具体行为取决于 `dog` 的实际类型(多态)。
- 不需要 `self.dog` 因为 `dog` 不是类的属性,而是方法的局部变量。

 

———————————

(三)

class Cat:
     def __init__(self,name2):
         self.name1 = name2

#区分开二者:①name1是该Cat的属性(成员变量);②而name2是参数(传入参数)、用于接收外界传入的内容

def eat(self):
      print("%s 爱吃鱼" % self.name1)
          tom = Cat("Tom")

#Tom作为内容传给传入参数name2,然后name2将值(Tom)提供给内部的成员变量self.name1
——————————
在Python类中,self.name1 带上 self. 是为了明确这个变量是实例属性(instance attribute),而不是局部变量。这是面向对象编程中非常重要的概念,具体原因如下:
区分"实例属性"和"局部变量"→
①name2 是方法的参数,它是一个局部变量,只在 __init__ 方法的作用域内有效。②self.name1 是实例属性,它属于当前创建的实例对象(比如某只具体的猫),会随着对象的存在而一直存在。

通过 self. 显式绑定,可以确保这个属性归属于实例。

———————

①⭐️在类的外部,通过“变量名.”访问对象的属性和方法("变量名"可指局部变量,只要这个局部变量接收传入的对象是“具有name属性和game方法的类的实例对象”那么就能直接用“变量名.属性/方法”访问“属性/方法”了)
②在类封装的方法中,通过“self.”访问对象的属性和方法

 

————————————————————

2.“方法(类中的函数)”和“函数”的参数中要不要带self参数→

别搞混了,区分开!:

(1)类的方法(即类中的函数,需要 self):

class Dog:
    def speak(self):  # self 代表调用该方法的实例(如 dog)
        print("Woof!")

dog = Dog()
dog.speak()  # Python 自动把 dog 作为 self 传入

(2)普通函数(独立的函数,不需要 self):

def animal_sound(animal):  # animal 是一个普通参数
    animal.speak()  # 调用 animal 的 speak 方法

animal_sound(dog)  # 手动传入 dog 作为 animal

 

————————————————————

3.理清一个关于用“self.”访问属性的疑难
→关键是要理解self是什么角色

(1)问题:
class  Person:
    def  __init__(self,name,weight):
          self.name=name
          self.weight=weight
    def  run(self):
          print("%s 跑了一次步" % self.name)
           self.weight -= 0.5

在类封装的方法中,通过“self.”访问对象的属性和方法。这句话中的方法是类中的各方法都可以用“self.”的方式访问对象的属性吗?

(2)解答:
是的,在 Python 的类中,所有实例方法(即第一个参数是 `self` 的方法)都可以通过 `self.` 访问当前对象的属性和其他方法。  

关键点:
①.⭐️ `self` 代表当前对象实例
   - 当调用 `person.run()` 时,`self` 会自动指向 `person` 这个实例对象。  
   - 因此,`self.name` 和 `self.weight` 访问的是当前对象的属性。  

②. 所有实例方法共享 `self`
   - 类中的任何实例方法(如 `run`、`eat`、`sleep` 等)都可以通过 `self.` 访问或修改对象的属性。  
   - 例如,你可以在另一个方法中直接读取 `self.weight` 或调用 `self.run()`。  

③. 修改属性会影响对象的状态
   - 比如 `run()` 方法中通过 `self.weight -= 0.5` 修改了对象的属性,其他方法调用时也会看到这个变化。  

示例扩展:
class Person:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def run(self):
        print("%s 跑了一次步" % self.name)
        self.weight -= 0.5

    def eat(self, food_calories):
        print("%s 吃了食物,增加了 %d 大卡" % (self.name, food_calories))
        self.weight += food_calories / 1000  # 假设每1000大卡增加1kg

    def check_weight(self):
        print("%s 的当前体重是 %.1f kg" % (self.name, self.weight))

# 使用示例
person = Person("小明", 70)
person.run()      # 体重减少0.5kg
person.eat(500)   # 体重增加0.5kg
person.check_weight()  # 输出当前体重(仍然是70kg)
```

总结:
- `self.` 是访问对象属性和方法的统一方式,所有实例方法均可使用。  
- 通过 `self.` 修改的属性会持久化到对象中,其他方法调用时会反映这些变化。  
 

————————————————————

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值