Python中面向对象(学习笔记)_面相对象程序设计python的笔记


1. **在子类中未定义构造函数,则创建子类对象默认调用父类中的构造函数**



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’


2. **在子类中定义构造函数,则创建子类对象调用的是子类中的构造函数**



有参数时

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


3. **在子类的构造函数中调用父类的构造函数**



方式一:
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. 继承的特点


1. 子类对象可以直接访问父类中未被私有化的属性和函数
2. 父类的 `__slots__` 属性对子类不起作用
3. 父类对象不能访问子类中特有的属性和函数


###### 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__` 属性


Python中针对**类**提供了一个内置属性 `__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 本质(继承树问题)


不是直接查找父类,而是根据调用节点的**广度优先**顺序执行的。


举个例子,创建A、B、C、D、E类,E类继承B、C、D类,B类继承A类,C类继承A类,D类继承A类,在每个方法中都调用 `super().show()` 方法,查看执行顺序。



class A(object):
def show(self):
print(“aaaa”)

class B(A):
def show(self):
print(“enterbbb")
super().show()
print("退出
~bbb”)

class C(A):
def show(self):
print(“enterccc")
super().show()
print("退出
~ccc”)

class D(A):
def show(self):
print(“enterddd")
super().show()
print("退出
~ddd”)

class E(B, C, D):
def show(self):
print(“entereee")
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()
“”"
entereee
enter
bbb
enterccc
enter
ddd
aaaa
退出~ddd
退出
~ccc
退出~bbb
退出
~eee

“”"


另外一个例子,在C类中没有调用 `super().show()` 方法。



class A(object):
def show(self):
print(“aaaa”)

class B(A):
def show(self):
print(“enterbbb")
super().show()
print("退出
~bbb”)

class C(A):
def show(self):
print(“enterccc")
print("退出
~ccc”)

class D(A):
def show(self):
print(“enterddd")
super().show()
print("退出
~ddd”)

class E(B, C, D):
def show(self):
print(“entereee")
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()
“”"
entereee
enter
bbb
enterccc
退出
~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. 系统函数


1. `__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©


2. `__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


3. `__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


4. 比较运算符相关魔法方法



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


5. 算术运算符相关魔法方法



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


6. 类型转换相关魔法方法



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)


思考:这段代码设是否有问题?


新增需求:多了一个犬种,需要在Person类里新建一个方法,让这个方法操作新的狗。



class XiaoTianDog(object):

def eat_moon(self):
    print('哮天犬把月亮吃了')

class Person(object):

def work_with_xiaotian(self, dog):  # 添加方法
    dog.eat_moon()

Person 类总是不断的添加新的功能,每次都需要改动Person类的源码,程序的扩展性太差了!


最好是提供一个父类 Dog,具备 work 的功能,其他小狗继承它,这样只要是小狗类,则行为被统一起来了,我们人类完全可以保证,只要是小狗的子类,找它干活肯定不会有问题。这样人只要一个方法就能逗任意种类的狗玩,哪怕是添加新的狗,人的类都不需要修改。


###### 最终实现



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)


Person 类中只需要调用 Dog 对象 `work()` 方法,而不关心具体是 什么狗


`work()` 方法是在 Dog 父类中定义的,子类重写并处理不同方式的实现


在程序执行时,传入不同的 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’>


* type的返回值可以直接比较是否相等



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§) # <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§)



from Day15.singleton.person import p

依据:Python中的模块本身是一种单例,因为只有当第一次import的时候才会去加载源文件【.pyc】,

print§
print(id§)


###### 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©
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©
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


##### 十、枚举类


###### 使用枚举类的好处


枚举类可以方便地表示星期,月份等常数类型,如果你不用枚举类,那么你只能用数字或者字符串。如果你使用数字,用1-7来表示星期数,但一个数字在程序中不仅可以表示星期数,可能还有其他许多含义,这样你在写程序时就必须时刻记住这些数字的含义,这降低了程序的可读性,也导致容易出错。而当你使用字符串时,虽然没有明显的缺点,但在内存中字符串所占内存要比数字多,这就降低了程序的效率。


枚举类正好弥补了这两方面的缺点,你可以在代码中使用枚举类,但在内存中存放时使用的是数字,既提高了可读性,又提高了程序效率。更重要的是,Python中的枚举类型是不可变类型,又可以进行迭代,这就意味着可以随时使用枚举类型而不用担心改变了枚举类型的值。


###### 创建枚举类


枚举类型可以通过继承Enum类来实现,注意Enum类是在enum模块中的。



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

现在能在网上找到很多很多的学习资源,有免费的也有收费的,当我拿到1套比较全的学习资源之前,我并没着急去看第1节,我而是去审视这套资源是否值得学习,有时候也会去问一些学长的意见,如果可以之后,我会对这套学习资源做1个学习计划,我的学习计划主要包括规划图和学习进度表。

分享给大家这份我薅到的免费视频资料,质量还不错,大家可以跟着学习

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里无偿获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值