#面向对象
class Tortoise:
    bodyColor = "绿色"
    footNum = 4
    weight = 10
    hasShell = True
    #会爬
    def crawl(self):
        print("乌龟会爬")
    #会吃东西
    def eat(self):
        print("乌龟会吃东西")
    #会睡觉
    def sleep(self):
        print("乌龟会睡觉")

class Person :
    name = "lisi"
    age = 18
    def __init__(self,name,age):
        self.name = name  #若没有这行,对象.name将返回类变量lisi
        self.age = age    #若没有这行,对象.age将返回类变量18
        print("创建实例!这个人的名字是:",name,"年龄为:",age)
    def say(self,content):
        print(content)

p1 = Person("梦竹",23)   #创建类对象
print(p1.name,p1.age)    #调用实例变量,查询
p1.name = "给队友一个助攻"         #实例变量赋值,修改
p1.say("我又选择了螳螂") #调用方法
print(p1.name,p1.age)
p1.skills = ["swimming","programming"] #增加实例变量
print(p1.skills)
# del p1.name                    #删除实例变量

#为对象动态添加方法,方法只对该对象有效
def info(self):                #定义一个函数
    print("--info函数--",self)
p1.foo = info                  #将该函数赋值给p1的foo方法
p1.foo(p1)                     #手动为第一个参数传入参数值
#使用lambda为对象动态添加方法
p1.bar = lambda self : print("--info函数--",self)
p1.bar(222)                     #手动为第一个参数传入参数值
#助于 types 模块下的 MethodType ,
def intro_func(self, content):
    print("我是%s ,信息为:%s" % (self.name,content))
from types import MethodType   # 导入MethodType
p1.intro = MethodType(intro_func, p1) # 使用MethodType对intro_func进行包装,将该函数的第一个参数绑定为p1
p1.intro("生活在别处") # 第一个参数已经绑定了,无需传入
print(type(p1))

#为类添加方法   __slots__ 限制了能动态添加的是属性名和方法名
class Dog:
    __slots__ = ('walk', 'age', 'name')
    def __init__(self, name):
        self.name = name
    def test(self):
        print('预先定义的test方法')
def walk_func(self):
    print('%s慢慢地走过一片草地' % self.name)
d1 = Dog('Snoopy')   #创建
d2 = Dog('Snoopy2')
d1.age = 5
Dog.walk = walk_func
d1.test()
d1.walk()
d2.walk()

#self
class ReturnSelf :
    def grow(self):
        if hasattr(self, 'age'):
            self.age += 1
        else:
            self.age = 1
        # return self返回调用该方法的对象
        return self
rs = ReturnSelf()
# 可以连续调用同一个方法
rs.grow().grow().grow()
print("rs的age属性值是:", rs.age)

#类方法/静态方法
class Bird:
    @classmethod    # @classmethod 修饰的方法是类方法 fly
    def fly(cls):
        print('类方法fly:',cls)
Bird.fly()   #调用类方法

class Bird:
    @staticmethod    # @staticmethod 修饰的方法是静态方法 fly
    def fly(p):
        print('静态方法fly:',p)
Bird.fly()  # fly不是类方法,不能直接调
Bird.fly("类名")   #调用静态方法
bird = Bird()
bird.fly("类对象")  #对象调用静态方法

#类中需要定义get del set等操作
class Rectangle:
    # 定义构造方法
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setsize()函数
    def setsize (self , size):
        self.width, self.height = size
    # 定义getsize()函数
    def getsize (self):
        return self.width, self.height
     # 定义delsize()函数
    def delsize (self):
        self.width, self.height = 0, 0
rect = Rectangle(3 , 4)
rect.setsize((6,8))
print(rect.getsize())
#使用property()
class Rectangle:
    # 定义构造方法
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setsize()函数
    def setsize (self , size):
        self.width, self.height = size
    # 定义getsize()函数
    def getsize (self):
        return self.width, self.height
     # 定义getsize()函数
    def delsize (self):
        self.width, self.height = 0, 0
    # 使用property定义属性
    size = property(getsize, setsize, delsize, '用于描述矩形大小的属性') # 访问size属性的说明文档
print(Rectangle.size.__doc__)
# 通过内置的help()函数查看Rectangle.size的说明文档
help(Rectangle.size)
rect = Rectangle(4, 3) # 创建实例
print(rect.size)       # (4, 3)
rect.size = 9, 7       #  对rect的size属性赋值
print(rect.width) # 9  # 访问rect的width、height实例变量
print(rect.height) # 7 # 访问rect的width、height实例变量
del rect.size          # 删除rect的size属性
print(rect.width) # 0  # 访问rect的width、height实例变量
print(rect.height) # 0
####所有的get del set 都用对象.size 来操作

#封装
#将__hide,__name,__age 隐藏起来,只能使用property的name和age,就是调用setname等
class User :
    def __hide(self):
        print('示范隐藏的hide方法')
    def getname(self):
        return self.__name
    def setname(self, name):
        if len(name) < 3 or len(name) > 8:
            raise ValueError('用户名长度必须在3~8之间')
        self.__name = name
    name = property(getname, setname)
    def setage(self, age):
        if age < 18 or age > 70:
            raise ValueError('用户名年龄必须在18在70之间')
        self.__age = age
    def getage(self):
        return self.__age
    age = property(getage, setage)
# 创建User对象
u = User()
u.name = 'fkit'# 对name属性赋值,实际上调用setname()方法
u.age = 25
print(u.name) # fkit
print(u.age) # 25
#u.__name 调不到,u._User__name可以绕过隐藏

#继承
class Fruit:
    def info(self):
        print("我是一个水果!重%g克" % self.weight)
class Food:
    def taste(self):
        print("不同食物的口感不同")
class Apple(Fruit, Food):     # 定义Apple类,继承了Fruit和Food类
    pass
a = Apple()   # 创建Apple对象
a.weight = 5.6   #添加了一个实例变量
a.info()      # 调用Apple对象的info()方法
a.taste()     # 调用Apple对象的taste()方法
#重写父类方法
class Bird:
    def fly(self):
        print("我在天空里自由自在地飞翔...")
class Ostrich(Bird):
    def fly(self):
        print("我只能在地上奔跑...")         # 重写Bird类的fly()方法,方法覆盖
    def foo(self):
        Bird.fly(self)
os = Ostrich()  # 创建Ostrich对象
os.fly()        # 执行Ostrich对象的fly()方法,调用的是子类重写的方法,子类的方法覆盖了父类的方法
os.foo()        #调用父类被重写的方法
Bird.fly(os)     #调用父类被重写的方法
#super() 多父类,构造方法重写
class Employee :
    def __init__ (self, salary):
        self.salary = salary
    def work (self):
        print('普通员工正在写代码,工资是:', self.salary)
class Customer:
    def __init__ (self, favorite, address):
        self.favorite = favorite
        self.address = address
    def info (self):
        print('我是一个顾客,我的爱好是: %s,地址是%s' % (self.favorite, self.address))
class Manager(Employee, Customer):                      # Manager继承了Employee、Customer
    def __init__(self, salary, favorite, address):      # 重写父类的构造方法
        print('--Manager的构造方法--')
        super().__init__(salary)                                # 通过super()函数调用父类的构造方法
        #super(Manager, self).__init__(salary)
        # 使用未绑定方法调用父类的构造方法
        Customer.__init__(self, favorite, address)
# 创建Manager对象
m = Manager(25000, 'IT产品', '广州')
m.work()  #
m.info()  #

#type
class Role:
    pass
r = Role()
print(type(r))    # <class '__main__.Role'>  对象类型显示为  __main__.类名
print(type(Role)) # <class 'type'>           类的类型为type

#特殊方法hasattr getattr  setattr  isinstance
class Comment:
    def __init__(self, detail, view_times):
        self.detail = detail
        self.view_times = view_times
    def info():
        print("一条简单的评论,内容是%s" % self.detail)
c = Comment('疯狂Python讲义很不错', 20)
print(hasattr(c, 'detail'))  # True # 判断是否包含指定的属性或方法
print(getattr(c, 'detail'))  # '疯狂Python讲义很不错' # 获取指定属性的属性值
setattr(c, 'detail', '天气不错') # 为指定属性设置属性值
isinstance(c, Comment)
issubclass(Manager,Employee)