从入门到入狱------面向对象(二)


class Student:
    def __init__(self, name, tel, study_id='001', score=0):
        self.name = name
        self.tel = tel
        self.study_id = study_id
        self.score = score

    # 在打印一个对象的时候,系统会自动用这个对象去调用__repr__方法,并且获取这个方法的返回值
    # 返回值是什么就打印什么(返回值必须是字符串)
    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}>'


#   __dict__将对象转换成字典
stu1 = Student('小王', 123456, '0001', 1)
stu2 = Student('小林', 22222, '0002', 12)
print(stu1)  # <'name': '小王', 'tel': 123456, 'study_id': '0001', 'score': 1>

# 对象属性的增删改查
# 查---获取对象的属性值
'''
对象.属性
getattr(对象,属性名) 可以做到动态获取属性值
'''
print(stu1.name)  # 小王

# value=input('请输入要获取的属性名:')
# print(getattr(stu2,value)) # value="name"  小林  value="tel" 22222
print(getattr(stu2, 'height', 180))  # 180 获取不存在的属性如果不给默认值会报错,

# 增/改
'''
对象.属性=值  属性存在的时候就是修改,属性不存在的时候就是增加
setattr(对象,属性名,值) 可以做到动态增加/修改属性值
'''
stu1.name = '我不是小王'
stu1.height = '新添加的属性:身高170'
print(stu1)  # <'name': '我不是小王', 'tel': 123456, 'study_id': '0001', 'score': 1, 'height': '新添加的属性:身高170'>
setattr(stu1, 'name', '我还是小王')
print(stu1)  # <'name': '我还是小王', 'tel': 123456, 'study_id': '0001', 'score': 1, 'height': '新添加的属性:身高170'>

# 删
'''
del 对象.属性   删除属性
del 对象       删除对象

delattr(对象,属性名)
'''
del stu1.height
print(stu1)  # <'name': '我还是小王', 'tel': 123456, 'study_id': '0001', 'score': 1>
delattr(stu1, 'study_id')
print(stu1)  # <'name': '我还是小王', 'tel': 123456, 'score': 1>

对象方法:

定义:直接定义
调用:对象.方法名()
特点:有个默认参数self,这个参数在调用的时候不用传参,系统会自动将当前对象传给self
使用:如果实现函数的功能需要用到对象,那么这个函数就定义成对象方法

类方法:

定义:在定义函数前加@classmethod
调用:类.方法名()
特点:有个默认参数cls,这个参数在调用的时候不用传参,系统会自动将当前类传给cls
使用:如果实现函数的功能不需要对象需要用到类,那么这个函数就定义成类方法

静态方法

定义:在定义函数前加@staticmethod
调用:类.方法名()
特点:没有默认参数
使用:实现函数功能不需要对象也不需要类的前提下就定义静态方法

class Student:
    # func1是对象方法
    def func1(self):
        print('对象方法')

    # func2是类方法
    @classmethod
    def func2(cls):
        print('cls:', cls)  # cls:<class '__main__.Student'>

    # 当前类能做的,cls都可以做

    # func3是静态方法
    @staticmethod
    def func3():
        print('静态方法')


print('Student:', Student)  # Student: <class '__main__.Student'>
class Person:
    """
    人类
    """
    num = 61

    def __init__(self, name='张三', age=18, gender='男'):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self, food='面条'):
        print(f'{self.name}在吃{food}')

    @classmethod
    def message(cls):
        print(f'人类目前的数量是:{cls.num}')

    @staticmethod
    def destroy():
        print('人类破坏环境')


p1 = Person()
# 类属性
'''
类名.__doc__    获取类的说明文档
print(Person.__doc__)    # 人类

类名.__module__  获取指定类所在的模块 如果结果是__main__  说明是当前模块
print(Person.__module__)  # __main__
print(list.__module__)  # builtins

对象.__class__   获取指定对象对应的类型,和type(对象)功能一样
print(p1.__class__)  # <class '__main__.Person'>
print(type(p1))  # <class '__main__.Person'>

类名.__name__    获取类名类型为str
print(Person.__name__) # 'Person'
print(int.__name__) # 'int'

类名.__dict__   获取类所有的字段和字段值,转化为字典,key是字段名,value是字段的值
print(Person.__dict__)
对象.__dict__   获取对象所有的属性和属性值,转化为字典,key是属性名,value是属性的值
print(p1.__dict__)  # {'name': '张三', 'age': 18, 'gender': '男'}

类名.__base__  获取指定类的父类
类名.__bases__ 获取类所有的父类
object是python中所有类的基类
print(Person.__base__)   # <class 'object'>
print(Person.__bases__)  # (<class 'object'>,)


'''

# 根据数据不同的类型创建以该类型名命名的文件
datas = ['abc', -0.1234, '你好', 564]
for data in datas:
    with open(rf'files\{data.__class__.__name__}.txt', 'a', encoding='utf-8') as f:
        f.write(str(data) + '\n')

getter

使用:在获取对象属性前,如果要做别的什么事就可以给这个属性添加getter
用法:
在需要添加getter的属性名前加_
在装饰器@property后面定义一个函数,函数名就是属性名去掉_
函数没有参数,但是需要一个返回值,返回值就是获取属性值得到的结果
通过对象获取属性的时候,属性不需要带_

class Circle:
    pi = 3.14

    def __init__(self, r=10):
        self.r = r

    @property
    def area(self):
        return Circle.pi * self.r ** 2


c1 = Circle(100)
print(c1.area)

练习,给Person添加属性,要求:age中保存年龄值,但是获取age属性的时候
得到的是:儿童(0-4),少年(5-12),青年(13-28),壮年(29-40)中年(41-55),老年(55以上)

class Person:
    def __init__(self, age=0, name='张三', gender='男'):
        self.name = name
        self._age = age
        self.gender = gender

    @property
    def age(self):
        if 0 <= self._age <= 4:
            return '儿童'
        elif 5 <= self._age <= 12:
            return '少年'
        elif 13 <= self._age <= 28:
            return '青年'
        elif 29 <= self._age <= 40:
            return '中年'
        else:
            return '老年'

setter —添加之前必须添加getter

给对象属性赋值的之前做别的事情,就给这个属性添加setter
用法
在装饰器 @函数名.setter 后面定义一个函数,函数名就是属性名去掉_
函数有且只有一个参数(这个参数指向的是赋值的时候赋的值)

 @age.setter
 def age(self, value):
     print(value)
     if type(value) != int:
         raise ValueError
     if value < 0 or value > 150:
         raise ValueError


p1 = Person()

# p1.age='dwa'  ValueError
# p1.age=151    ValueError

访问权限

公开的:公开的属性和方法在类的内部外部都能用,并且可以被继承
保护的:保护的属性和方法在类的内部可以使用,外部不能用,但是可以继承
私有的:私有的属性和方法在类的内部可以使用,外部不能用,不能被继承

python中的属性和方法只有访问权限:公开的
python 所谓的私有化只是一种说明提示

私有化的方法:
在属性名和方法名前加__(只能是两个__开头,不能再__结尾)

class Person:
    num = 100
    __info = '动物'

    def __init__(self, name='张三', age=18, gender='男'):
        self.name = name
        self.age = age
        self.gender = gender

    def func1(self):
        return Person.__info

    def __func2(self):
        return Person.num


p1 = Person()
print(p1.func1())  # 动物
print(Person.num)  # 100
# print(Person.__info) # AttributeError: type object 'Person' has no attribute '__info'
# print(p1.func2()) # AttributeError: 'Person' object has no attribute 'func2'
# print(Person._Person__info) # 动物 强行查看

运算符

python在使用运算符的时候,本质是在调用运算符对应的方法
每个运算符对应的方法的方法名是固定的,不同类型的数据在参与相同运算的时候
会调用不同类中对应方法

某个类型的数据是否支持某种运算,就看这个数据对应的类型中有没有实现这个运算符对应的方法

# __add__
class Person:
    def __init__(self, age=0, name='?', gender='男'):
        self.name = name
        self._age = age
        self.gender = gender
    #self指向+前面的数据,other指向+后面的数据
    def __add__(self, other):
        return self.name + other.name

    def __mul__(self, other):
        return [self.name for _ in range(len(other.name))]

    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}>'

    def __gt__(self, other1):
        return self._age>other1._age

p1 = Person(56,'王五','男')
p2 = Person(1, "小花",'女')
print(p1 + p2)  # 张三李四 本质是:pi.__add__(p2)
print(p1 * p2)  # ['张三', '张三'] 本质是:pi.__mul__(p2)

# 练习 根据年龄排序
p3=Person(20,'张三','男')
p4=Person(25,'老王','男')
# 方法一 重载 > 运算符
ps=[p1,p2,p3,p4]
print(sorted(ps))

# 方法二 实参高阶函数
ps.sort(key=lambda item :item._age)
print(ps)

猜你喜欢

转载自blog.csdn.net/weixin_44628421/article/details/109235545