2018-09-07类和对象2(day15)

一、内置类属性

内置类属性就是魔法属性

  • 魔法属性:属性名的前面和后面都有两个下划线
  • 魔法方法:方法的前后都有两个下划线
class Person:
    '''人类''' #类的说明文档
    # 类的字段
    number = 61
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height
    def __trunc__(self):
        print('%s在跑步'%self.name)

    # 类方法
    @classmethod
    def show_number(cls):
        print('人类的数量为:%d亿'%cls.number)

    # 静态方法
    @staticmethod
    def destroy():
        print('人类在破坏环境!')

if __name__ == '__main__':
    p1 = Person('张三',23,179)
    # 1.__name__属性 ---类的名字(是个字符串)
    name = Person.__name__
    print(name,type(name),type(Person))
    # Person    

    # 2.__class__属性 --- 获取对象对应的类(是一个类)
    # 对象的属性
    # my_class是一个类,之前类能做的事他都能做
    my_class = p1.__class__
    p2 = my_class('张三',20,200)
    print(p2.name,my_class.__name__)
    # 张三 Person

    # 3.__dict__属性 --- 将对象和类的属性及其对应的值转换成键值对存到一个字典中
    # print(Person.__dict__)
    print(p1.__dict__)
    # {'name': '张三', 'age': 23, 'height': 179}
    # 4.__doc__属性  ---获取类的说明文档
    # 类的属性
    doc = Person.__doc__
    print(doc)
    # 人类
    # 5.__module__属性 --- 获取类所在的模块对应的名字
    print(Person.__module__)
    # __main__
    # 6.__bases__属性 --- 获取当前类的父类
    # 类的属性
    print(Person.__bases__)
    #(,)

二、__ slots __魔法

  • 通过__ slots __中存的元素的属性的值来约束当前这个类的对象的属性。对象的属性只能比元祖中的元素少,不能多!
  • 注意:一旦在类中给__ slots __ 属性赋了值,那么这个类的对象的__ dict __属性就不能使用了
class Person:

    # 通过__slots__中存的元素的属性的值来约束当前这个类的对象的属性。对象的属性只能比元祖中的元素少,不能多!
    __slots__ = ('name', 'age', 'face')

    def __init__(self):
        self.name = '张三'
        self.age = 18
        self.face = 70
        # self.sex = 'boy'  # __slots__中并没有sex


if __name__ == '__main__':
    p1 = Person()
    # p1.sex = 'girl'
    # print(p1.sex)

    # p1.neme = '小明'
    print(p1.name)

    # 注意:一旦在类中给__slots__属性赋了值,那么这个类的对象的__dict__属性就不能使用了
    # print(p1.__dict__)

三、属性的私有化

python中并没有真正的私有化!
python类中默认的属性和方法都是公开的

1.私有化
  • a.类中的属性和方法都可以通过在属性名和方法名前加两个下划线,来让属性和方法变成私有的
  • b.私有的属性和方法只能在当前的类中使用
2.私有化原理
  • 在前面有两个下划线的属性名和方法名前添加'_类名'来阻止外部通过直接访问属性名来使用属性
class Dog:
    # 字段
    number = 100
    __count = 10

    def __init__(self):
        # 对象的属性
        self.color = '黄色'
        self.age = 3
        self.name = '大黄'
        self.__sex = '母的'

    # 对象方法
    def eat(self):
        print('%s在吃屎~'%self.name)

    # 类方法
    @classmethod
    def shout(cls):
        print(cls.__count)
        print('汪汪汪~~~')

    # 静态方法
    @staticmethod
    def function():
        print('看家!!')

dog1 = Dog()
print(Dog.number)  # 100
print(dog1.name,dog1.color,dog1.age) # 大黄 黄色 3
dog1.eat()  #10
Dog.shout() # 汪汪汪~~~
Dog.function() # 看家

# 在类的外面不能直接使用私有的属性
# print(Dog.__count)  AttributeError
# print(dog1.__sex)   AttributeError
print(dog1._Dog__sex) # 母的
print(dog1.__dict__)
# {'color': '黄色', 'age': 3, 'name': '大黄', '_Dog__sex': '母的'}

四、属性的getter和setter

1.保护类型的属性
  • a.就是在声明在对象属性的时候在属性名前加一个下划线来代表这个属性是受保护的属性。
    那么以后访问这个属性的时候就不要直接访问,要通过getter来获取这个属性的值,setter来给这个属性赋值
  • b.如果一个属性已经声明成保护类型的属性,那么我们就需要给这个属性添加getter。也可以添加setter
2.添加getter
  • 添加getter其实就是声明一个没有参数有一个返回值的函数。作用是获取属性的值
  • a.格式:
    @property
    def 去掉下滑线的属性名(self):
    函数体
    将属性相关的值返回
  • b.使用场景
    场景一:如果想要获取对象的某个属性的值之前,想要再干点儿别的事情(做额外的处理)。就可以给这个属性添加getter
    场景二:想要拿到某个属性被使用的时刻
3.添加setter
  • a.格式 @XXXX属性.setter
  • b.使用场景
    在给属性赋值前想要再干点儿别的事情,就给属性添加setter
class Car:
    def __init__(self):
        self.color = '黄色'
        self.type = '自行车'
        # _price属性是保护类型
        self._price = 2000

    # 给_price属性添加getter
    @property
    def price(self):
        print('在使用_price属性')
        return self._price/1000

    # 想要给一个属性添加setter,必须先给这个属性添加getter
    @price.setter
    def price(self, price):
        if isinstance(price, int) or isinstance(price, float):
            self._price = price
        else:
            self._price = 0

# 练习:声明一个员工类,其中有一个属性是是否已婚(bool),获取值之前根据存的值返回'已婚'/'未婚'
class Staff:

    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        self._is_marry = False

    @property
    def is_marry(self):
        if self._is_marry:
            return '已婚'
        return '未婚'

    @is_marry.setter
    def is_marry(self, marry):
        self._is_marry = marry


staff1 = Staff('张三', 10000)
print(staff1.is_marry)  # 未婚

staff1.is_marry = True
print(staff1.is_marry) # 已婚


if __name__ == '__main__':

    car1 = Car()
    print(car1.color) # 黄色

    # 添加完getter后就通过getter去获取属性的值
    # price就是属性_price的getter
    print(car1.price,'k')  # 实质是在调用getter对应的方法
    print(car1.price,'k') # 2.0K

    # 通过setter给_prince属性赋值。实质是在调用setter对应的方法
    car1.price = 1000
    print(car1.price) # 1.0K

    car1.price = 'abc'
    print(car1.price)  #0.0

五、继承

  • python中类可以继承,并且支持多继承。
  • 程序中的继承:就是让子类直接拥有父类的属性和方法(继承后父类中的内容不会因为被继承而减少)
1.继承的语法
  • class 子类(父类):
    类的内容
  • 注意:如果声明类的时候没有写继承,那么这个类会自动继承python的基类,object;相当于class 类名(object):
    python中所有类都是直接或者间接的继承自object

2.能继承哪些东西

  • a.所有的属性和方法都能继承
  • b.__ slots __ 的值不会继承,但是会影响子类对象的__ dict __属性。不能获取到父类继承下来的属性
class Person(object):
    """人类"""
    # 字段
    numer = 61

    # __slots__ = ('name', 'age')
    # 对象属性
    def __init__(self, name1='张三', age1=18):
        self.name = name1
        self.age = age1
        self.__height = 160

    # 对象方法
    def show_message(self):
        print('姓名:%s 年龄:%d' % (self.name, self.age))

    # 类方法
    @classmethod
    def show_number(cls):
        print('人类的数量:%d' % cls.numer)

    # 静态方法
    @staticmethod
    def complaint():
        print('人类殴打小动物!')


class Student(Person):
    """学生类"""
    pass


# 创建Person类的对象
p = Person()
# p.sex = 'boy'
# print(p.__dict__)

# 创建Student类的对象
stu1 = Student()

print(Student.numer) # 61
stu1.name = '李四'
print(stu1.name) # 李四
stu1.show_message() # 姓名:李四 年龄:18
Student.show_number() # 人类的数量61
Student.complaint() # 人类殴打小动物!

stu1.sex = 'girl'
print(stu1.__dict__)
# {'name': '李四', 'age': 18, '_Person__height': 160, 'sex': 'girl'}

六、方法的重写

子类继承父类,拥有父类的属性和方法,还可以添加自己的属性和方法

1.添加方法和类的字段
  • 直接在子类中声明相应的方法
2.添加对象属性
  • 对象的属性是通过继承弗雷的init方法而继承下来的
  • 如果想要在保留父类的对象的同时添加自己的对象属性,需要在子类的init方法中通过super()去调用父类的init方法
3.方法的重写
  • 在子类中重写实现父类的方法就还是重写
  • 方式1:直接覆盖父类的实现
  • 方式2:保留父类的功能再添加其他功能
4.类中方法的调用过程
  • 先在当前这个中的去找,找不到就去父类中找。。。。

  • 在第一次找到的位置,去调用

  • 注意:使用super的时候必须要通过super()来代替父类或者父类对象

class Animal:
    number = 100

    def __init__(self):
        self.age = 0
        self.sex = '雌'

    def shout(self):
        print('嗷嗷叫')

class Cat(Animal):

    def __init__(self):
        # 调用父类的init方法
        super().__init__()
        self.name = '小花'

    food = '鱼'

    def shout(self):
        print(super()) # , >
        print('喵喵') # 喵喵
        print('+++++++++++++++++++++++++++++++++++++++')
    @classmethod
    def run(cls):
        print(Animal.number)   #100
        print(super().number) #100
        print(super()) # , >

Cat.run()

print('=================================')
class Dog(Animal):
    def shout(self):
        # 通过super()调用父类的方法,保留父类的功能
        super().shout() #  直接赋值
        print('汪汪')

cat1 = Cat()
dog1 = Dog()
print(cat1.age) # 0
print(cat1.name) # 小花
cat1.shout() # 嗷嗷叫
dog1.shout() # 汪汪

七、init方法的重写练习

# 练习:写一个Person类,拥有属性name,age,sex。要求创建Person对象的时候必须给name和age赋值,sex可赋可不赋
#      在写一个staff类继承自Person类,要求保留Person中所有的属性,并且添加新的属性salary
#      要求创建staff类的对象的时候,只能给name赋值(必须)

class Person:
    def __init__(self,name,age,sex = 'boy'):
        self.name = name
        self.age = age
        self.sex = sex
class Staff(Person):
    def __init__(self,name):
        super().__init__(name,20)
        self.salary = 0

if __name__ == '__main__':
    p1 = Person('李涵','23','girl')
    p2 = Person('魏世强','23','boy')
    s1 = Staff('王龙')

八、运算符的重载

  • 如果希望类的对象支持相应的运算符操作(例如:+, -, *, /, >, <等),就必须实现相应的魔法方法

  • 这个过程就叫运算符的重载

  • +: __ add __()

  • .> __ gt __()

  • 一般情况需要对>或者<进行重载,重载后可以通过sort方法直接对对象的列表进行排序

class Student:
    def __init__(self, name='', age=0, score=0):
        self.name = name
        self.age = age
        self.score = score

    # self:+前面的对象
    # other: +后面的对象
    def __add__(self, other):
        return self.score + other.score

    # 重载 > 符号
    # 注意:重载>和<可以只重载一个,另外一个对应的功能自动取反
    def __gt__(self, other):
        return self.age > other.age

    # 重写魔法方法__str__,用来定制对象的打印样式
    def __str__(self):
        # return '<%s.%s object at 0x%x>' % (self.__module__, self.__class__.__name__, id(self))
        # return 'Student: %s %d %d' % (self.name, self.age, self.score)
        return str(self.__dict__)[1:-1]

class Schoolchild(Student):
    def __add__(self, other):
        return self.age + other.age


if __name__ == '__main__':

    stu1 = Student('小明', 18, 90)
    stu2 = Student('老王', 29, 84)
    stu3 = Student('小花', 20, 78)

    print(stu1)  # 'name': '小明', 'age': 18, 'score': 90

    all_students = [stu1, stu2, stu3]
    all_students.sort(reverse=True)
    for stu in all_students:
        print(stu.name, stu.age, stu.score)  # 老王 29 84 ; 小花 20 78 ; 小明 18 90


    print(stu1 > stu2) # False
    print(stu1 < stu2) # True
    print(stu1 + stu2) # 174
    print(stu3 > stu1) # True

    # 父类重载了运算符,子类也能用
    c1 = Schoolchild('小明明', 8, 70)
    c2 = Schoolchild('小花花', 10, 67)
    print(c1+c2) # 18

你可能感兴趣的:(2018-09-07类和对象2(day15))