python面向对象-01

面向过程和面向对象的区别:

在这里插入图片描述

类的作用:

在这里插入图片描述

类的组成:

在这里插入图片描述

根据类创建对象的底层原理:

左边的Money和one都是变量名

在这里插入图片描述

属性和变量的区别:

在这里插入图片描述

python查找机制:

在这里插入图片描述

删除(不是对象)的属性:

包括修改类的属性也是不能通过对象进行修改,相当于类是类的属性,对象是对象的属性

在这里插入图片描述

class Money:
    age = 15

one = Money()
del one.age # 报错,因为one是对象,不能直接删除类的属性的

one.age += 5	# one.age = one.age + 5(右边one.age显示Money中的属性age=15,加完后新增one对象的属性age)
print(one.age) # 15
print(Money.age) # 10
__dict__对于类和对象的区别:

在这里插入图片描述

class Money:
    age = 15

one = Money()
one.__dict__["name"] = 'psj'
print(one.__dict__) # 不会报错,对象可以直接修改__dict__
Money.__dict__['name'] = 'psw'
print(Money.__dict__) # 报错,类不能直接对__dict__进行修改
限制对象属性添加:
class Person:
    __slots__ = ["age", "sex"] 	# 列表形式
    pass
p1 = Person()
p1.age = 20
p1.sex = "male"
p1.height = 180 # 此处注意上面没写这个height,结果会报错显示没有属性height
方法的划分:

在这里插入图片描述

class Money:
    # 第一个参数self是一个实例
    def shilifangfa(self):
        print("这是一个实例方法", self)
	# 第一个参数cls是一个类
    @classmethod
    def leifangfa(cls):
        print("这是一个类方法", cls)

    @staticmethod
    def jingtaifangfa():
        print("这是一个静态方法")
        
m = Money()
# 下面两个输出值一样
m.shilifangfa() # 这是一个实例方法 <__main__.Money object at 0x0000027FBFB94C70>
print(m)	# <__main__.Money object at 0x0000027FBFB94C70>
Money.leifangfa()	# 这是一个类方法 <class '__main__.Money'>
Money.jingtaifangfa()	# 这是一个静态方法
print(m.__dict__) # {} 对应了图中注意中的第二点,方法都是存储在类中的,没有存储在实例中的
print(Money.__dict__) # {'__module__': '__main__', 'shilifangfa': <function Money.shilifangfa at 0x0000020986D8F280>, 'leifangfa': <classmethod object at 0x0000020986FF0CD0>, 'jingtaifangfa': <staticmethod object at 0x0000020988CE4A90>, '__dict__': <attribute '__dict__' of 'Money' objects>, '__weakref__': <attribute '__weakref__' of 'Money' objects>, '__doc__': None}
实例方法:
class Money:
    def shilifangfa(self):
        print("这是一个实例方法", self)
	# 报错,这是静态方法的形式,需要加上@staticmethod
    def fangfa():
        print("test")

tips:根据场景不同选择定义实例方法还是类方法,比如:

l = [1,2,3]
l.sort(就两个参数,不需要list)	# 使用实例方法
list.sort(list对象,后面还要两个参数)
类方法:
class Money:
    @classmethod
    def leifangfa(cls):
        print("这是一个类方法", cls)

Money.leifangfa()	# 这是一个类方法 <class '__main__.Money'>
# 另一种调用方式
p = Money.leifangfa	
p()	# 这是一个类方法 <class '__main__.Money'>
# The instance is ignored except for its class(实例被类给忽略了)
a = Money()
a.leifangfa()	# 这是一个类方法 <class '__main__.Money'>
不同类型的方法访问不同的属性:
class Person:
    age = 0
    def shilifangfa(self):
        print(self)
        print(self.age)
        print(self.num)
    @classmethod
    def leifangfa(cls):
        print("这是一个类方法", cls)
        print(cls.age)
        print(cls.num)
    @staticmethod
    def jingtaifangfa():
        print("这是一个静态方法")
        
p = Person()
p.num = 10
p.shilifangfa() # 不会报错
p.leifangfa()	# 报错 type object 'Person' has no attribute 'num'
Person.leifangfa() # 同样报错 type object 'Person' has no attribute 'num'

tips:可以通过对象属性去找到类属性,但是不能通过类属性找到对象属性

元类:

在这里插入图片描述

class Person:
    pass
print(Person.__class__)	# type
print(int.__class__)	# type
类对象的创建方式:
# 自动在内存中创建类对象
class Person:
    num = 10

    def run(self):
        pass
p = Person()
    
# 手动调用type创建类对象
def run():
    pass
# 第一个参数是类名(左边的Person是引用对象的名字,相当于class Person的Person),第二个参数是基类,第三个是属性和方法
Person = type('Person', (), {'num': 10, 'run': run})
p1 = Person()
print(p1.__dict__) # {}
print(Person.__dict__)	# {'num': 10, 'run': <function run at 0x000001B7D4A363A0>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
类对象的创建(元类的查找机制):

在这里插入图片描述

在这里插入图片描述

__metaclass__ = xxx 	# 模块的(没有就找内置的type)
def Animal:
    __metaclass__ = xxx		# 父类的(没有就找模块的)
    pass
def Dog(Animal):
    __metaclass__ = xxx		# 类中的(没有就找父类的)
    pass
受保护的属性:
class Animal:
    _x = 10
    def run(self):
        print(Animal._x)
        print(self._x)
class Dog(Animal):
    def run(self):
        print(Dog._x)
        print(self._x)
# 测试类内部是否正常访问(可以)
a = Animal()
a.run()
# 测试子类内部是否正常访问(可以)
b = Dog()
b.run()
# 测试模块内是否正常访问(可以)
print(Animal._x)
print(Dog._x)
print(a._x)
print(b._x)
# 测试跨模块是否正常访问
_a = 111
__all__ = ['_a']	

在另一个py文件中(上面的文件名为test.py):

from test import *
print(_a)	# 不在test.py中加入__all__ = ['_a']就报错

import test
print(test._a)	# 没问题,但是有警告
私有属性:
class Animal:
    __x = 10
    def run(self):
        print(Animal.__x)
        print(self.__x)
class Dog(Animal):
    def run(self):
        print(Dog.__x)
        print(self.__x)

# 测试类内部是否正常访问(可以)
a = Animal()
a.run()
# 测试子类内部是否正常访问(不行)
b = Dog()
b.run()
# 测试模块内是否正常访问(不行)
print(Animal.__x)
print(Dog.__x)
print(a.__x)
print(b.__x)
# 测试跨模块是否正常访问
__all__ = ['_a']
_a = 111	# 与受保护的属性一样
私有(伪私有)属性的实现机制:

在这里插入图片描述

class Animal:
    __x = 10
    pass
print(Animal.__dict__)	#{'__module__': '__main__', '_Animal__x': 10, ...}
print(Animal._Animal__x)	# 可以输出
私有属性的应用场景:
class Animal:
    def __init__(self):
        self.__age = 10
    def setAge(self, value):
        self.__age = value
    def getAge(self):
        return self.__age

a = Animal()
print(a.__age)	# 访问不了,只能通过_Animal__age访问
print(a.getAge()) # 可以得到数值
变量添加下划线:
class_	#与类中的关键字进行区分
__x__	# 大部分为系统内置,尽量避免
只读属性:
# 方式1:通过双下划线进行全部隐藏,然后通过get方法部分可读
class Animal:
    def __init__(self):
        self.__age = 10
    def getAge(self):
        return self.__age

a = Animal()
print(a.__age)  # 报错
a.__age = 10
print(a.__age)  # 这个__age是实例属性,不是类属性了
print(a.getAge())   #成功输出

# 方式2:使用property,它可以以使用属性的方式使用该方法
class Animal:
    def __init__(self):
        self.__age = 10
    @property
    def getAge(self):
        return self.__age

a = Animal()
print(a.getAge)	# 成功输出
a.getAge = 666	# 报错,无法进行修改(下面使用property可以解决)
经典类和新式类:

在这里插入图片描述

property在新式类中的使用:
# 第一种使用方式
class Animal:
    def __init__(self):
        self.__age = 10
    def get_age(self):
        return self.__age
    def set_age(self, value):
        self.__age = value
    age = property(get_age, set_age)
a = Animal()
print(a.age)
a.age = 100	# 不是新增一个实例属性,而是在类属性上进行修改
print(a.age)
print(a.__dict__)	# {'_Animal__age': 100}

# 第二种使用方式
class Animal:
    def __init__(self):
        self.__age = 10
    @property
    def age(self):
        return self.__age
    @age.setter	# 这个age对应上面的函数名字
    def age(self, value):	# 这里函数名也为age是为规范
        self.__age = value
a = Animal()
print(a.age)
a.age = 100
print(a.age)
print(a.__dict__)

tips:property在经典类中只能关联读取方法,其他方法不能关联

常用内置属性:

在这里插入图片描述

私有方法:
class Animal:
    def __run(self):
        print('xxx')
	
a = Animal()
a.__run	# 和私有属性一样报错
# 直接定义转换后的方法,会覆盖之前的方法
class Animal:
    def __run(self):
        print('xxx')
    def _Animal__run(self):
        print('yyy')
a = Animal()
a._Animal__run()	# 打印yyy
print(Animal.__dict__)
内置特殊方法:
# 1.__str__方法
class Person:
    def __init__(self, age):
        self.age = age
    def __str__(self):
        return '年龄:%s'%str(self.age)
    def __repr__(self):
        return 'repr'
p = Person(18)
print(p)	# 年龄:18
# 2.__repr__方法:面向开发人员
print(repr(p))	# 当类没有实现__repr__函数时,会返回<__main__.Person object at 0x0000029C363A0DC0>
print(repr(p))	# 当类实现__repr__函数后会返回实现的函数的内容:'repr';当类没有实现__str__时,print(p)会调用__repr__
# 3.__call__方法:使得实例对象也可以像方法一样被调用
class Person:
    def __call__(self, *args, **kwargs):
        print(args,kwargs)

p = Person()
p(12,23,age=22)	# 不实现__call__方法直接执行会报错;(12, 23) {'age': 22}(前面两个参数被传入到args,后面带名称的参数传入kwargs形成字典)
# 场景实例
class PenFactory:
    def __init__(self, g_type):
        self.g_type = g_type
    def __call__(self, animal):
        print('使用%s画%s'%(self.g_type, animal))

p = PenFactory('钢笔')	
p('狗')	# 无需传入多个重复的参数'钢笔'
p('猫')
# 4.索引操作:可以以索引的形式操作对象,方法有__setitem__,__getitem__,__delitem__
class Person:
    def __init__(self):
        self.cache = {}
    def __setitem__(self, key, value):
        self.cache[key] = value
    def __getitem__(self, item):
        return self.cache[item]
    def __delitem__(self, key):
        del self.cache[key]

p = Person()
p['age'] = 10	# 如果没有索引操作__setitem__,这一步会报错
print(p['age'])	# 10
print(p.__dict__)   # {'cache': {'age': 10}}
# 5.比较操作:自定义方法去比较实例对象的大小,有__eq__,__lt__等等
class Person:
    def __init__(self, age, height):
        self.age = age
        self.height = height
    def __eq__(self, other):
        return self.age == other.age
	def __lt__(self, other):
		pass
p1 = Person(22, 180)
p2 = Person(22, 180)
print(p1 == p2)	# True.如果没有__eq__方法,则python3会报错,python2会比较两个对象的内存地址大小
print(p1 <= p2)	# 要判断小于等于,需要去分别实现__lt__和__eq__方法(或直接实现__le__方法)
# 也可以使用functools装饰器自动补全所有比较方法,但是前提要实现<,>,<=,>=至少其中一种方法
import functools
@functools.total_ordering
class Person:
    def __init__(self, age, height):
        self.age = age
        self.height = height
    def __lt__(self, other):
        
# 上下文bool值:__bool__方法
class Person:
    def __init__(self, age):
        self.age = age
    def __bool__(self):
        return self.age >= 18
p = Person(20)
if p:	# 如果没有实现__bool__方法,则if p恒为真
    print('成年')       
# 6.遍历操作:
# 方法1:__getitem__方法
class Person:
    def __init__(self):
        self.result = 1
    def __getitem__(self, item):	# 将返回的值给下面代码的i
        self.result += 1
        if self.result >= 10:
            raise StopIteration('停止遍历')
        return self.result
    pass
p = Person()
for i in p:
    print(i)	# 如果没有实现__getitem__方法,则对象是无法进行遍历的(即不属于迭代器,也不是可迭代对象)
# 方法2:__iter__方法和__next__方法
class Person:
    def __iter__(self):	# 1.将self变成一个迭代器
        return self
    def __next__(self):	# 2.一个迭代器需要有next方法(有next方法不一定是迭代器)
        return '传给i值'
p = Person()
for i in p:	# 3.__next__方法返回的值传给了i进行输出
    print(i)
import collections
print(isinstance(p,collections.Iterator))	# True,说明对象p已经是一个迭代器了(迭代器需要实现两个方法)
print(isinstance(p,collections.Iterable))	# True,但是只能说明p是一个可迭代对象(迭代对象只需要实现next方法)
描述器(data descriptors):

作用:接管一个类的增删改查操作;描述器是一个对象,这个对象里面有set,get,del方法;外界对类的属性进行操作时,会转而通过描述器对属性进行操作

方法1:参考’property在新式类中的使用’

方法2:创建一个描述器对象

# Age就是一个描述器
class Age:
    def __set__(self, instance, value):
        print('set')
    def __get__(self, instance, owner):
        print('get')
    def __del__(self):
        print('del')
class Person:
    age = Age()
p = Person()
p.age = 10

如果知道p.age调用的是描述器而不是类的age属性:

在这里插入图片描述

资料描述器(实现了get和set)>实例属性>非资料描述器(只实现了get)

# 此时为资料描述器
class Age:
    def __set__(self, instance, value):
        print('set')
    def __get__(self, instance, owner):
        print('get')
    def __del__(self):
        print('del')
class Person:
    def __init__(self):
        self.age = 10
    age = Age()
p = Person()
p.age = 10
print(p.age)
# 打印set set get None del.打印了两次set是因为此时的age是描述器不是属性age,所以在init方法中self.age=10执行一次描述器的set方法

tips:如果创建多个Person实例,描述器age对于每个实例是共享的

参考视频:https://www.bilibili.com/video/BV1A4411v7b2 (p1-p82)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值