Python基础 - 09面向对象
面向对象:
类(有共同特征和行为的抽象的)、 对象(实例化的个体、个例)、 属性: 特征、 方法: 动作
一、类定义
所有的类名要求首字母大写,多个单词使用驼峰式命名。 如 ValueError、 StopIterable
class Phone:
brand = 'huawei'
print(Phone) # <class '__main__.Phone'>
# 使用类创建对象
hw = Phone()
print(hw) # <__main__.Phone object at 0x0000006683783B20>
print(hw.brand) # huawei, 如果对象自己的空间存在 brand属性,则不会去模型中取查找
hw.brand = 'honor'
print(hw.brand) # honor
构造器__init__(self)
1. 找有没有一块空间是Phone类的
2. 利用Phone类,向内存申请一块和Phone一样的空间,0x0000009196583B20
3. 去 Phone 中找有没有 __init__, 如没有则 执行将开辟的内存空间 给对象 p1 -> 0x0000009196583B20
4. 如果有__init__,则会进入__init__方法执行里面动作。 动态的self 空间添加两个属性: brand, price
二、方法
种类: 普通方法/对象方法、 类方法、 静态方法、 魔术方法
2.1 普通方法
# 方法
class Phone:
brand = 'xiaomi'
def __init__(self):
print('-----init-----')
def call(self):
print('self ---> ', self)
print('打电话....')
xm1 = Phone()
print(xm1) # <__main__.Phone object at 0x0000009196583B20>
xm1.call() # self ---> <__main__.Phone object at 0x0000009196583B20> \n 打电话....
2.2 类方法
# 类方法
# 定义需要依赖装饰器 @classmethod
# 类方法中参数不是一个对象,而是类。 print(cls) <class '__main__.Dog'>
# 类方法中只可以使用类属性。
# 类方法中不可使用普通方法。
class Dog:
def __init__(self, nickname):
self.nickname = nickname
def run(self):
print('{}在院子里跑圈'.format(self.nickname))
@classmethod
def test(cls):
print(cls)
# print(cls.nickname) # AttributeError: type object 'Dog' has no attribute 'nickname'
# print(self.nickname) # NameError: name 'self' is not defined
d1 = Dog('球球')
d1.run() # 球球在院子里跑圈
d1.test() # <class '__main__.Dog'>
Dog.test() # <class '__main__.Dog'>
#------------------------------------------
class Person:
__age = 18
def show(self):
print('-->', Person.__age)
@classmethod
def update_age(cls):
cls.__age = 20
print('---->类方法')
print(Person.__age)
@classmethod
def show_age(cls):
print('修改后年龄:', cls.__age)
# print(Person.__age) # AttributeError: type object 'Person' has no attribute '__age'
Person.update_age() # ---->类方法 \n 20
Person.show_age() # 修改后年龄: 20
2.3 静态方法
# 静态方法
# 需要装饰器 @staticmethod
# 静态方法是无需传递参数(cls, self)
# 只能访问类的属性和方法,对象的属性和方法是无法访问的。
# 加载时机同类方法
class Student:
__age = 18
name = 'lucy'
def show(self):
print('-->', Person.__age)
@classmethod
def update_age(cls):
cls.__age = 20
print('---->类方法')
print(Person.__age)
@classmethod
def show_age(cls):
print('修改后年龄:', cls.__age)
@staticmethod
def test():
print('-->静态方法')
# print(self.name) # 语法错误
print(Student.__age)
s = Student()
s.test() # -->静态方法 \n 18
类方法 和 静态方法
不同: 1. 装饰器不同 2. 类方法是有参数的, 静态方法是没有参数的
相同: 1. 只能访问类的属性和方法, 无法访问对象的 2. 都可以通过类名调用访问 3. 可以在创建对象之前访问。不依赖对象。
普通方法: 没有装饰器, 要依赖对象,每个普通方法都有一个self, 只有创建了对象才能调用。
2.4 魔术方法
格式: __名字__()
2.4.1 构造器 __init__(): 初始化, 触发时机: 初始化对象时触发。(不是实例化触发,是和实例化在一个操作中)
参数: 至少有一个self,接收对象 返回值: 无
class Person:
name = 'zhangsan'
def __init__(self):
self.name = '张三'
self.age = 18
def eat(self):
print('{}正在吃饭'.format(self.name))
def run(self):
print('{},今年{}岁,正在跑步'.format(self.name, self.age))
p1 = Person()
p1.name = '李四'
p1.eat() # 李四正在吃饭
p2 = Person()
p2.eat() # 张三正在吃饭
p2.run() # 张三,今年18岁,正在跑步
# -----------------------------------------
class Person:
name = 'zhangsan'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self, food):
print('{}正在吃{}'.format(self.name, food))
def run(self):
print('{},今年{}岁,正在跑步'.format(self.name, self.age))
p3 = Person('王五', 11)
p3.eat('烤鸭') # 王五正在吃烤鸭
p3.run() # 王五,今年11岁,正在跑步
2.4.2 __new__(): 实例化 触发时机: 实例化对象时触发
参数: 至少一个cls接收当前类 返回值: 必须返回一个对象实例
实例化对象是Object类底层实现, 其他类继承了Object的__new__才能实现实例化对象。
先触发__new__才会触发__init__
class Person: def __init__(self): print('-----> init') def __new__(cls, *args, **kwargs): print('--->new') p = Person() print('p:',p) ''' --->new p: None # 未实例化对象, p 未指向地址 '''
def __new__(cls, *args, **kwargs): print('--->new') return object.__new__(cls, *args, **kwargs) ''' --->new # 先实例化 -----> init # 后初始化 p: <__main__.Person object at 0x000000B66357AFA0> '''
def __new__(cls, *args, **kwargs): print('--->new') # return object.__new__(cls, *args, **kwargs) return super(Person, cls).__new__(cls, *args, **kwargs) # 正确
def __new__(cls, name): print('--->new') return super(Person, cls).__new__(cls, name) TypeError: object.__new__() takes exactly one argument (the type to instantiate) --->new
class Person:
def __init__(self, name):
print('-----> init')
self.name = name
def __new__(cls, *args, **kwargs):
print('--->new')
pos = object.__new__(cls) # 申请开辟内存空间0x8183A7BFA0, 然后返回给 __init__的 self,进行初始化
print(pos)
return pos
p = Person('Jack') # --->new
print(p) # None
print(p.name) # Jack
'''
--->new
<__main__.Person object at 0x0000008183A7BFA0>
-----> init
<__main__.Person object at 0x0000008183A7BFA0>
'''
2.4.3 __call__: 对象调用方法, p() / p(param)
触发时机: 将对象当成函数使用时,默认调用此函数中内容
class Person:
def __init__(self, name):
print('-----> init')
self.name = name
def __new__(cls, *args, **kwargs):
print('--->new')
pos = object.__new__(cls)
print(pos)
return pos
def __call__(self, name):
print('----> call')
print('执行对象得到参数为', name)
p = Person('Luck')
print(p.name)
p('aaa')
'''
--->new
<__main__.Person object at 0x00000040DD9BBFA0>
-----> init
Luck
----> call
执行对象得到参数为 aaa
'''
2.4.4 __del__ 删除对象
当一块空间没有了任何引用,默认执行__del__
python解释器,回收所有在本次执行过程中使用到的空间。Python底层自带垃圾回收,进行内存释放。
import sys
class Person:
def __init__(self, name):
self.name = name
def __del__(self):
print('删除对象了')
p = Person('abc')
p1 = p
p2 = p
print(p1.name) # abc
print(p2.name) # abc
print(sys.getrefcount(p)) # 4 / p, p1, p2, sys 四个引用, 指向同一个地址
p1.name = 'tom'
print(p.name) # tom
print(p2.name) # tom
del p2 # 删除p2 对地址的引用
print(p.name) # tom
print(sys.getrefcount(p)) # 3 \n 删除对象了
2.4.5 __str__: 单纯打印对象名称,打印的是地址。
触发时机: 打印对象名称时, 自动触发去调用__str__里面的内容。
在__str__方法中添加return, return 后面的内容是打印对象输出的内容。
class Teacher:
def __init__(self, name):
self.name = name
def __str__(self):
# print('对象str:', self.name)
return '对象str: {}'.format(self.name)
t = Teacher('tt')
print(t) # 对象str: tt