类和对象
编程语言分类:
编译型语言 解释型语言
面向过程语言: c
面向对象语言: java python c++ c# php javascript
面向过程:注重过程 我们是执行者
面向对象:注重结果 我们是调用者
面向对象的本质还是面向过程
类: 类又叫模板
对象: 又叫实例 是根据类创建出来的
创建一个类需要一个关键字:
class
根据类创建对象:
对象名 = 类名()
对象名 = 类名()
类是对一群具有相同特征或者行为 的事物的一个统称,是抽象的,不能直接使用
- 特征其实就是一个变量,在类里我们称之为属性。
- 行为其实就是一个函数,在类里我们称之为方法。
- 类其实就是由 属性 和 方法 组成的一个抽象概念。
对象
对象是由类创建出来的一个具体存在,可以直接使用。由哪一个类创建出来的 对象,就拥有在哪一个类中定义的属性和方法。 对象 就相当于用图纸制造的飞机。在开发中,应该先有类,在类里定义好属性和行为,再根据类来创建对象
class Dog:
def __init__(self, name, sex, age, color):
self.name = name
self.sex = sex
self.age = age
self.color = color
def look_door(self):
print("%s能看门" % self.name)
def eat(self):
print("%s吃骨头" % self.name)
dog1 = Dog('狗蛋子', '公', '3岁', '黄色')
dog1.look_door()
dog1.eat()
dog2 = Dog('二愣子', '母', '4岁', '灰色')
dog2.look_door()
dog2.eat()
关系
- 类是模板,对象是根据类这个模板创建出来的,应该先有类,再有对象。
- 使用同一个类,能够创建出很多对象。
- 类中定义了什么属性和方法,对象中就有什么属性和方法。
- 不同对象对应的属性值也会不同。
在程序开发中,要设计一个类,通常需要满足一下三个要素:
- 类名 这类事物的名字,安照大驼峰命名法(每个单词的首字母大写)起名。
- 属性 这类事物具有什么样的特征。
- 方法 这类事物具有什么样的行为。
定义类名
名词提炼法:分析整个业务流程,出现的名词,通常就是找到的类。
属性和方法的确定
- 对对象的特征描述,可以定义成属性
- 对象具有的行为(动词)可以定义成方法属性和方法的确定
- 对对象的特征描述,可以定义成属性
- 对象具有的行为(动词)可以定义成方法
面向对象
在Python中,对象几乎是无处不在的,我们可以使用dir
内置函数来查看这个对象里的方法。
class Person:
def __init__(self, name, age, height):
self.name = name
self.age = age
self.height = height
def run(self, flag):
if flag:
print(f"{self.name}跑会步")
else:
print(f"{self.name}不喜欢跑步")
def eat(self):
print("吃东西")
p1 = Person('小明', '18', '1.75')
p1.run(True)
p1.eat()
p2 = Person('小美', '17', '1.65')
p2.run(False)
p2.eat()
print(dir(p1))
定义类
在Python中要定义一个只包含方法的类,语法格式如下:
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
"""
方法的定义格式和之前学习过的函数一样
方法里的第一个参数必须是self,大家暂时先记住,稍后介绍 self.
类名要遵守大驼峰命名法。
"""
创建实例对象
当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:
对象变量名 = 类名()
列子
class Cat:
"""这是个猫类"""
def eat(self):
print("小猫在吃东西")
def drink(self):
print("小猫在喝水")
tom = Cat() # 创建了一个Cat对象
tom.eat()
tom.drink()
hello_kitty = Cat() # 又创建了一个新的Cat对象
hello_kitty.eat()
hello_kitty.drink()
self的使用
给对象添加属性
python支持动态属性,当一个对象创建好了以后,直接使用 对象.属性名 = 属性值 就可以很方便的给对象添加一个属性。
# 这种方法很方便,但是,不建议使用这种方式给对象添加属性。
tom = Cat()
tom.name = 'Tom' # 可以直接给 tom 对象添加一个 name 属性
self的概念
哪个对象调用了方法,方法里的self指的就是谁。 通过 self.属性名 可以访问到这个对象的属性;通过 self.方法名() 可以调用这个对象的方法。
class Cat:
def eat(self):
print("%s爱吃鱼" %self.name)
tom = Cat()
tom.name = 'Tom' # 给 tom 对象添加了一个name属性
tom.eat() # Tom爱吃鱼
lazy_cat = Cat()
lazy_cat.name = "大懒猫"
lazy_cat.eat() # 大懒猫爱吃鱼
在日常开发中,不推荐在类的外部直接给对象添加属性这种方式。对象应该具有哪些属性,我们应该封装在类的内部。
魔法方法
Python 里有一种方法,叫做魔法方法。Python 的类里提供的,两个下划线开始,两个下划线结束的方法,就是魔法方法,魔法方法在恰当的时候就会被激活,自动执行。 魔法方法的两个特点:
- 两侧各有两个下划线;
- "咒语"名字已经由 Python 官方定义好,我们不能乱写。
不太能理解到底啥是魔法方法
## __init__方法
初始化值
__init__()
方法,在创建一个对象时默认被调用,不需要手动调用。在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对 __init__
方法进行改造。
class Cat:
"""这是一个猫类"""
def __init__(self,name): # 重写了 __init__ 魔法方法
self.name = name
def eat(self):
return "%s爱吃鱼"%self.name
def drink(self):
return '%s爱喝水'%self.name
"""
tom = Cat()
TypeError: __init__() missing 1 required positional argument: 'name'
这种写法在运行时会直接报错!因为 __init__ 方法里要求在创建对象时,必须要传递 name 属性,如果不传入会直接报错!
"""
tom = Cat("Tom") # 创建对象时,必须要指定name属性的值
tom.eat() # tom爱吃鱼
#注意
"""
1.__init__()方法在创建对象时,会默认被调用,不需要手动的调用这个方法。
2.__init__()方法里的self参数,在创建对象时不需要传递参数,python解释器会把创建好的对象引用直接赋值给self
3.在类的内部,可以使用self来使用属性和调用方法;在类的外部,需要使用对象名来使用属性和调用方法。
4.如果有多个对象,每个对象的属性是各自保存的,都有各自独立的地址。
5.方法是所有对象共享的,只占用一份内存空间,方法被调用时会通过self来判断是哪个对象调用了实例方法。
"""
__del__方法
前期没啥用,到后期用刀数据流就会有用啦
创建对象后,python解释器默认调用__init__()方法;
而当删除对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法。
class Student:
def __init__(self,name,score):
print('__init__方法被调用了')
self.name = name
self.score = score
def __del__(self):
print('__del__方法被调用了')
s = Student('lisi',95)
del s
input('请输入内容')
.__str__方法
可以吧本来输出为地址或者是其他东西的输出, 变为输出字符串
__str__方法返回对象的描述信息,使用print()函数打印对象时,其实调用的就是这个对象的__str__方法。
class Cat:
def __init__(self,name,color):
self.name = name
self.color = color
tom = Cat('Tom','white')
# 使用 print 方法打印对象时,会调用对象的 __str__ 方法,默认会打印类名和对象的地址名
print(tom) # <__main__.Cat object at 0x0000021BE3B9C940>
#如果想要修改对象的输出的结果,可以重写 __str__ 方法。
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return '哈哈'
p = Person('张三',18)
print(p) # 哈哈 打印对象时,会自动调用对象的 __str__ 方法
#一般情况下,我们在打印一个对象时,可能需要列出这个对象的所有属性。
class Student:
def __init__(self,name,score):
self.name = name
self.score = score
def __str__(self):
return '姓名是:{},成绩是{}分'.format(self.name,self.score)
s = Student('lisi',95)
print(s) # 姓名是:lisi,成绩是95分
class Book:
def __init__(self, name, price, author):
self.name = name
self.price = price
self.author = author
def look(self, uname):
print(f"{uname}正在看{self.name}")
def __str__(self):
return self.name + "--" + self.price + "--" + self.author
def __call__(self, *args, **kwargs):
self.look(args[0])
print("hello world")
b = Book('三体', '180$', '刘慈欣')
# b('haha')
print(b)
repr__方法
有__str__方法就用,这个和str方法差不多,建议优先使用str方法
__repr__方法和__str__方法功能类似,都是用来修改一个对象的默认打印内容。在打印一个对象时,如果没有重写__str__方法,它会自动来查找__repr__方法。如果这两个方法都没有,会直接打印这个对象的内存地址。
__call__方法
对象后面加括号,触发执行。
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
总结
当创建一个对象时,会自动调用__init__方法,当删除一个对象时,会自动调用__del__方法。
使用__str__和__repr__方法,都会修改一个对象转换成为字符串的结果。一般来说,__str__方法的结果更加在意可读性,而__repr__方法的结果更加在意正确性(例如:datetime模块里的datetime类)