面向对象的三要素
封装
class Turtle: # python 中的类
age = 'green'
weight = 10
legs = 4
shell = True
mouth = '大嘴'
# 方法
def climb(self):
print('我在很努力')
def run(self):
print('运行')
def bite(self):
print('陶死你')
def add(self):
print('加法运算')
t = Turtle()
t.climb()
继承
继承是子类自动共享父类之间数据和方法的机制
'''
Mylist 继承 list 列表的方法
pass 表示占位
Mylist 这个类不做任何事情, 达到信息隐蔽
'''
class Mylist(list):
pass
# 实例化 Mylist 实例对象
list2 = Mylist()
list2.append(5)
list2.append(9)
list2.append(15)
print(list2)
# 也可以进行排序
print(list2.stor())
-------------------------------
>>>>[5, 19, 15]
>>>>[5, 15, 19]
多态
'''
多态就是 不同对象 对同一方法 响应不同的行动
'''
class A:
def fun(self):
print('我是A对象里的函数')
class B:
def fun(self):
print('我是B对象里的函数')
a = A()
b = B()
a.fun()
b.fun()
------------------
>>>我叫张三, 该死的, 谁踢我....
>>>我叫李四, 该死的, 谁踢我....
>>>我叫小明, 该死的, 谁踢我....
self 是什么?
python的 self 就相当于 JavaScript 中的 this 的指针
# self 指针 相当于 JavaScript中的 this 指针
# 这个类相当于模版一样,
class Ball:
def setName(self, name):
self.name = name
def cick(self):
print("我叫%s, 该死的, 谁踢我...." %self.name)
a = Ball()
a.setName("张三")
b = Ball()
b.setName("李四")
c = Ball()
c.setName("小明")
a.cick()
b.cick()
c.cick()
--------------------
>>>我叫张三, 该死的, 谁踢我....
>>>我叫李四, 该死的, 谁踢我....
>>>我叫小明, 该死的, 谁踢我....
访问控制与属性装饰器
在python 中定义私有变量 只需要在变量或者函数名前加上 “__” 两个下划线, 那么这个函数或变量就会为私有 外部访问不了 , 同时也称为装饰器
共有变量函数
# 共有 ,可以被外部访问的
class temp:
age = 18
def setName(self, name):
print('我叫:%s' % name)
A = temp()
print(A.age)
A.setName('张三')
-------------------
>>>18
>>>我叫:张三
访问私有变量函数1
'''
定义私有函数或者变量 在变量或者函数前 添加 __ 双下划线即可
然后调用共有的方法, 获取内部私有的变量或者函数
'''
class temp:
__age = 18
def __setName(self, name):
print('我叫:%s' % name)
def getAge(self):
print('age的值:%s' % self.__age)
def getName(self,name):
self.__setName(name)
A = temp()
A.getAge()
A.getName('李四')
---------------------------------
>>>18
>>>我叫:李四
访问私有变量函数2
class temp:
__age = 18
def __setName(self, name):
# print('我叫:%s' % name)
return '我叫:%s' % name
def getAge(self):
print('age的值:%s' % self.__age)
def getName(self,name):
self.__setName(name)
A = temp()
A.getAge()
A.getName('李四')
# 还可以通过 下划线类名 进行访问也可以
print(A._temp__age)
print(A._temp__setName('王五'))
---------------------------------
>>>age的值:18
>>>18
>>>我叫:王五
类和实例
# 类
class Turbo:
name = '张三'
def add(a,b):
return a + b
# 实例化 出了 t
t = Turbo()
t.name
类方法与静态方法
静态方法 @staticmethod
为什么会报错?
静态方法不能访问实例属性、类属性、实例方法、类方法
class Test2:
name ="你好世界"
@staticmethod
def static(self):
print("我的口号是:" +self.name)
temp2 = Test2()
temp2.static()
# static 已经通过 @staticmethod 定义成静态方法, 所以不能直接这样访问,
因为 self是上下文访问 属性name, 当然也包括这个 self
---------------------报错
TypeError: static() missing 1 required positional argument: 'self'
静态方法的特别之处
- 它跟类与对象无关
- 跟在模块中直接定义普通函数没有什么区别,只是把“静态方法”放到了类里面,所以只能设置形参
- 只能通过 类名.静态方法 来调用 ```python
class Test: name =”你好世界”
@staticmethod
def static(name):
print("我的口号是:" +name)
temp = Test()
temp.static(temp.name)
Test.static(temp.name)
我的口号是:你好世界 我的口号是:你好世界
<a name="Bqd4L"></a>
### 类方法 @classmethod
```python
class person:
name = "cool man"
@classmethod
def class_m(cls):
print("--第一个类方法--", id(cls))
print("--第一个类方法--", cls.name)
cls.self_m(cls)
cls.class_m2()
def self_m(self):
print("--实例方法--", id(self))
print("--实例方法--", self.name)
@classmethod
def class_m2(cls):
print("--第二个类方法--", id(cls))
p = person()
p.name = "bad boy" # 绑定实例属性
p.class_m()
person.class_m()
知识点
- 类方法内部可以直接访问类属性、类方法、实例方法
- 可以理解成类对象的引用,哪一个类对象调用的方法, cls 就是哪个一个类的引用, 类对象.类方法 ;和实例方法中的 self 很像, 实例对象.实例方法
cls
- 调用其他类方法时,不用传递cls参数;但调用其他实例方法时,需要传递cls参数
- 在类方法内部调用的实例方法,接收的是一个类对象而不是实例对象,当实例对象绑定实例属性时,在实例方法中打印的仍然是类属性;表明类方法无法访问实例属性
一个类只有一个类对象,即使通过实例对象调用类方法,传递的仍然是类对象的引用,所有类方法都被同一个类对象调用
思考题
如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?
答案:实例方法,因为可以通过 类对象.类属性 来访问,但在类方法中无法访问实例属性 ```python class Person: name = “bad boy”def self_m(self):
Person.name = "yep"
print(self.name)
p = Person() p.name = “陈十八” # 绑定实例属性 p.self_m()
Person.self_m(Person)
陈十八 yep
<a name="h3sYt"></a>
## 继承与多态
<a name="usqCm"></a>
### 子继承父类
```python
class Panent:
def hello(self):
print('正在调用父类的方法....')
class Child(Panent):
pass
p = Panent()
p.hello()
c=Child()
c.hello()
-----------
>>>正在调用父类的方法....
>>>正在调用父类的方法....
如果子类中定义与父类同名的方法或者属性, 则会自动覆盖父类对应的方法或属性
class Panent: # 这个是父类
def hello(self):
print('正在调用父类的方法....')
class Child(Panent): # 这个是子类
def hello(self):
print('正在调用子类的方法....')
p = Panent()
p.hello()
c=Child()
c.hello()
-----------
>>>正在调用父类的方法....
>>>正在调用子类的方法....
小案列
鲨鱼移动 的代码 会报错 为什么呢, 可是代码都相同啊!
因为 我们重写 init方法, 子类重写了父类的方法, 就会覆盖原来的方法
import random as r
class Fish: # 鱼
def __init__(self):
self.x = r.randint(0, 10)
self.y = r.randint(0, 10)
def move(self):
self.x -= 1
print("我的位置是:", self.x, self.y)
class Goldfish(Fish): # 金鱼
pass
class Carp(Fish): # 鲤鱼
pass
class Salmon(Fish): # 三文鱼
pass
class Shark(Fish):
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有的吃")
self.hungry = False
else:
print("太撑了, 吃不下")
fish = Fish()
fish.move()
goldfish = Goldfish() # 金鱼移动
goldfish.move()
shark = Shark() # 鲨鱼移动
shark.move()
---------------------
我的位置是: 5 8
我的位置是: 5 5
Traceback (most recent call last):
File "e:/001笔记大全/008Python01/demon10.py", line 40, in <module>
shark.move()
File "e:/001笔记大全/008Python01/demon10.py", line 8, in move
self.x -=1
AttributeError: 'Shark' object has no attribute 'x'
我们要在重写init 方法的时候
解决方法1
调用未绑定的父类方法
应该要在鲨鱼的类里面 重写init 方法的时候先调用子类的init方法
只需要书写父类的名字 Fish.init(self)
import random as r
class Fish: # 鱼
def __init__(self):
self.x = r.randint(0, 10)
self.y = r.randint(0, 10)
def move(self):
self.x -= 1
print("我的位置是:", self.x, self.y)
class Goldfish(Fish): # 金鱼
pass
class Carp(Fish): # 鲤鱼
pass
class Salmon(Fish): # 三文鱼
pass
class Shark(Fish):
def __init__(self):
'''
原理, 子类中有跟父类一样的方法会覆盖父类的方法, 所以在修改前 添加这段代码即可
注意: Fish.__init__(self)是调用父类的
而self 是子类的实列对象
'''
Fish.__init__(self)
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有的吃")
self.hungry = False
else:
print("太撑了, 吃不下")
fish = Fish()
fish.move()
goldfish = Goldfish() # 金鱼移动
goldfish.move()
shark = Shark() # 鲨鱼移动
shark.move()
---------------------
我的位置是: 9 0
我的位置是: 9 9
我的位置是: 8 8
解决办法2
使用 super 函数 能够帮我们自动找到基类的方法, 还能帮我们传参数
import random as r
class Fish: # 鱼
def __init__(self):
self.x = r.randint(0, 10)
self.y = r.randint(0, 10)
def move(self):
self.x -= 1
print("我的位置是:", self.x, self.y)
class Goldfish(Fish): # 金鱼
pass
class Carp(Fish): # 鲤鱼
pass
class Salmon(Fish): # 三文鱼
pass
class Shark(Fish):
def __init__(self):
# Fish.__init__(self)
super().__init__()
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有的吃")
self.hungry = False
else:
print("太撑了, 吃不下")
fish = Fish()
fish.move()
goldfish = Goldfish() # 金鱼移动
goldfish.move()
shark = Shark() # 鲨鱼移动
shark.move()
--------------------------------
我的位置是: 2 0
我的位置是: 1 9
我的位置是: 2 3
多重继承
可以继承多重父类的方法
注意, 请尽量避免使用它
class Base1:
def fun1(self):
print("我是fun1d.")
class Base2:
def fun2(self):
print("我是fun2.")
class C(Base1, Base2):
pass
b = C()
b.fun1()
b.fun2()
---------------------
我是fun1d.
我是fun2.
继承与多继承(组合)
思路提示 :
定义一个水池类
水池里有乌龟类, 金鱼类等等
如果使用继承和多继承显然不行, 乱搞
那怎么样才能组成一个和谐的类呢? 使用组合即可
所谓的组合就是把旧类放到新类里, 这样就组合进去了
# 水池组合
class Turtle: # 乌龟
def __init__(self, x): # x 表示有多少个乌龟进来
self.num = x
class Fish: # 金鱼
def __init__(self, x): # x
self.num = x
class Pool: # 水池
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("水池里总共有乌龟 %d 只, 小鱼 %d 条" % (self.turtle.num, self.fish.num))
# 组合就是 把2 个旧类 实列化 放到 新的类里面 那么就把旧类 组合进去了,
pool = Pool(2,10)
pool.print_num()
--------------------------
水池里总共有乌龟 1 只, 小鱼 10 条