面向过程:根据业务逻辑从上到下写代码。 面向对象:将变量与函数绑定到一起,分类进行封装,每个程序只要负责分配给自己的分类,这样能够更快速的开发程序,减少了重复代码。 面向过程编程的关注点在于怎么做 特点: 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)和面向过程编程,是两种不同的编程方式。 相比较函数,面向对象是更大的封装,根据职责在 一个对象中封装多个方法 面向对象编程的关注点在于谁来做 特点: 类是对一群具有相同 特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用。 对象是由类创建出来的一个具体存在,可以直接使用。由哪一个类创建出来的对象,就拥有在哪一个类中定义的属性和方法。在开发中,应该先有类,在类里定义好属性和行为,再根据类来创建对象。 在实际项目开发中,建议类的定义和模块结合使用(一个模块中定义一个类),相同或者相似的类可以使用包进行管理。 方式一:通过 方式二:通过 语法: 类其实就是自定义的数据类型,创建对象(实例化对象)的过程其实就是定义变量过程。 通过一个普通的类可以创建无数个对象,每个对象在内存中都会开辟新的空间。 方式一:使用 方式二:使用 语法: 缺点:绑定的属性的数量没有上限,绑定的属性的名称没有限制,在实际项目开发中,需要进行限制绑定。 语法: 在代码比较复杂的情况下,使用动态绑定属性的方式创建对象,就不太好了。这时需要一个名称为 构造函数,也被称为构造器,指的是当创建对象的时候,被自动调用的函数。 严格意义讲, 但是,一般形参列表中变量的名称和规定的属性名一致,所以建议使用下面的书写方式。 当对象被销毁的时候自动调用的函数,称为析构函数,析构函数为 广义的封装:函数的定义和类的提取,都是封装的体现。 狭义的封装:在面向对象编程中,一个类的某些属性,在使用的过程中,如果不希望被外界直接访问,就可以将该属性封装(将不希望被外界直接访问的属性私有化private,该属性只能被当前类持有,此时可以给外界暴露一个访问的函数即可)。 封装的本质:就是属性私有化的过程。 封装的好处:提高了数据的安全性,提高了数据的复用性。 公开属性:可以在类以外的任何地方直接访问。 私有属性:只能在类的内部被直接访问,在对象属性的前面添加两个下划线表示是私有属性。 工作原理:一个属性一旦被私有化,在底层形成了 在类外面访问属性,无非涉及到两个操作:获取值,修改值。 注意:如果函数被 为了简化函数的调用,Python中通过 在类中,对象函数之间相互调用,语法: 如果两个或者两个以上的类具有相同的属性和方法,我们可以抽取一个类出来,在抽取出来的类中声明各个类公共的部分。被抽取出来的类称之为父类(超类、基类),两个或两个以上的类称之为子类 (派生类),他们之间的关系是 子类继承自父类 或者 父类派生了子类。 子类之继承一个父类,被称为单继承。 语法: 注意:object 是 Python 中所有类的根类。 注意:在单继承中,三种方式都可以使用;在多继承中,只能使用方式三 继承的优点: 继承的缺点: 子类可以拥有多个父类,并且具有所有父类的属性和方法。 如果一个子类继承了多个父类,在没有书写构造函数的前提下,创建子类对象,默认调用的父类列表中的第一个父类中的构造函数。 如果需要继承父类中的属性,则需要调用父类的构造函数。 如果多个父类中出现了重名的函数,则子类对象调用时,调用的是父类列表中的第一个父类中的函数。 Python中针对类提供了一个内置属性 不是直接查找父类,而是根据调用节点的广度优先顺序执行的。 举个例子,创建A、B、C、D、E类,E类继承B、C、D类,B类继承A类,C类继承A类,D类继承A类,在每个方法中都调用 另外一个例子,在C类中没有调用 打印对象时,会调用对象的 不同的子类调用相同的父类方法,产生不同的执行结果,可以增加代码的外部灵活度。多态是以继承和重写父类方法为前提的,它是一种调用方法的技巧,不会影响到类的内部设计。 思考:这段代码设是否有问题? 新增需求:多了一个犬种,需要在Person类里新建一个方法,让这个方法操作新的狗。 Person 类总是不断的添加新的功能,每次都需要改动Person类的源码,程序的扩展性太差了! 最好是提供一个父类 Dog,具备 work 的功能,其他小狗继承它,这样只要是小狗类,则行为被统一起来了,我们人类完全可以保证,只要是小狗的子类,找它干活肯定不会有问题。这样人只要一个方法就能逗任意种类的狗玩,哪怕是添加新的狗,人的类都不需要修改。 Person 类中只需要调用 Dog 对象 在程序执行时,传入不同的 Dog 对象作为实参,就会产生不同的执行效果 限制对象属性的动态绑定。 表示类的描述信息,获取类中的文档注释(多行注释)。 获取类或者对象的信息【属性和方法】,返回字典。 总结: 内置的数据类型没有 每个类有自己的 对象也有自己的 获取当前操作的对象在哪个模块。 如果被操作的对象在当前模块,则获取的结果为 类似于 获取一个对象在内存中的地址 判断一个实例对象是否是由某一个类(或者它的子类)实例化创建出来的。 查看对象内的所有的属性和方法。 判断两个类之间的继承关系。 形参列表的第一个参数为 使用 使用场景 使用场景 注意点 类中定义了同名的方法时,调用方法会执行最后定义的方法。 程序运行过程中,确保某一个类只有一个实例【对象】,不管在哪个模块获取这个类的对象,获取到的都是同一个对象。该类有一个静态方法,向整个工程提供这个实例,例如:一个国家只有一个主席,不管他在哪里。 单例设计模式的核心:一个类有且仅有一个实例,并且这个实例需要应用于整个程序中,该类被称为单例类。 应用程序中描述当前使用用户对应的类,当前用户对于该应用程序的操作而言是唯一的,所以一般将该对象设计为单例。 实际应用:数据库连接池操作,应用程序中多处地方连接到数据库,连接数据库时的连接池只需一个就行,没有必要在每个地方都创建一个新的连接池,这种也是浪费资源 ,解决方案也是单例。 装饰器装饰函数 装饰器装饰类 实现单例 类函数 枚举类可以方便地表示星期,月份等常数类型,如果你不用枚举类,那么你只能用数字或者字符串。如果你使用数字,用1-7来表示星期数,但一个数字在程序中不仅可以表示星期数,可能还有其他许多含义,这样你在写程序时就必须时刻记住这些数字的含义,这降低了程序的可读性,也导致容易出错。而当你使用字符串时,虽然没有明显的缺点,但在内存中字符串所占内存要比数字多,这就降低了程序的效率。 枚举类正好弥补了这两方面的缺点,你可以在代码中使用枚举类,但在内存中存放时使用的是数字,既提高了可读性,又提高了程序效率。更重要的是,Python中的枚举类型是不可变类型,又可以进行迭代,这就意味着可以随时使用枚举类型而不用担心改变了枚举类型的值。 枚举类型可以通过继承Enum类来实现,注意Enum类是在enum模块中的。 当存在枚举成员有重复时,则后面的枚举成员相当于第一个枚举成员的别名,而且在实际使用中,就是使用的第一次出现的枚举成员。 上述代码中, 如果尝试遍历枚举类型,则后面重复的不会被打印出来。但是,如果想要获取别名,我们可以使用属性 枚举类型默认可以对相同的值使用别名,但有时我们需要确保枚举类型不能重复,我们也有办法使每个枚举值只出现一次。我们可以引入装饰器 限制枚举成员必须是整数类型。 最有趣的也是最重要的是枚举类型是使用单例模式实现的。在创建枚举类的时候,Python就在内存中为我们创建了枚举类的对象,因此我们不必实例化枚举类。并且由于枚举类的 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类 实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合,继承的第二种用途非常重要。它又叫接口继承。 由于python 没有抽象类、接口的概念,所以要实现这种功能得借助于 抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。文章目录
一、面向过程与面向对象
简述
面向过程编程
面向对象编程
二、类和对象
类
对象(实例)
类和对象的关系
三、类的定义
class 类名(): def 方法1(self,参数列表): pass def 方法2(self,参数列表): pass
四、类中的成员
类属性
类名.类属性
访问实例对象.类属性
访问class Person(object): # 类属性 num = 10 p = Person() # 方式一 print(Person.num) # 方式二 print(p.num)
实例函数(对象函数,成员函数)
class Person(): # 实例函数,对象函数,成员函数 def eat(self, food): print("eating" + food)
实例函数和普通函数的区别
实例函数的形参列表第一个参数是self,而普通则不是。
关于self
self表示当前对象 1. self并不是一个关键字,其实可以是任意的标识符,为了表达代表的是当前对象自己,习惯用self 2. 调用实例函数的时候,self不需要手动传参,系统会自动传递当前的对象 3. 哪个对象调用了方法,方法里的self指的就是谁。 通过 self.属性名 可以访问到这个对象的属性。 通过 self.方法名() 可以调用这个对象的方法。
创建对象(实例化对象)
变量名 = 类名(初始值)
,目前初始值省略。class Person(object): def eat(self, food): # 实例方法有一个参数self,指的是实例对象 print(food) p1 = Person() p2 = Person()
调用类中的实例函数
对象名.方法名(参数)
调用的方式,不需要传递self。类名.方法名(self, 参数)
的方式,不会自动给 self 传参,需要手动的指定self。class Person(object): def eat(self, food): # 实例方法有一个参数self,指的是实例对象 print(food) p1 = Person() # 方式一 p1.eat('蘸水面') # 方式二 Person.eat(p1, '蘸水面')
动态绑定属性和限制绑定
动态绑定属性
对象.属性 = 初始值
class Person(object): def eat(self, food): # 实例方法有一个参数self,指的是实例对象 print(food) p1 = Person() p1.name = 'Lucy' p1.age = 18
限定绑定
__slots__ = (属性1, 属性2,…………)
class Person(object): __slots__ = ('name', 'age') def eat(self, food): # 实例方法有一个参数self,指的是实例对象 print(food) p1 = Person() p1.name = 'Lucy' p1.age = 18 # p1.height = 178 # AttributeError: 'Person' object has no attribute 'height'
内存中的对象
class Person(object): num = 10 p11 = Person() p12 = Person() # p11.num 和 p12.num访问的是同一个num,num来自于类属性,当前类持有,通过该类创建的所有的对象都持有 print(p11.num is p12.num) # True print(p11.num, p12.num) # 10 10
class Person(object): num = 10 p13 = Person() p13.num = 20 p14 = Person() p14.num = 20 # p13.num和 p14.num访问的不是同一个num,num被称为对象属性,仅限当前对象持有 print(p13.num is p14.num) # True del p13.num print(p13.num, p14.num) # 10 20
构造函数
__init__
的方法,该特殊的方法被称为构造函数,主要用于创建对象并将对象的数据初始化。__new__
不属于构造函数。工作原理
class Book(object): # cls和self都不是关键字,可以是一个普通的标识符 # cls全称class,表示当前类 # __new__属于类方法 def __new__(cls, *args, **kwargs): print("new被调用了") # 注意:__new__必须有返回值,并且返回一个实例 # super(Book,cls).__new__(cls)表示当前类创建出来的一个实例 return super(Book, cls).__new__(cls) # self表示当前对象 # __init__属于实例函数 def __init__(self): print("init被调用了") b1 = Book() print(b1) # <__main__.Book objcet at 0x6572846> # 如果类中重写__str__,则不打印地址
工作原理: 1. __new__:创建对象的时候首先自动调用__new__,它的作用就是创建实例,然后将该实例返回 2. __init__:当实例创建完毕之后被调用的,然后通过__init__给实例设置初始值 3. __new__先被调用,__init__后被调用,__new__的返回值(实例)将传递给__init__的第一个参数self,然后__init__给这个实例设置一些参数,__init__不需要返回值。
给
__init__()
设置参数class Student(object): __slots__ = ("name", "age", "hobby", "score") def __init__(self, a, b, c): self.name = a self.age = b self.hobby = c self.score = 60
class Student(object): __slots__ = ("name", "age", "hobby", "score") def __init__(self, name, age, hobby): self.name = name self.age = age self.hobby = hobby self.score = 60
析构函数
__del__()
。1. 将对象定义为全局变量,程序执行完毕,对象自动被销毁
class Animal(object): def __init__(self): print("init被调用了") def __del__(self): print("del被调用了") a1 = Animal() print("over") """ init被调用了 over del被调用了 """
2. 将对象定义为局部变量,当指定的函数执行完毕,则对象随着会被自动销毁
class Animal(object): def __init__(self): print("init被调用了") def __del__(self): print("del被调用了") def func(): a2 = Animal() print("函数内部") func() print("over") """ init被调用了 函数内部 del被调用了 over """
3. 强制销毁对象,什么时候del对象,则什么时候执行析构函数
__del__()
class Animal(object): def __init__(self): print("init被调用了") def __del__(self): print("del被调用了") a3 = Animal() del a3 print("over") """ init被调用了 del被调用了 over """
五、封装
概念
私有属性
1. 概念
2. 属性未被私有化
class Person(object): def __init__(self, name, age): # 公开属性 self.name = name self.age = age p1 = Person("jack", 10) # 直接访问 print(p1.name, p1.age) # jack 10 # 修改 p1.name = "tom" p1.age = 19 print(p1.name, p1.age) # tom 19
3. 属性被私有化
_类名__属性名
的属性名 ,但是不建议使用。私有化属性在底层的存在形式根据操作系统或者Python解释器的不同会有所差别,如果直接使用此种方式访问,违背了Python跨平台的特点。class Person(object): def __init__(self, name, age): self.__name = name self.__age = age p = Person("jack", 10) # print(p.name,p.age) #AttributeError: 'Person2' object has no attribute 'name' # print(p.__name) #AttributeError: 'Person2' object has no attribute '__name' print(p._Person__name) # jack
4. 暴露给外界访问的函数
class Person(object): def __init__(self, name, age): self.__name = name self.__age = age # 返回被私有化属性的值 def getname(self): return self.__name def setname(self, name): self.__name = name def getage(self): return self.__age def setage(self, age): if age < 0: age = abs(age) self.__age = age p = Person("jack", 10) # 获取值 r1 = p.getname() print(r1) # jack # 修改值 p.setname("tom") r2 = p.getname() print(r2) # tom p.setage(-19) print(p.getage()) # 19
5. @property装饰器
@property
将一个函数转换为属性调用,为了简化函数的调用,函数名本身表示指定函数的返回值,如:show()
使用@property
修饰,则 show()
的调用:对象名.show
。@property
修饰,最好设置返回值。class Check(object): @property def show(self): # 如果函数被@property修饰,最好设置返回值 return 'hello' c = Check() # c.show() #TypeError: 'str' object is not callable print(c.show) # hello
@property
和 @xxx.setter
@property
和 @xxx.setter
分别修改两个函数。
注意:
@xxx.setter
中的 xxx
需要和被 @property
修饰的函数名保持一致@property
修饰的函数用于获取值,@xxx.setter
修饰的函数用于修改值@property
和 @xxx.setter
并不是需要同时出现,根据自己的需求进行选择
@property
出现,@xxx.setter
可以不出现@xxx.setter
出现,@property
必须出现class Person(object): def __init__(self, name, age): self.__name = name self.__age = age # 获取值:将被私有化属性的值返回 @property def name(self): return self.__name # 修改值:设置参数 @name.setter def name(self, name): self.__name = name @property def age(self): return self.__age @age.setter def age(self, age): if age < 0: age = abs(age) self.__age = age # 将函数当做属性访问 p = Person("tom", 17) print(p.name) # tom p.name = "bob" print(p.name) # bob
私有函数
self.函数名
。1. 函数未被私有化
class Person1(object): def func1(self): print("111") # 注意:在类中,对象函数之间相互调用,语法:self.函数 self.func2() def func2(self): print("222") def show(self): print("show") p1 = Person1() p1.func1() # 111 # 222 p1.show() # show
2. 函数被私有化
class Person2(object): def func1(self): print("111") # 间接调用 self.__show() def func2(self): print("222") def __show(self): print("show") p2 = Person2() p2.func2() # 222 # p2.show() # 报错 # p2.__show() # 报错 # p2._Person2__show() # show p2.func1() # 111 # 222
六、继承
单继承
1. 基本使用
class 子类类名(父类类名): 类体
class Person(object): def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender def eat(self): print("eating") def __show(self): print("showing")
class Doctor(Person): pass d = Doctor("张医生", 30, "male") # 注意:子类对象可以直接调用父类中未被私有化的函数 d.eat() # eating d._Person__show() # showing 不建议这样使用 d._Doctor__show() # AttributeError: 'Doctor' object has no attribute '_Doctor__show'
# 有参数时 class Teacher(Person): def __init__(self, height): self.height = height t = Teacher(180) print(t.height) # 180 # print(t.name, t.age, t.gender) # AttributeError: 'Teacher' object has no attribute 'name' t.eat() # eating # 无参数时 class Lawyer(Person): def __init__(self): print("lawyer~~~init") la = Lawyer() # lawyer~~~init # print(la.name) # AttributeError: 'Lawyer' object has no attribute 'name' la.eat() # eating
方式一: super(当前类, self).__init__(参数列表) 方式二: super().__init__(参数列表) 方式三: 父类名.__init__(self, 参数列表)
class Worker(Person): def __init__(self, name, age, gender, type): super(Worker, self).__init__(name, age, gender) self.type = type def work(self): print("working") w = Worker("工作者", 10, "男", "行政") print(w.type) # 行政 print(w.name, w.age, w.gender) # 工作者 10 男
2. 继承中的
__slots__
属性
__slots__
定义的属性仅对当前类的实例起作用,对继承的子类实例是不起作用class Aniaml(object): __slots__ = ("name", "age") class Cat(Aniaml): pass c = Cat() c.name = "tom" c.age = 6 c.num = 8 print(c.name, c.age, c.num) # tom 6 8
__slots__
属性,子类的属性就是自身的 __slots__
加上父类的 __slots__
class Aniaml(object): __slots__ = ("name", "age") class Cat(Aniaml): __slots__ = ("num",) c = Cat() c.name = "tom" c.age = 6 c.num = 8 # c.weight = 80 # 报错 print(c.name, c.age, c.num) # tom 6 8
3. 继承中的类属性
class MyClass1(object): x = 10 class SubClass1(MyClass1): pass class SubClass2(MyClass1): pass print(MyClass1.x, SubClass1.x, SubClass2.x) # 10 10 10 # 通过子类修改继承自父类的类属性,只会改变该子类继承的类属性 SubClass1.x = 20 print(MyClass1.x, SubClass1.x, SubClass2.x) # 10 20 10 # 通过父类修改类属性,子类继承的类属性也改变 MyClass1.x = 30 print(MyClass1.x, SubClass1.x, SubClass2.x) # 30 20 30 # 子类先修改继承的类属性,父类再修改类属性,将不会再对已经修改过的子类类属性做出改变 SubClass2.x = 50 MyClass1.x = 40 print(MyClass1.x, SubClass1.x, SubClass2.x) # 40 20 50
4. 继承的特点
__slots__
属性对子类不起作用5. 继承的优缺点
多继承
1. 基本使用
class Father1(object): def __init__(self, num1): self.num1 = num1 def func1(self): print("func1~~~111") def show(self): print("show~~~1111") class Father2(object): def __init__(self, n1, n2): self.n1 = n1 self.n2 = n2 def func2(self): print("func2~~~222") def show(self): print("show~~~2222")
class Child(Father2, Father1): pass c1 = Child(2, 3) c2 = Child(1) # 报错
class Child(Father1, Father2): def __init__(self, num1, n1, n2, a): Father1.__init__(self, num1) Father2.__init__(self, n1, n2) self.a = a c = Child(3, 4, 6, 8) print(c.a) # 8 print(c.num1, c.n1, c.n2) # 3 4 6 c.func1() # func1~~~111 c.func2() # func2~~~222
class Child(Father1, Father2): def __init__(self, num1, n1, n2, a): Father1.__init__(self, num1) Father2.__init__(self, n1, n2) self.a = a c = Child(3, 4, 6, 8) c.show() # show~~~1111
2. 继承的
__mro__
属性__mro__
可以用来查看方法的搜索顺序。mro
是 method resolution order
的简称,主要用于在多继承时判断方法属性的调用顺序。
__mro__
的输出结果从左至右的顺序查找。class A(object): def show(self): print("aaaa") class B(A): def show(self): print("bbbb") class C(A): def show(self): print("cccc") class D(B, C): def show(self): print("dddd") print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) d = D() d.show() # ddd
3. 多继承中 super 本质(继承树问题)
super().show()
方法,查看执行顺序。class A(object): def show(self): print("aaaa") class B(A): def show(self): print("enter~~~~bbb") super().show() print("退出~~~~~bbb") class C(A): def show(self): print("enter~~~~ccc") super().show() print("退出~~~~~ccc") class D(A): def show(self): print("enter~~~~ddd") super().show() print("退出~~~~~ddd") class E(B, C, D): def show(self): print("enter~~~~eee") super().show() print("退出~~~~~eee") print(E.mro()) # [<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>] e = E() e.show() """ enter~~~~eee enter~~~~bbb enter~~~~ccc enter~~~~ddd aaaa 退出~~~~~ddd 退出~~~~~ccc 退出~~~~~bbb 退出~~~~~eee """
super().show()
方法。class A(object): def show(self): print("aaaa") class B(A): def show(self): print("enter~~~~bbb") super().show() print("退出~~~~~bbb") class C(A): def show(self): print("enter~~~~ccc") print("退出~~~~~ccc") class D(A): def show(self): print("enter~~~~ddd") super().show() print("退出~~~~~ddd") class E(B, C, D): def show(self): print("enter~~~~eee") super().show() print("退出~~~~~eee") print(E.mro()) # [<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>] e = E() e.show() """ enter~~~~eee enter~~~~bbb enter~~~~ccc 退出~~~~~ccc 退出~~~~~bbb 退出~~~~~eee """
函数重写
1. 自定义函数
class Person(object): def func1(self): print("父类~~~func1") def show(self): print("父类~~~show") class Student(Person): # 建议:重写的时候,子类中的函数的声明部分尽量和父类中的函数保持一致 def func1(self): print("子类~~~~func1") return 100 stu1 = Student() stu1.func1() # 子类~~~~func1
class Person(object): def func1(self): print("父类~~~func1") def show(self): print("父类~~~show") class Student(Person): def func1(self): super().func1() print("子类~~~~func1") return 100 stu1 = Student() stu1.func1() """ 父类~~~func1 子类~~~~func1 """
2. 系统函数
__str__
和 __repr__
__str__
方法,默认会打印类名和对象的地址名;__repr__
方法 和 __str__
方法功能类似,都是用来修改一个对象的默认打印内容。在打印一个对象时,如果没有重写 __str__
方法,它会自动来查找 __repr__
方法。如果这两个方法都没有,会直接打印这个对象的内存地址。如果两个方法都写了,选择 __str__
方法。class Check1(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score def __str__(self): return f"name:{self.name},age:{self.age},score:{self.score}" __repr__ = __str__ # 如果只是打印一个对象,则重写__str__即可 c1 = Check1("aaa", 10, 199) c2 = Check1("bbb", 20, 88) # 如果将对象添加到序列中,为了能看到对象的值,则重写__str__和__repr__ list1 = [c1, c2] print(list1) for c in list1: print(c)
__add__
print("hello" + "Python") print("hello".__add__("Python"))
class Book(object): def __init__(self, num): self.num = num # 重写 def __add__(self, other): # 参与相加的两个对象:self 和 other # Book + Book = Book return Book(self.num + other.num) # 重写__str__,保证最后返回的结果 def __str__(self): return f"{self.num}" b1 = Book(100) b2 = Book(400) b3 = b1 + b2 print(b3) # 500 print(b1.__add__(b2)) # 500
__eq__
__eq__
方法如果不重写,默认比较依然是内存地址class Student(object): def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): return self.name == other.name and self.age == other.age s1 = Student('lucy', 18) s2 = Student('lucy', 18) s3 = Student('lucy', 20) # s1 == s2本质是调用 p1.__eq__(p2),获取这个方法的返回结果 print(s1 == s2) # True print(s1 == s3) # False
class Student: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): # 等于 return self.name == other.name and self.age == other.age def __ne__(self, other): # 不等于 return self.age != other.age def __lt__(self, other): # 小于 return self.age < other.age # return self.age < other def __gt__(self, other): # 大于 return self.age > other.age def __le__(self, other): # 小于等于 return self.age <= other.age def __ge__(self, other): # 大于等于 return self.age >= other.age s1 = Student('zhangsan', 18) s2 = Student('zhangsan', 18) s3 = Student('lisi', 20) print(s1 == s2) # True print(s1 != s2) # False print(s1 < s2) # False # print(s1 < 6) # False print(s1 > s2) # False print(s1 <= s2) # True print(s1 >= s2) # True
class Student: def __init__(self, name, age): self.name = name self.age = age def __add__(self, other): return self.age + other def __sub__(self, other): return self.age - other def __mul__(self, other): return self.age * other def __truediv__(self, other): return self.age / other def __mod__(self, other): return self.age % other def __pow__(self, power, modulo=None): return self.age ** power s = Student('zhangsan', 18) print(s + 1) # 19 print(s - 2) # 16 print(s * 2) # 36 print(s / 5) # 3.6 print(s % 5) # 3 print(s ** 2) # 324
class Student: def __init__(self, name, age): self.name = name self.age = age def __int__(self): return self.age def __float__(self): return self.age * 1.0 def __str__(self): return self.name def __bool__(self): return self.age > 18 s = Student('zhangsan', 18) print(int(s)) # 18 print(float(s)) # 18.0 print(str(s)) # zhangsan print(bool(s)) # False
七、多态
场景
实现
class ArmyDog(object): def bite_enemy(self): print('追击敌人') class DrugDog(object): def track_drug(self): print('追查毒品') class Person(object): def work_with_army(self, dog): dog.bite_enemy() def work_with_drug(self, dog): dog.track_drug() ad = ArmyDog() dd = DrugDog() p = Person() p.work_with_army(ad) p.work_with_drug(dd)
class XiaoTianDog(object): def eat_moon(self): print('哮天犬把月亮吃了') class Person(object): def work_with_xiaotian(self, dog): # 添加方法 dog.eat_moon()
最终实现
class Dog(object): def work(self): # 父类提供统一的方法,哪怕是空方法 pass class ArmyDog(Dog): # 继承 Dog def work(self): # 子类重写方法,并且处理自己的行为 print('追击敌人') class DrugDog(Dog): def work(self): print('追查毒品') class XiaoTianDog(Dog): def work(self): print('哮天犬把月亮吃了') class Person(object): def work_with_dog(self, dog): dog.work() # 使用小狗可以根据对象的不同而产生不同的运行效果, 保障了代码的稳定性 # 子类对象可以当作父类来使用 dog = Dog() ad = ArmyDog() dd = DrugDog() xtd = XiaoTianDog() p = Person() # 同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性 # 并且传递不同对象,最终 work_with_dog 产生了不同的执行效果 p.work_with_dog(dog) p.work_with_dog(ad) p.work_with_dog(dd) p.work_with_dog(xtd)
work()
方法,而不关心具体是 什么狗work()
方法是在 Dog 父类中定义的,子类重写并处理不同方式的实现多态总结
八、其他
对象的内置属性
1.
__slots__
2.
__doc__
class Check(object): """ 功能:实现校验的功能 参数 返回值 """ def show(self): pass print(Check.__doc__) c = Check() print(c.__doc__)
3.
__dict__
class MyClass(object): num = 10 def __init__(self, m): self.m = m def show(self): pass @classmethod def func(cls): pass @staticmethod def test(): pass # 类名:类属性,构造函数,实例函数,类函数,静态函数 print(MyClass.__dict__) m = MyClass(5) # 对象:实例属性 print(m.__dict__)
__dict__
属性__dict__
属性,就算存着继承关系,父类的__dict__
并不会影响子类的__dict__
__dict__
属性,存储实例属性信息4.
__module__
__main__
,如果被操作的对象在其他模块,则获取的结果为 模块名
。class MyClass(object): pass m = MyClass() print(m.__module__) # __main__
from random import randint print(randint.__module__) # random
5.
__class__
type(xxx)
,返回当前对象的类型。class MyClass(object): pass m = MyClass() print(m.__class__) # <class '__main__.MyClass'> print(type(m)) # <class '__main__.MyClass'>
print('abc'.__class__) # <class 'str'> print(type('abc')) # <class 'str'>
对象的内置函数
1.
id()
a = 99 print(id(a)) print(type(id(a))) # 比较两个对象的地址是否相同 a = 19 b = 10 print(id(a) == id(b)) print(a is b)
2.
type()
print(type("abc")) # <class 'str'>
print(type(20) == type(40)) # True print(type(20) == int) # True print(type(type(10))) # <class 'type'>
class Person(object): pass p = Person() print(type(p)) # <class '__main__.Person'> print(type(Person)) # <class 'type'>
types
模块,可以判断函数的类型import types print(type(lambda x: x) == types.LambdaType) print(type((x for x in range(10))) == types.GeneratorType) print(type(abs) == types.BuiltinFunctionType)
3.
isinstance()
class Person(object): def __init__(self, name, age): self.name = name self.age = age class Student(Person): def __init__(self, name, age, score): super(Student, self).__init__(name, age) self.score = score p = Person('tony', 18) s = Student('jack', 20, 90) print(isinstance(p, Person)) # True.对象p是由Person类创建出来的 print(isinstance(s, Person)) # True.对象s是有Person类的子类创建出来的
print(isinstance(18, int)) print(isinstance([1, 2, 3], (list, tuple, dict))) print(isinstance(33, (str, int)))
4.
dir()
# 获得当前模块的属性 print(dir())
print(dir("abcd"))
5.
issubclass(子类, 父类)
class Person(object): def __init__(self, name, age): self.name = name self.age = age class Student(Person): def __init__(self, name, age, score): super(Student, self).__init__(name, age) self.score = score class Dog(object): def __init__(self, name, color): self.name = name self.color = color print(issubclass(Student, Person)) # True print(issubclass(Dog, Person)) # False
类方法
cls
,表示当前类;@classmethod
装饰器来装饰。
class Person(object): # 类属性 __num = 3 # 构造函数 def __init__(self, name, age): # 实例属性 self.name = name self.age = age # 实例函数:形参列表的第一个参数必须为self,表示当前对象 def show(self): print("show", self) print("showing") @classmethod def func1(cls): # cls就相当于是Person,所以可以通过cls创建对象 c = cls("jack", 18) # 在类方法中调用 实例函数,必须先通过cls创建对象,然后再调用 c.show() return cls.__num p = Person("tom", 5) # 类函数可以通过类名或者对象调用 print(p.func1()) print(Person.func1()) """ show <__main__.Person object at 0x000001D1865BB308> showing 3 """
静态方法
@staticmethod
来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。
class Dog(object): type = "狗" def __init__(self): name = None # 静态方法 @staticmethod def introduce(): # 静态方法不会自动传递实例对象和类对象 print("工作赚钱了养只金毛") dog1 = Dog() Dog.introduce() # 可以用 实例对象 来调用 静态方法 dog1.introduce() # 可以用 类对象 来调用 静态方法
class Dog: def demo_method(self): print("对象方法") @classmethod def demo_method(cls): print("类方法") @staticmethod def demo_method(): # 被最后定义 print("静态方法") dog1 = Dog() Dog.demo_method() # 结果: 静态方法 dog1.demo_method() # 结果: 静态方法
九、单例设计模式
概念
应用场景
实现
1. 模块
class Person(object): def __init__(self, name): self.name = name def dance(self): print(self.name + "dancing") p = Person("小彩旗") print(id(p))
from Day15.singleton.person import p # 依据:Python中的模块本身是一种单例,因为只有当第一次import的时候才会去加载源文件【.pyc】, print(p) print(id(p))
2.
__new__
class Person(object): # 定义类属性,用于存储当前类可以创建的唯一的实例 __instance = None # 只要执行创建对象的语法,都会调用__new__,也都会将__new__的返回值传递给__init__的self,进行属性的赋值 def __new__(cls, *args, **kwargs): # 思路:判断__instance 值是否为None,如果为None,则赋值【当前实例】,如果不为None,则直接返回 if not cls.__instance: cls.__instance = super(Person, cls).__new__(cls) return cls.__instance def __init__(self, name, age): self.name = name self.age = age p1 = Person("jack", 10) # 0x67345674 第一次肯定会创建 print(p1) p2 = Person("aaa", 6) # 0x67345674 第二次则表示获取,但是会将属性值重新赋值 print(p2) print(id(p1) == id(p2)) # True print(p1 is p2) # True print(p1.name, p2.name) # aaa aaa
3. 装饰器
def outter(func): print("ouuter~~~~") def inner(): print("inner~~~") func() return inner @outter def test(): print("test") test()
def outter(cls): print("outter~~~222") def inner(): print("inner~~~~222") return cls() return inner @outter class Check(object): pass # 只要上述代码,会打印outter~~~222 c = Check() print(c) c1 = Check() print(c1) """ outter~~~222 inner~~~~222 <__main__.Check object at 0x000002422E4E8B88> inner~~~~222 <__main__.Check object at 0x000002422E4E5788> """
def outter(cls): print("outter~~~222") def inner(*args, **kwargs): print("inner~~~~222") return cls(*args, **kwargs) return inner @outter class Check(object): def __init__(self, name, age): self.name = name self.age = age c = Check("jack", 10) print(c) print(c.name, c.age) """ outter~~~222 inner~~~~222 <__main__.Check object at 0x0000020A220CB2C8> jack 10 """
def singleton(cls): # 定义一个变量,用于存储被装饰的类唯一的实例 instance = None # 建议:函数命名为getinstance/currentinstance/defaultinstance def getinstance(*args, **kwargs): # 思路:判断instance值是否为None,如果为None,则赋值【当前实例】,如果不为None,则直接返回 # nonlocal instance声明局部作用域中的instance不是定义了新的变量,而是来自于函数作用域的instance nonlocal instance if not instance: # cls()会自动调用原类的构造函数【__init__】 instance = cls(*args, **kwargs) # 返回被装饰类唯一的实例 return instance return getinstance @singleton class Person(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score p1 = Person("zhangsan", 10, 99) p2 = Person("lisi", 18, 100) print(p1 is p2) # True print(id(p1) == id(p2)) # True print(p1.name, p2.name) # zhangsan zhangsan
def singleton(cls): instance_dict = {} def getinstance(*args, **kwargs): # 思路:判断instance_dict是否为空,如果为空,以被装饰的类作为key,唯一的实例作为value # 如果不为空,则直接返回value if not instance_dict: instance_dict[cls] = cls(*args, **kwargs) return instance_dict[cls] return getinstance @singleton class Person(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score p1 = Person("zhangsan", 10, 99) p2 = Person("lisi", 18, 100) print(p1 is p2) # True print(id(p1) == id(p2)) # True print(p1.name, p2.name) # zhangsan zhangsan
# 思路:在当前类中创建一个实例,在类的外面只需要获取 class Person(object): # 定义一个类私有属性,保存当前类唯一的实例 __instance = None @classmethod def getinstance(cls, *args, **keargs): # 创建对象 if not cls.__instance: cls.__instance = cls(*args, **keargs) return cls.__instance def __init__(self, name, age): self.name = name self.age = age p1 = Person.getinstance("zhangsan", 10) print(p1) # <__main__.Person object at 0x00000287C9535A08> p2 = Person.getinstance("lisi", 20) print(p2) # <__main__.Person object at 0x00000287C9535A08> print(p1 is p2) # True print(id(p1) == id(p2)) # True print(p1.name, p2.name) # zhangsan zhangsan
十、枚举类
使用枚举类的好处
创建枚举类
from enum import Enum class Week(Enum): # 枚举成员 MONDAY = 1 TUESDAY = 2 WEDNESDAY = 3 THURSDAY = 4 FRIDAY = 5 SATURDAY = 6 SUNDAY = 0
查看枚举类型
# 枚举类型 print(Week.MONDAY, type(Week.MONDAY)) # Week.MONDAY <enum 'Week'> print(Week['MONDAY']) # Week.MONDAY # 枚举名称 key print(Week.MONDAY.name) # MONDAY # 枚举值 value print(Week.MONDAY.value) # 1 # 通过value得到枚举类型 print(Week(0)) # Week.SUNDAY # 遍历查询枚举成员的值 for w in Week: print(w.value)
重复的枚举类型
from enum import Enum class Week(Enum): # 枚举成员 MONDAY = 1 TUESDAY = 2 WEDNESDAY = 3 THURSDAY = 4 FRIDAY = 5 SATURDAY = 6 SUNDAY = 0 ALIAS_FOR_SUNDAY = 0
ALIAS_FOR_SUNDAY
就是 SUNDAY
的别名,就比如“星期日”和“星期天”都可以表示星期七一样,当遇到这种情况我们也可以这样用。__members__
,它是一个OrderedDict,包括所有定义的枚举名称,包括别名。for name, member in Week.__members__.items(): print(name, member)
确保枚举类型的唯一
@unique
,它会遍历枚举成员,如果发现有重复就会立即抛出 ValueError。from enum import Enum, unique @unique class Week(Enum): # 枚举成员 MONDAY = 1 TUESDAY = 2 WEDNESDAY = 3 THURSDAY = 4 FRIDAY = 5 SATURDAY = 6 SUNDAY = 0 # ALIAS_FOR_SUNDAY = 0 # ValueError: duplicate values found in <enum 'Week'>: ALIAS_FOR_SUNDAY -> SUNDAY
IntEnum
from enum import Enum, unique, IntEnum class Flag(IntEnum): A = 3 B = 19 C = 10 # D = "abc" # ValueError: invalid literal for int() with base 10: 'abc'
枚举类的其他特性
__new__
方法,将会保证内存中只会存在一个枚举类的实例。十一、接口类
Interface
,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能。# 接口类,将多个类中的共同的需求做出了一个抽象 class Payment(object): # 规定了一个兼容的接口 def pay(self): pass class WechatPay(Payment): def pay(self, money): print("微信支付") class AliPay(Payment): def pay(self, money): print("支付宝支付") class ApplePay(Payment): def pay(self, money): print("苹果支付") def func(obj, money): obj.pay(money) # 创建对象 w = WechatPay() a = AliPay() a1 = ApplePay() func(w, 1000) func(a, 1000) func(a1, 1000)
十二、抽象类
abc
这个类库。import abc # abstract class # 1.定义一个抽象类,并在其中定义抽象方法 class Check1(metaclass=abc.ABCMeta): @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass # 注意1:抽象类本身不能被实例化 # c1 = Check1() # 注意2:抽象类存在的意义就是为了被继承 # 注意3:在继承了抽象类的子类中必须实现抽象类中的方法 class SubClass1(Check1): def read(self): print("读取") def write(self): print("写入") s1 = SubClass1() s1.read() s1.write()
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算