python类学习

# 面向对象的分析(OOA,ObjectOriented Analysis)
# 面向对象的设计(OOD,Object Oriented Design)
# 面向对象的编程实现(OOP,Object Oriented Programming)


# def talkFunc(self):
#     print('hello %s' % self.name)
# # 初始化方法
# def __init__(self, name, age):
#     self.name = name
#     self.age = age
# # type('类名', '继承谁', '里面的方法')
# Foo = type('Foo', (object,), {'talk': talkFunc, '__init__': __init__})
# f = Foo('demo', '18')
# f.talk() # hello demo
# print(type(Foo)) # <class 'type'>

# 构造方法的名字为 __init__,第一个参数一定为 self,其他可以有 0 个或者任意多个 参数
# 以两个连续的下划线开始和两个连续的下划线结尾的函数都有特殊的含义
# 如果构造函数有参数,那么实例化时必须传入对应的参数
# class Student:
#     def __init__(self, name, age, score):
#         print("Name =", name, "Age =", age, "Score =", score)
#         self.name = name
#         self.age = age
#         self.score = score
#     def sayHello(self):
#         print("Hello ", self.name)
# stu = Student("Demo", 18, 99.8)
# stu.sayHello()
# 构造函数,跟普通函数 一样,也可以设置默认参数,如果设置了默认参数,那么在实例话实例时,可以不传该参数,而使用默认值
# class Student:
#     def __init__(self, name, age=99):
#         print("Name =", name, "Age =", age)
#     def sayHello(self):
#         print("Hello, Demo")
# stu = Student("demo")

# 类属性调用方法有两种,一种是通过 “类名.属性”,一种是通过 “对象.属性”
# class Student:
#     score = 99
#     def __init__(self):
#         print("Call init")
#
#
# print("Score =", Student.score)  # 99
# Student.score = 100
# print("Score =", Student.score)  # 100
# stu = Student()
# stu.score = 200
# print("Score =", Student.score)  # 100
# print("Score =", stu.score)  # 200

# 实例属性 nm和ag
# 实例属性只能通过 “实例.属性” 的方法来调用
# class Student:
#     score = 99.95
#     def __init__(self, name, age):
#         self.nm = name
#         self.ag = age
# stu = Student("Demo", 18)
# print("Name =", stu.nm, "Age =", stu.ag, "Score =", stu.score)

# 类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本
# 实例对象的属性为实例对象自己所私有
# class Student:
#     score = 99.95
#     def __init__(self, name, age):
#         print("Call init")
# stu = Student("Demo", 18)
# print("Name =", stu.name, "Age =", stu.age, "Score =", stu.score) 报错

# 类属性实例属性调用区别
# class Student:
#     score = 99
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#
# print()
# stu = Student("Demo", 18)
# stu2 = Student("Demo1", 108)
# print("Student.score =", id(Student.score))  # 获取类属性的地址 4387620272
# print("stu.score =", id(stu.score))  # 4387620272
# print("stu2.score =", id(stu2.score))  # 4387620272
# stu.score = 100
# stu2.score = 101
# Python 是动态语言,可以在运行时改变自身结构,动态添加和删除类的属性和方法
# Python 的实例属性,也可以进行动态的增加和删除。动态增加的实例属性只属于实例对象私有,而不是所有对象公有
# 类属性的删除有两种方法,即:使用 del 语句和使用 delattr 函数,del 语句和 delattr 函数不仅可以删除类属性还可以删除动态添加的类属性
# 实例属性的删除有两种方法,即:使用 del 语句和使用 delattr 函数,del 语句和 delattr 函数不仅可以删除实例属性还可以删除动态添加的实例属性
# Student.score = 102
# print("Student.score =", id(Student.score))  # 4387620368
# print("stu.score =", id(stu.score))  # 4387620304
# print("stu2.score =", id(stu2.score))  # 4387620336
# stu3 = Student("Demo2", 19)
# print("stu3.score =", id(stu3.score))  # 4387620368

# class Student:
#     score = 99.95
#     def __init__(self):
#         pass
# Student.name = "Demo"
# print("before del name =", Student.name)
# delattr(Student, 'name')
# print("name =", Student.name)  # 删除类属性后再访问就报错
#
# class Student:
#     score = 99.95
#     def __init__(self):
#         pass
# Student.name = "Demo"
# print("before del name =", Student.name)
# del Student.name
# print("name =", Student.name) # 删除类属性后再访问就报错
#
# class Student:
#     score = 99.95
#     def __init__(self, name):
#         self.name = name
# stu = Student("Demo")
# print("before del name =", stu.name)
# del stu.name
# print("name =", stu.name) # 删除实例属性后再访问就报错
#
# class Student:
#     score = 99.95
#     def __init__(self):
#         pass
# stu = Student()
# stu.name = "Demo"
# print("before del name =", stu.name)
# del stu.name
# print("name =", stu.name) # 删除实例动态属性后再访问就报错

# 类中的方法有三种形式,分别为:类方法、实例方法 和 静态方法
# 类方法类似于构造函数,最少也要包含一个参数
# 只不过,类方法中通常将其命名为 cls,且 Python 会自动将类本身绑定给 cls 参数。
# 因此,在调用类方法时,无需显式传递 cls 参数
#
# 和 self 一样,cls 参数的命名也不是规定的(可以随意命名),只是 Python 程序员约定俗称的习惯而已
# 和构造方法最大的不同在于,类方法需要使用 @classmethod 进行修饰
#
# 通过类名访问类方法
# class Student:
#     @classmethod
#     def s_info(cls, id):
#         print("call Student classmethod, id =", id)
# Student.s_info(3)
#
# 通过对象访问类方法
# class Student:
#     @classmethod
#     def s_info(cls):
#         print("call Student classmethod")
# stu = Student()
# stu.s_info()
#
# 在 类 中定义的 方法 默认都是实例方法,Python 中的实例方法类似于 构造方法,第一个 参数 也是 self,且不需要使用任何的修饰符修饰
# 通过类名调用实例方法
# class Student:
#     def s_info(cls):
#         print("call Student instancemethod")
# stu = Student()
# Student.s_info(stu) # 第一个参数必须是 cls
# # 通过对象访问实例方法
# class Student:
#     def s_info(cls):
#         print("call Student instancemethod")
# stu = Student()
# stu.s_info()
#
# 静态方法的需要使用 @staticmethod 来修饰,且 Python 类的静态方法的 参数 没有任何的限制,可以没有任何参数
# 第一个参数也不必像 类方法 和 实例方法 那样
# 通过 “类名.方法名” 的方法来调用
# class Student:
#     @staticmethod
#     def s_info():
#         print("call Student staticmethod")
# Student.s_info()
# # 是通过 “对象.方法名” 的方法来调用
# class Student:
#     @staticmethod
#     def s_info():
#         print("call Student staticmethod")
# stu = Student()
# stu.s_info()

# 使用 Python 编写类时,类中的构造函数、实例函数和类函数的第一个参数都是 self
# self 并不是关键字,也可以将 self 名称换成 a 或 b 或其它名字都可以,约定成俗,一般都用 self
# self 只有在类的方法中才会有,独立的函数或方法是不必带有 self ,且 self 参数在调用时不必传入相应的参数
# class Student:
#     def __init__(my, name):
#         my.name = name
#
#     def learn(my, course):
#         print("I am Learn", course)
#
#     def eat(my, food):
#         print("I am eat", food)
#
#
# stu = Student("William")
# stu.learn("Python")
# stu.eat("Apple")
#
# self 可以做函数返回值
# class Student:
#     def incry(self):
#         if hasattr(self, 'score'):
#             self.score += 1
#         else:
#             self.score = 1
#         return self  # 在这里返回了self
# stu = Student()
# stu.incry().incry().incry()
# print("Score =", stu.score)  # 3
# stu.incry().incry().incry()
# print("Score =", stu.score)  # 6

# Python 中的 实例方法 可以访问类中的 类属性 和 实例属性
# Python 中的 类方法 可以访问类中的类属性但不可以访问实例属性
# class Student:
#     score = "Python"
#     def __init__(self, name):
#         self.name = name
#     @classmethod
#     def info(cls):
#         print("I am", cls.name, "study python") # 类方法中使用实例属性name,报错
# stu = Student("William")
# stu.info()
# 实例方法访问类属性
# class Student:
#     score = "Python"
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#     def info(self):
#         print("I am", self.name, "and i am", self.age, "years old", "study", self.score)
# stu = Student("William", 18)
# stu.info()


# Python 中的类,都会从 object 里继承一个 __dict__ 属性
# 这个属性中存放着类的属性和方法对应的键值对
# 一个类实例化之后,这个类的实例也具有 __dict__ 属性
# __dict__ 属性是以字典的形式存放着属性和方法,键为属性名,值为属性的值
# class Student:
#     course = "Python"
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#     def info(self, name, age):
#         print("call instance method, name =", name, "age =", age)
#     @classmethod
#     def hello(cls):
#         print("call class method, course =", cls.course)
#     @staticmethod
#     def thx():
#         print("call static method")
# print("Student dict =", Student.__dict__)
# 里面没有name和age
# {
#     '__module__': '__main__',
#     'course': 'Python',
#     '__init__': <function Student.__init__ at 0x1029a5670>,
#     'info': <function Student.info at 0x102a42790>,
#     'hello': <classmethod object at 0x102a36fd0>,
#     'thx': <staticmethod object at 0x102a36fa0>,
#     '__dict__': <attribute '__dict__' of 'Student' objects>,
#     '__weakref__': <attribute '__weakref__' of 'Student' objects>,
#     '__doc__': None
# }
# stu = Student("Demo", 18)
# print("stu dict =", stu.__dict__)    # {'name': 'Demo', 'age': 18}
# print("Student Course =", Student.__dict__["course"])
# print("stu name =", stu.__dict__["name"])
# print("stu age =", stu.__dict__["age"])

# 每一个 Python的实例对象中,都有一个内置的 __getattr__ 函数
# 当访问一个不存在的实例属性时,就会自动调用到 __getattr__ 函数
# 使用类名访问一个不存在的类属性,不会调用 __getattr__ 函数
# 访问一个存在的类属性或者实例属性也不会调用到 __getattr__ 函数
#
# class Student:
#     course = "Python"
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#     def __getattr__(self, item):
#         print("Get not exist attr, key =", item)
#         return "default"
# stu = Student("William", 18)
# print("stu name =", stu.name, "age =", stu.age)
# print("stu sex =", stu.sex) # 不存在的实例属性,则走到 __getattr__

# 每一个 Python 中的 实例对象 中,都有一个内置的 __getattribute__ 函数
# 当访问一个不管是存在还是不存在的 实例属性 时,就会自动调用到 __getattribute__ 函数
# 如果使用类名访问一个不管存在还是不存在的类属性,不会调用 __getattribute__ 函数
# 如果同时有 __getattribute__ 方法和 __getattr__ 方法,首先调用 __getattribute__ 方法
# class Student:
#     course = "Python"
#     def __init__(self, name, age):
#         print("__init__")
#         self.name = name
#         self.age = age
#     def __getattribute__(self, item):
#         print("__getattribute__", item)
#     def __getattr__(self, item):
#         print("__getattr__", item)
# stu = Student("William", 18)
# print("stu name =", stu.name, "age =", stu.age)
# 打印结果
# __init__
# __getattribute__ name
# __getattribute__ age
# stu name = None age = None
#
# class Student:
#     course = "Python"
#     def __init__(self, name, age):
#         print("__init__")
#         self.name = name
#         self.age = age
#     def __getattribute__(self, item):
#         print("__getattribute__", item)
#         return "Empty"
#     def __getattr__(self, item):
#         print("__getattr__", item)
#         return "empty"
# stu = Student("William", 18)
# print("stu name =", stu.name, "age =", stu.age)
#
# 打印结果
# __init__
# __getattribute__ name
# __getattribute__ age
# stu name = Empty age = Empty
#
# __getattribute__ 会调用,但是 __getattr__不会被调用
# class Student:
#     course = "Python"
#     def __init__(self, name, age):
#         print("__init__")
#         self.name = name
#         self.age = age
#     def __getattribute__(self, item):
#         print("__getattribute__", item)
#         return "Empty"
#     def __getattr__(self, item):
#         print("__getattr__", item)
#         return "empty"
# stu = Student("William", 18)
# print("stu name =", stu.name, "age =", stu.age)
# print("stu site =", stu.site)
# __init__
# __getattribute__ name
# __getattribute__ age
# stu name = Empty age = Empty
# __getattribute__ site
# stu site = Empty

# class Descriptor(object):
#     def __init__(self):
#         self.name = 'anonymous'
#     def __get__(self, instance, owner):
#         print('instance: %s' % instance)
#         print('owner: %s' % owner)
#         print("Invoke __get__: %s" % self.name)
#         return self.name
# class Person(object):
#     name = Descriptor()
# # 通过类Person访问
# print(Person.name)
# print('---------------------------------------')
# print(Person.__dict__['name'].__get__(None, Person))
# print('---------------------------------------')
# person = Person()
# print(person.name)
# print('---------------------------------------')
# # # 通过实例person访问, `owner`访问描述符实例的对象。`instance`则是访问描述符实例的实例
# print(type(person).__dict__['name'].__get__(person, type(person)))


# 描述符主要作用就是控制类的行为/对类的操作进行 hook,大部分时候是用来拦截对实例属性的访问
# 只要类中有 __get__(), __set__(), 和 __delete__() 其中之一,那么它就是一个描述器
# 对一个类进行操作,逃不开三种方法,需要控制什么操作,就 hook 哪个方法
# class Integer(object):
#     def __init__(self, name):
#         self.name = name
#
#     def __set__(self, instance, value):
#         if not isinstance(value, int):
#             raise TypeError('Expected an int')  # 抛异常
#         instance.__dict__[self.name] = value
#
#
# class Point(object):
#     x = Integer('x')
#     y = Integer('y')
#
#     def __init__(self, x, y):
#         self.x = x
#         self.y = y
#
#     def info(self):
#         print("x =", self.x, "y =", self.y)
#
#
# p1 = Point(2, 3)
# p1.info()
# p2 = Point(2, 3.3)  # TypeError: Expected an int
# p2.info()

# 【property】
# Python 中的属性可以使用 “类对象.属性” 的方式来访问
# 这种方式虽然方便,但它破坏了类的封装原则
# 正常情况下的类,它包含的属性应该是隐藏的,只允许通过类提供的方法来间接实现对类属性的访问和操作
# 在不破坏类封装原则的基础上,为了能够有效操作类中的属性
# 类中应包含读(或写)类属性的多个 getter(或 setter)方法
# 这样就可以通过 “类对象.方法(参数)” 的方式操作属性
# class Person(object):
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#     def setinfo(self, info):
#         self.name, self.age = info
#     def getinfo(self):
#         return self.name, self.age
#     def delinfo(self):
#         self.name, self.age = "", 0
#     # 使用property定义属性
#     info = property(getinfo, setinfo, doc='用于name和age属性')
# person = Person("demo", 18)
# person.info = ("demo", 19)
# print("Name =", person.name, "Age =", person.age)
# 使用 property 定义了一个 info 属性
# info 属性用于对类的 name 属性和 age 属性进行操作
# 构造 info 属性的 property 方法传入了获取 info 属性值和设置 info 属性值的方法
# (1)通过构造函数设置 name 和 age 的属性值
# (2)通过 “实例.属性” 的方式操作 name 和 age 属性
# (3)通过 info 属性,直接设置 name 和 age 的值

# 【只读装饰器】
# 如果既要保护类的封装特性,又要让开发者可以使用 “对象.属性” 的方式操作操作类属性
# 除了可以使用 property() 函数,Python 还提供了 @property 装饰器
#
# 通过 @property 装饰器,可以直接将类的方法设置为我们访问类属性的形式
# 如果仅仅使用 @property 修饰类的属性,那么该属性是只读,不可以被修改
# class Person(object):
#     def __init__(self, name, age):
#         self.__name = name
#         self.__age = age
#     @property
#     def name(self):
#         return self.__name
#     @property
#     def age(self):
#         return self.__age
# person = Person("demo", 18)
# # print("Person name =", person.name(), "age =", person.age()) 报错
# # print("Person name =", person.__name, "age =", person.__age) 报错
# print("Person name =", person.name, "age =", person.age)

# 【可写装饰器】
# 如果需要为类属性添加一个可写的装饰器,那么需要使用 @propertyname.setter 来修饰类的属性
# class Person(object):
#     def __init__(self, name, age):
#         self.__name = name
#         self.__age = age
#     @property
#     def name(self):
#         return self.__name
#     @property
#     def age(self):
#         return self.__age
#     @name.setter
#     def name(self, val):
#         self.__name = val
#     @age.setter
#     def age(self, val):
#         self.__age = val
# person = Person("demo", 18)
# person.name = "Demo"
# person.age = 19
# print("Person name =", person.name, "age =", person.age)

# 【删除装饰器】
# 如果需要为类属性添加一个可写的装饰器,那么需要使用 @propertyname.setter 来修饰类的属性
# 但此时类的属性不可以被删除
# 如果需要为类属性添加一个删除的装饰器,那么需要使用 @propertyname.deleter 来修饰类的属性
# class Person(object):
#     def __init__(self, name, age):
#         self.__name = name
#         self.__age = age
#     @property
#     def name(self):
#         return self.__name
#     @property
#     def age(self):
#         return self.__age
#     @name.setter
#     def name(self, val):
#         self.__name = val
#     @age.setter
#     def age(self, val):
#         self.__age = val
#     @name.deleter
#     def name(self):
#         self.__name = 0
#     @age.deleter
#     def age(self):
#         self.__age = 0
# person = Person("demo1", 18)
# del person.name
# delattr(person, 'age')
# # 删除属性之后再次访问这两个属性的值,发现都变成 0,即属性删除成功
# print("Person name =", person.name, "age =", person.age)

# 【私有属性】
# class Person(object):
#     def __init__(self, name, age, score):
#         self.name = name
#         self.age = age
#         self.__score = score
#     def info(self):
#         print("name =", person.name, "age =", person.age, "score =", person.__score) # 可正常打印
# person = Person("demo", 18, 100)
# person.info()
#
# 【修改类的私有属性】
# 使用 property 实现在类的内部,修改类私有属性
# 在类内部通过提供 get 和 set 方法来提供对类的私有属性的访问和修改
# 在类内部使用 getter 和 setter 装饰器提供对类私有属性的修改
# class Person(object):
#     def __init__(self, name, age, score):
#         self.name = name
#         self.age = age
#         self.__score = score
#     @property
#     def score(self):
#         return self.__score
#     @score.setter
#     def score(self, val):
#         self.__score = val
#     def info(self):
#         print("name =", person.name, "age =", person.age, "score =", person.__score)
# person = Person("demo", 18, 100)
# person.info()
# person.score = 99
# person.info()
#
# 【类的私有方法】
# Python 默认的成员函数都是公开的,在 Python 中定义私有方法只需要在方法名前加上 “__” 两个下划线
# 私有的属性只能在类内部访问,不能在类的外部调用
# class Person(object):
#     def __init__(self, name, age, score):
#         self.name = name
#         self.age = age
#         self.__score = score
#     def __getscore(self):
#         return self.__score
#     def info(self):
#         print("Name =", self.name, "Age =", self.age, "Score =", self.__getscore())
# person = Person("demo", 18, 100)
# person.info()

# 【封装】
# 把该隐藏的隐藏起来,把该暴露的暴露出来
# class Person(object):
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#     def info(self):
#         print("Name =", self.name, "Age =", self.age)
# person = Person("", -18)
# person.info() # 错误案例
#
# class Person(object):
#     def __init__(self, name, age):
#         self.__setname(name)
#         self.__setage(age)
#     def setname(self, val):
#         self.__setname(val)
#     def getname(self):
#         return self.__name
#     name = property(getname, setname)
#     def setage(self, val):
#         if val < 1:
#             self.__age = 1
#         else:
#             self.__age = val
#     def getage(self):
#         return self.__age
#     age = property(getage, setage)
#     def info(self):
#         print("Name =", self.__name, "Age =", self.__age)
#     def __setname(self, val):
#         if len(val) == 0:
#             self.__name = "Demo"
#         else:
#             self.__name = val
#     def __setage(self, val):
#         if val < 1:
#             self.__age = 1
#         else:
#             self.__age = val
# person = Person("", -18)
# person.info()
# person.name = "demo"
# person.age = 19
# person.info()
# person.name = ""
# person.age = -18
# person.info()

# 【继承】
# 定义子类时,将父类放在子类之后的圆括号里
# 多继承,就是子类继承多个父类
# 如果在定义一个 Python 类时,并未显式指定这个类的直接父类,则这个类默认继承 object 类
# class Person:
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
# class Job:
#     def __init__(self, job, salary):
#         self.__job = job
#         self.__salary = salary
#     def setjob(self, val):
#         self.__job = val
#     def getjob(self):
#         return self.__job
#     job = property(getjob, setjob)
#     def setsalary(self, val):
#         self.__salary = val
#     def getsalary(self):
#         return self.__salary
#     salary = property(getsalary, setsalary)
# class Teacher(Person, Job):
#     def info(self):
#         print("Name =", self.name, "Age =", self.age, "Job =", self.job, "Salary =", self.salary)
# teacher = Teacher("Demo", 18)
# teacher.job = "Teach"
# teacher.salary = 3500
# # Name = Demo Age = 18 Job = Teach Salary = 3500
# teacher.info()

# 【重写】
# 子类重写父类方法,必须要子类方法的函数名和 函数参数 与父类的一模一样
# 如果子类的方法名和父类一致,但参数不一致,那么不构成方法重写,而是方法覆盖
# 在子类中,通过类名可以显式调用父类被重写方法
# class Animal:
#     def eat(self):
#         print("I like eat anything")
#     def sleep(self):
#         print("I need sleep for 15 hours a day")
# class Cat(Animal):
#     def eat(self):
#         print("I am a cat, and i just like eat finish")
#     def eat_delicious(self):
#         print("when i was a child")
#         self.eat()
#         print("when i grown up")
#         Animal.eat(self)  # 调用父类被重写方法
# cat = Cat()
# cat.eat_delicious()
# cat.sleep()

# 【多继承】
# 方案一:太麻烦
# class Person:
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
# class Job:
#     def __init__(self, job):
#         self.__job = job
#     def setjob(self, val):
#         self.__job = val
#     def getjob(self):
#         return self.__job
#     job = property(getjob, setjob)
# class Teacher(Person, Job): # 如果继承很多,并且需要初始化的参数很多
#     def __init__(self, name, age, job):
#         Person.__init__(self, name, age)
#         Job.__init__(self, job)
#     def info(self):
#         print("Name =", self.name, "Age =", self.age, "Job =", self.job)
# teacher = Teacher("Demo", 18, "Teach")
# teacher.info()
#
# 优雅的方式
# class Person:
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
# class Job:
#     def __init__(self, job):
#         self.__job = job
#     def setjob(self, val):
#         self.__job = val
#     def getjob(self):
#         return self.__job
#     job = property(getjob, setjob)
# class Teacher(Person, Job):
#     def __init__(self, name, age, job):
#         super().__init__(name, age)  # super是继承的第一个
#         Job.__init__(self, job)
#     def info(self):
#         print("Name =", self.name, "Age =", self.age, "Job =", self.job)
# teacher = Teacher("Demo", 18, "Teach")
# teacher.info()
#
# super 用来解决多重继承问题,直接用类名调用父类方法在使用单继承的时候没问题
# 但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题
#
# super() 函数是用于调用父类(超类)的一个方法
# super 不仅仅可以调用父类的构造函数,还可以调用父类的成员函数
# class Animal:
#     def eat(self):
#         print("I like eat anything")
#     def sleep(self):
#         print("I need sleep for 15 hours a day")
# class Cat(Animal):
#     def eat(self):
#         print("I am a cat, and i just like eat finish")
#     def eat_delicious(self):
#         print("when i was a child")
#         self.eat()
#         print("when i grown up")
#         super().eat() # 通过 super 调用了父类被覆盖的 eat 实例方法
# cat = Cat()
# cat.eat_delicious()
# cat.sleep()

# 【__slots__限制类的实例属性,无法限制类属性】
# 用 元祖 定义允许绑定的属性的名称,不在元祖内的属性,不可以动态的添加
# class Person:
#     __slots__ = ('name', 'age')
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
# person = Person("HaiCoder", 109)
# person.score = 99 # 报错
# print("Name =", person.name, "Age =", person.age, "Score =", person.score)
#
# 问题:先在__slots__中注册,然后动态添加,没问题
# class Person:
#     __slots__ = ('name', 'age', 'score')
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
# person = Person("Demo", 19)
# person.score = 99 # 报错
# print("Name =", person.name, "Age =", person.age, "Score =", person.score)
#
# __slots__ 只能限制类的实例属性而不能限制类属性
# 如果在继承中使用 __slots__,那么 __slots__ 只能限制父类,不能限制子类的属性
# class Person:
#     __slots__ = ('name', 'age')
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
# class Student(Person):
#     __slots__ = ('name', 'age')
# student = Student("HaiCoder", 109)
# student.score = 99 # 报错
# print("Name =", student.name, "Age =", student.age, "Score =", student.score)

# 【多态】
# 具有不同功能的函数 可以使用相同的函数名
# 函数的重写其实就是多态的一种体现,在 Python 中,多态指的是父类的引用指向子类的对象
# class Animal:
#     def eat(self, animal):
#         animal.eat()
# class Cat(Animal):
#     def eat(self):
#         print("I am a cat, and i just like eat finish")
# class Dog(Animal):
#     def eat(self):
#         print("I am a dog, and i just like eat bone")
# cat = Cat()
# dog = Dog()
# animal = Animal()
# animal.eat(cat)
# animal.eat(dog)

# 【枚举】
# 在 Python 中,枚举的第一个值是从 1 开始的,而不是从 0 开始
# (1)直接使用 Enum 包列出多个枚举值来创建枚举类
# (2)通过 继承 Enum 基类来派生枚举类
# import enum
# 定义枚举类
# Day = enum.Enum('Day', ('Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'))
# 直接访问指定枚举
# print(Day) # <enum 'Day'>
# 直接使用枚举名访问枚举成员
# print(Day.Tue) # Day.Tue
# 枚举的 name 属性
# print(Day.Tue.name)  # Tue
# 枚举的 value 属性
# print(Day.Tue.value) # 2
# 通过枚举变量名访问枚举
# print(Day['Tue'])  # Day.Tue
# print("MonName =", Day['Mon'].name)
#
# Day的遍历
# import enum
# Day = enum.Enum('Day', ('Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'))
# # {
# #     'Mon': <Day.Mon: 1>,
# #     'Tue': <Day.Tue: 2>,
# #     'Wed': <Day.Wed: 3>,
# #     'Thur': <Day.Thur: 4>,
# #     'Fri': <Day.Fri: 5>,
# #     'Sat': <Day.Sat: 6>,
# #     'Sun': <Day.Sun: 7>
# # }
# print(Day.__members__)
# for name, member in Day.__members__.items():
#     # Mon => Day.Mon , Mon 1
#     # Tue => Day.Tue , Tue 2
#     # Wed => Day.Wed , Wed 3
#     # Thur => Day.Thur , Thur 4
#     # Fri => Day.Fri , Fri 5
#     # Sat => Day.Sat , Sat 6
#     # Sun => Day.Sun , Sun 7
#     print(name, '=>', member, ',', member.name, member.value)
#
# import enum
# # 定义Day枚举类
# class Day(enum.Enum):
#     Mon = '星期一'
#     Tue = '星期二'
#     Wed = '星期三'
#     Thur = '星期四'
#     Fri = '星期五'
#     Sat = '星期六'
#     Sun = '星期日'
#     def info(self):
#         print('今天是' % self.value)
# # 使用 Enum 包实现枚举,并访问枚举成员
# print("Mon =", Day.Mon)  # Day.Mon
# print("MonName =", Day.Mon.name)  # Mon
# print("MonValue =", Day.Mon.value)  # 星期一
# # 使用枚举变量名来访问枚举成员
# print("Mon =", Day['Mon'])  # Day.Mon
# print("MonName =", Day['Mon'].name) # Mon
# print("MonValue =", Day['Mon'].value) # 星期一
# for name, member in Day.__members__.items():
#     print(name, '->', member, ',', member.name, member.value)

# 【new】
# __new__() 方法是一种负责创建类实例的静态方法
# __new__() 方法是在新式类中新出现的方法
# 构造方法 __init__() 负责将类实例化
# 在 __init__() 执行前,__new__() 负责制造这样的一个实例对象
# 以便 __init__() 去让该实例对象更加丰富(为其添加属性等)
#
# __new__() 方法还决定是否要使用该 __init__() 方法
# __new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例
# class Person(object):
#     # 重写 __new__ 方法和 __init__ 方法
#     def __new__(cls,*args,**kwargs):
#         print("call __new__()")
#         instance = super().__new__(cls)
#         return instance
#     def __init__(self):
#         print("call __init__()")
# # call __new__()
# # call __init__()
# p = Person()
#
# class Person(object):
#     def __new__(cls, *args, **kwargs):
#         print("call Person __new__()")
#         instance = super().__new__(cls)
#         return instance
#     def __init__(self):
#         print("call Person __init__()") # 未执行
# class Student(object):
#     def __new__(cls, *args, **kwargs):
#         print("call Student __new__()")
#         # 在实例化 Student 类实例时,其实创建的是 Person 类的实例,而不是 Student 类的实例
#         instance = object.__new__(Person, *args, **kwargs)
#         return instance
#     def __init__(self):
#         print("call Student __init__()") # 未执行
# stu = Student()
# print("Type stu =", type(stu))  # Type stu = <class '__main__.Person'>

# 【新式类和旧式类】
# 新式类就是 继承 object 类的 类
# 经典类就是没有继承 object 类的类
# 在 Python2.x 版本中,所有的类默认都没有继承 object 类
#
# 在 Python3.X 版本中,不管我们有没有显式指定,所有的类都继承 object 类
#
# 使用的是 Python3 版本,因此不需要显式指定继承 object
# class Person:
#     name = "Demo"
# class Student(object):
#     name = "demo"
# person = Person()
# print(dir(person))
# student = Student()
# print(dir(student))

# 【判断某个类是否是另一个类的子类】
# issubclass 函数用于判断参数 class 是否是类型参数 classinfo 的子类
# issubclass 不仅可以用于内置类型的判断,也可以用于自定义类的判断
# class Person:
#     pass
# class Student(Person):
#     pass
# class Teacher(Student):
#     pass
# class Cat:
#     pass
# print("Student issubclass (Person or Student) =", issubclass(Student, Person))  # True
# print("Teacher issubclass (Person or Teacher) =", issubclass(Teacher, Person))  # True
# print("Cat issubclass (Person or Cat) =", issubclass(Cat, Person))              # False
# print("Cat issubclass (Person or object) =", issubclass(Cat, (Person, object))) # True

# 【判断类型】
#  isinstance 函数用于判断一个对象是否是某种类型
# isinstance(object, classinfo)
# 判断实例 object 是否为类 classinfo 的类型
# 如果 object 是 classinfo 的类型返回 True,否则返回 False
#
# class Person:
#     pass
# class Student(Person):
#     pass
# class Teacher(Student):
#     pass
# class Cat:
#     pass
# person = Person()
# student = Student()
# teacher = Teacher()
# cat = Cat()
# # Teacher->Student->Person->object
# # Cat->object
# # student 对象是否是 Person 类的实例
# print("student isinstance Person =", isinstance(student, Person))   # True
# # teacher 对象是否是 Person 类的实例
# print("teacher isinstance Person =", isinstance(teacher, Person))   # True
# # cat 对象是否是 Person 类的实例
# print("cat isinstance Person =", isinstance(cat, Person))           # False
# # cat 对象是否是 Person类 或者 object类 的实例
# print("cat isinstance (Person or object) =", isinstance(cat, (Person, object))) # True
# #
# name = "Demo"
# age = 109
# score = 99.98
# print("name isinstance str =", isinstance(name, str))       # True
# print("age isinstance int =", isinstance(age, int))         # True
# print("score isinstance float =", isinstance(score, float)) # True
# print("age isinstance str =", isinstance(age, str))         # False

# 【运算符重载】
# 运算符重载是让自定义的类生成的对象(实例) 能够使用运算符进行操作
# 就像 Python 中的字符串类型支持直接做加法实现字符串的拼接的功能,列表、元祖等可以直接使用减法实现求差集的功能等
# 这些类型能够使用运算符直接操作,都是实现了运算符的重载
# 重载比较运算符
# class Mynumber:
#     def __init__(self, v):
#         self.data = v
#     def __lt__(self, other):
#         return self.data - other.data
#     def __gt__(self, other):
#         if self.data > other.data:
#             return True
#         return False
# n1 = Mynumber(100)
# n2 = Mynumber(200)
# res = n1 > n2
# print("Res =", res) # False
# res = n1 < n2
# print("Res =", res) # -100
# class Mynumber:
#     def __init__(self, v):
#         self.data = v
#     def __add__(self, other):
#         v = self.data + other.data
#         return Mynumber(v)
#     def __sub__(self, other):
#         v = self.data - other.data
#         return Mynumber(v)
#     def info(self):
#         print("Number =", self.data)
# n1 = Mynumber(100)
# n2 = Mynumber(200)
# n3 = n1 + n2
# n3.info() # 300
# n4 = n3 - n2
# n4.info() # 100
#
# 常见运算符重载列表
# __add__(self,rhs)	self + rhs	加法
# __sub__(self,rhs)	self - rhs	减法
# __mul__(self,rhs)	self * rhs	乘法
# __truediv__(self,rhs)	self / rhs	除法
# __floordiv__(self,rhs)	self //rhs	地板除
# __mod__(self,rhs)	self % rhs	取模(求余)
# __pow__(self,rhs)	self **rhs	幂运算
#
# 传统除法和地板除法的区别
# / 传统除法 3/2=1.5 浮点数
# // 地板除法 3//2=1 舍弃小数
# print(-1//2.0)  # -1.0
# print(-3//2.0)  # -2.0
# print(-4//2.0)  # -2.0
# print(-1//2)    # -1
# print(-3//2)    # -2
# print(-4//2)    # -2
# print(-1//-2.0)  # 0.0
# print(-3//-2.0)  # 1.0
# print(-4//-2.0)  # 2.0
# print(-1//-2)  # 0
# print(-3//-2)  # 1
# print(-4//-2)  # 2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值