zoukankan      html  css  js  c++  java
  • Python(16):Python面向对象进阶

    一、对象的继承

    Python中支持一个类同时继承多个父类

    class Parent1:
        pass
    
    
    class Parent2:
        pass
    
    
    class Sub1(Parent1, Parent2):
        pass

    使用__bases__方法可以获取对象继承的类

    print(Sub1.__bases__)
    # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)

    在Python3中如果一个类没有继承任何类,则默认继承object类。

    print(Parent1.__bases__)
    #(<class 'object'>,)

    1、类的构造函数继承__init__():

    1. 子类需要自动调用父类的方法:子类不重写__init__()方法,实例化子类后,会自动调用父类的__init__()的方法。
    2. 子类不需要自动调用父类的方法:子类重写__init__()方法,实例化子类后,将不会自动调用父类的__init__()的方法。
    3. 子类重写__init__()方法又需要调用父类的方法:需要使用super关键词。

    2、继承关系中,对象查找属性的顺序

    对象自己——>对象的类——>父类——>父类。。。

    class OldboyPeople:
        """由于学生和老师都是人,因此人都有姓名、年龄、性别"""
        school = 'oldboy'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    
    class OldboyStudent(OldboyPeople):
       def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    class OldboyTeacher(OldboyPeople):
        def score(self, stu_obj, num):
            print('%s is scoring' % self.name)
            stu_obj.score = num
    
    
    stu1 = OldboyStudent('tank', 18, 'male')
    tea1 = OldboyTeacher('nick', 18, 'male')
    
    
    print(stu1.school)
    # oldboy
    
    print(tea1.school)
    # oldboy
    
    print(stu1.__dict__)
    # {'name': 'tank', 'age': 18, 'gender': 'male'}
    
    tea1.score(stu1, 99)
    # nick is scoring
    
    print(stu1.__dict__)
    # {'name': 'tank', 'age': 18, 'gender': 'male', 'score': 99}

    二、类的派生

    子类中新定义的属性的这个过程叫做派生,子类在使用派生的属性时始终以自己的为准

    1、派生方法一(类调用)

    指名道姓访问某一个类的函数:该方式与继承无关

    class OldboyPeople:
        """由于学生和老师都是人,因此人都有姓名、年龄、性别"""
        school = 'oldboy'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    
    class OldboyStudent(OldboyPeople):
        """由于学生类没有独自的__init__()方法,因此不需要声明继承父类的__init__()方法,会自动继承"""
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    class OldboyTeacher(OldboyPeople):
        """由于老师类有独自的__init__()方法,因此需要声明继承父类的__init__()"""
    
        def __init__(self, name, age, gender, level):
            OldboyPeople.__init__(self, name, age, gender)
            self.level = level  # 派生
    
        def score(self, stu_obj, num):
            print('%s is scoring' % self.name)
            stu_obj.score = num
    
    
    stu1 = OldboyStudent('tank', 18, 'male')
    tea1 = OldboyTeacher('nick', 18, 'male', 10)
    
    
    print(stu1.__dict__)
    # {'name': 'tank', 'age': 18, 'gender': 'male'}
    
    print(tea1.__dict__)
    # {'name': 'nick', 'age': 18, 'gender': 'male', 'level': 10}

    2、派生方法二(super)

    • 严格以继承属性查找关系
    • super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
    • super().__init__(不用为self传值)
    • super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super()。
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, stu_id):
            # OldboyPeople.__init__(self,name,age,sex)
            # super(OldboyStudent, self).__init__(name, age, sex)
            super().__init__(name, age, sex)
            self.stu_id = stu_id
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    stu1 = OldboyStudent('tank', 19, 'male', 1)
    super(OldboyPeople,stu1).choose_course() #用子类对象调用父类已被覆盖的方法
    print(stu1.__dict__)
    # {'name': 'tank', 'age': 19, 'sex': 'male', 'stu_id': 1}

    三、类的组合

    类对象可以引用/当做参数传入/当做返回值/当做容器元素,类似于函数对象。

    • 组合是用来解决类与类之间代码冗余的问题

    组合可以理解成多个人去造一个机器人,有的人造头、有的人造脚、有的人造手、有的人造躯干,大家都完工后,造躯干的人把头、脚、手拼接到自己的躯干上,因此一个机器人便造出来了

    class Course:
        def __init__(self, name, period, price):
            self.name = name
            self.period = period
            self.price = price
    
    
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, stu_id):
            OldboyPeople.__init__(self, name, age, sex)
            self.stu_id = stu_id
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    class OldboyTeacher(OldboyPeople):
        def __init__(self, name, age, sex, level):
            OldboyPeople.__init__(self, name, age, sex)
            self.level = level
    
        def score(self, stu, num):
            stu.score = num
            print('老师[%s]为学生[%s]打分[%s]' % (self.name, stu.name, num))
    
    
    # 创造课程
    python = Course('python全栈开发', '5mons', 3000)
    linux = Course('linux运维', '5mons', 800)
    
    
    # 创造学生与老师
    stu1 = OldboyStudent('tank', 19, 'male', 1)
    tea1 = OldboyTeacher('nick', 18, 'male', 10)
    
    # 组合
    # 将学生、老师与课程对象关联/组合
    stu1.course = python
    tea1.course = linux
    
    

    四、多父类继承问题

    Python同样有限的支持多继承形式。多继承的类定义形如下例:

    class DerivedClassName(Base1, Base2, Base3):
        <statement-1>
        .
        .
        .
        <statement-N>

    需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 。即方法在子类中未找到时,从左到右查找父类中是否包含方法。

    1、新式类(MRO)列表

    • 继承了object的类以及该类的子类,都是新式类
    • Python3中所有的类都是新式类
    • 广度优先, 老祖宗最后找。
    class G(object):
        # def test(self):
        #     print('from G')
        pass
    
    
    class E(G):
        # def test(self):
        #     print('from E')
        pass
    
    
    class B(E):
        # def test(self):
        #     print('from B')
        pass
    
    
    class F(G):
        # def test(self):
        #     print('from F')
        pass
    
    
    class C(F):
        # def test(self):
        #     print('from C')
        pass
    
    
    class D(G):
        # def test(self):
        #     print('from D')
        pass
    
    
    class A(B, C, D):
        def test(self):
            print('from A')
    
    
    obj = A()
    obj.test()  # A->B->E-C-F-D->G-object
    # from A

    92-菱形继承问题-新式类.png?x-oss-process=style/watermark

    python计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,来实现继承的。

    为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。

    print(A.mro())  # A.__mro__
    # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
    
    for i in A.mro():
        print(i)
    
    # <class '__main__.A'>
    # <class '__main__.B'>
    # <class '__main__.E'>
    # <class '__main__.C'>
    # <class '__main__.F'>
    # <class '__main__.D'>
    # <class '__main__.G'>
    # <class 'object'>

    2、super()方法详解

    super() 函数是用于调用父类(超类)的一个方法。

    super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

    下面的例子可以看到:

    • 每个类开始调用是根据MRO顺序进行开始,然后逐个进行结束的。
    • 由于因为需要继承不同的父类,参数不一定,所有的父类都应该加上不定参数*args , **kwargs ,不然参数不对应是会报错的。
    # 胖子老板的父类
    class FatFather(object):
        def __init__(self, name, *args, **kwargs):
            print()
            print("=============== 开始调用 FatFather  ========================")
            print('FatFather的init开始被调用')
            self.name = name
            print('调用FatFather类的name是%s' % self.name)
            print('FatFather的init调用结束')
            print()
            print("=============== 结束调用 FatFather  ========================")
    
    
    # 胖子老板类 继承 FatFather 类
    class FatBoss(FatFather):
        def __init__(self, name, hobby, *args, **kwargs):
            print()
            print("=============== 开始调用 FatBoss  ========================")
            print('胖子老板的类被调用啦!')
            # super().__init__(name)
            # 因为多继承传递的参数不一致,所以使用不定参数
            super().__init__(name, *args, **kwargs)
            print("%s 的爱好是 %s" % (name, hobby))
            print()
            print("=============== 结束调用 FatBoss  ========================")
    
    
    # 胖子老板的老婆类 继承 FatFather类
    class FatBossWife(FatFather):
        def __init__(self, name, housework, *args, **kwargs):
            print()
            print("=============== 开始调用 FatBossWife  ========================")
            print('胖子老板的老婆类被调用啦!要学会干家务')
            # super().__init__(name)
            # 因为多继承传递的参数不一致,所以使用不定参数
            super().__init__(name, *args, **kwargs)
            print("%s 需要干的家务是 %s" % (name, housework))
            print()
            print("=============== 结束调用 FatBossWife  ========================")
    
    
    # 胖子老板的女儿类 继承 FatBoss FatBossWife类
    class FatBossGril(FatBoss, FatBossWife):
        def __init__(self, name, a, b):
            print('胖子老板的女儿类被调用啦!要学会干家务,还要会帮胖子老板斗地主')
            super().__init__(name, a, b)
    
    
    def main():
        print("打印FatBossGril类的MRO")
        print(FatBossGril.__mro__)
        # (<class '__main__.FatBossGril'>, <class '__main__.FatBoss'>, <class '__main__.FatBossWife'>, <class '__main__.FatFather'>, <class 'object'>)
        print("=========== 下面按照 MRO 顺序执行super方法 =============")
        gril = FatBossGril("胖子老板", "打斗地主", "拖地")
    
    
    if __name__ == "__main__":
        main()
    
    # =========== 下面按照 MRO 顺序执行super方法 =============
    # 胖子老板的女儿类被调用啦!要学会干家务,还要会帮胖子老板斗地主
    # 
    # =============== 开始调用 FatBoss  ========================
    # 胖子老板的类被调用啦!
    #
    # =============== 开始调用 FatBossWife  ========================
    # 胖子老板的老婆类被调用啦!要学会干家务
    #
    # =============== 开始调用 FatFather  ========================
    # FatFather的init开始被调用
    # 调用FatFather类的name是胖子老板
    # FatFather的init调用结束
    #
    # =============== 结束调用 FatFather  ========================
    # 胖子老板 需要干的家务是 拖地
    #
    # =============== 结束调用 FatBossWife  ========================
    # 胖子老板 的爱好是 打斗地主
    #
    # =============== 结束调用 FatBoss  ========================

    五、抽象类

    多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

    import abc
    
    
    class Animal(metaclass=abc.ABCMeta):  # 同一类事物:动物
        @abc.abstractmethod  # 上述代码子类是约定俗称的实现这个方法,加上@abc.abstractmethod装饰器后严格控制子类必须实现这个方法
        def talk(self):
            raise AttributeError('子类必须实现这个方法')
    
    
    class People(Animal):  # 动物的形态之一:人
        def talk(self):
            print('say hello')
    
    
    class Dog(Animal):  # 动物的形态之二:狗
        def talk(self):
            print('say wangwang')
    
    
    class Pig(Animal):  # 动物的形态之三:猪
        def talk(self):
            print('say aoao')
    
    
    peo2 = People()
    pig2 = Pig()
    d2 = Dog()
    
    peo2.talk()
    pig2.talk()
    d2.talk()
    
    # say hello
    # say aoao
    # say wangwang

    六、类的封装

    类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

    1、私有属性:双下划线的方式__x

    在python中用双下划线的方式__x实现隐藏属性(设置成私有的),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了。

    class Site:
        def __init__(self, name, url):
            self.name = name       # public
            self.__url = url   # private
     
        def who(self):
            print('name  : ', self.name)
            print('url : ', self.__url)
     
        def __foo(self):          # 私有方法
            print('这是私有方法')
     
        def foo(self):            # 公共方法
            print('这是公共方法')
            self.__foo()
     
    x = Site('菜鸟教程', 'www.runoob.com')
    x.who()        # 正常输出
    x.foo()        # 正常输出
    x.__foo()      # 报错

    2、外部使用变形访问:_类名__x

    类中所有双下划线开头的名称如__x都会自动变形成: _类名__x的形式:

    这种自动变形的特点:

    • 类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
    • 这种变形其实正是针对内部的变形,在外部是无法通过__x这个名字访问到的。
    • 在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的

    这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N。

    class A:
        __N = 0  # 把类的数据属性设置成私有的如__N,会变形为_A__N
    
        def __init__(self):
            self.__X = 10  # 变形为self._A__X
    
        def __foo(self):  # 变形为_A__foo
            print('from A')
    
        def bar(self):
            self.__foo()  # 只有在类内部才可以通过__foo的形式访问到.
    
    
    # 对象测试
    a = A()
    print(a._A__N)  # 0
    print(a._A__X)  # 10
    
    
    # 类测试
    print(A._A__N)  # 0
    print(A._A__X)  # 对象私有的属性# type object 'A' has no attribute '_A__X'

    注意:变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形。

    a = A()
    print(a.__dict__)  # {'_A__X': 10}
    
    a.__Y = 1
    print(a.__dict__)  # {'_A__X': 10, '__Y': 1}

    3、在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

    # 正常情况
    class A:
        def fa(self):
            print('from A')
    
        def test(self):
            self.fa()
    
    
    class B(A):
        def fa(self):
            print('from B')
    
    
    b = B()
    b.test()  # from B
    
    
    # 把fa定义成私有的,即__fa
    class A:
        def __fa(self):  # 在定义时就变形为_A__fa
            print('from A')
    
        def test(self):
            self.__fa()  # 只会与自己所在的类为准,即调用_A__fa
    
    
    class B(A):
        def __fa(self): #子类无法覆盖
            print('from B')
    
    
    b = B()
    b.test()  # from A

    python模块也遵循这种约定,如果模块中的变量名_amodule以单下划线开头,那么from module import *时不能被导入该变量,但是你from module import _amodule依然是可以导入该变量的。

    如果遇到下划线开头的(socket._socket,sys._home,sys._clear_type_cache),这些都是私有的,原则上是供内部调用的,作为外部也是可以用的。严格控制属性的访问权限,只能借助内置方法如__getattr__。

    七、类的属性(property)

    1、装饰器方式 (推荐使用)

    property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不用加括号而直接使用。

    • 1. 定义时,在实例方法的基础上添加 @property 装饰器,并且仅有一个self参数
    • 2. 调用时,无需括号

    property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回。

    分页的功能包括:

    1. 根据用户请求的当前页和总数据条数计算出 m 和 n
    2. 根据m 和 n 去数据库中请求数据
    class Pager:
        def __init__(self, current_page):
            # 用户当前请求的页码(第一页、第二页...)
            self.current_page = current_page
            # 每页默认显示10条数据
            self.per_items = 10
    
        @property
        def start(self):
            val = (self.current_page - 1) * self.per_items
            return val
    
        @property
        def end(self):
            val = self.current_page * self.per_items
            return val
    
    
    # ############### 调用 ###############
    p = Pager(2)
    print(p.start)  # 就是起始值,即:m
    # 10
    
    print(p.end)  # 就是结束值,即:n
    # 20

    2、经典类和新式类的属性方式:

    • 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法。

    • 新式类(如果类继object,那么该类是新式类 )中的属性有三种访问方式,并分别对应了三个被 @property、@方法名.setter、@方法名.deleter 修饰的方法,对同一个属性:获取、修改、删除

    class Goods(object):
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        @property
        def price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
    
        @price.setter
        def price(self, value):
            self.original_price = value
    
        @price.deleter
        def price(self):
            print('del')
            del self.original_price
    
    
    obj = Goods()
    print(obj.price)  # 获取商品价格
    # 80.0
    
    obj.price = 200  # 修改商品原价
    print(obj.price)
    # 160.0
    
    del obj.price  # 删除商品原价
    # del

    3、类属性方式

    注意:当使用类属性的方式创建property属性时,经典类和新式类无区别。

    property方法中有个四个参数

    1. 第一个参数是调用 对象.属性 时自动触发执行方法
    2. 第二个参数是调用 对象.属性 = XXX 时自动触发执行方法
    3. 第三个参数是调用 del 对象.属性 时自动触发执行方法
    4. 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
    class Goods(object):
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        def get_price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
    
        def set_price(self, value):
            self.original_price = value
    
        def del_price(self):
            del self.original_price
    
        PRICE = property(get_price, set_price, del_price, '价格属性描述...')
    
    
    obj = Goods()
    print(obj.PRICE)  # 获取商品价格
    # 80.0
    
    obj.PRICE = 200  # 修改商品原价
    print(obj.PRICE)
    # 160.0
    
    del obj.PRICE  # 删除商品原价

    3、实例

    实现一个属性的设置和读取方法,可做边界判定

    class Money(object):
        def __init__(self):
            self.__money = 0
    
        # 使用装饰器对money进行装饰,那么会自动添加一个叫money的属性,当调用获取money的值时,调用装饰的方法
        @property
        def money(self):
            return self.__money
    
        # 使用装饰器对money进行装饰,当对money设置值时,调用装饰的方法
        @money.setter
        def money(self, value):
            if isinstance(value, int):
                self.__money = value
            else:
                print("error:不是整型数字")
    
    
    a = Money()
    a.money = 100
    print(a.money)# 100

    八、实例方法及非绑定实例方法

    1、实例方法

    在类中没有被任何装饰器修饰的方法就是绑定到对象的实例方法,这类方法专门为对象定制。

    class Person:
        country = "China"
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def speak(self):
            print(self.name + ', ' + str(self.age))
    
    
    p = Person('Kitty', 18)
    print(p.__dict__)
    # {'name': 'Kitty', 'age': 18}
    
    print(Person.__dict__['speak'])
    # <function Person.speak at 0x10f0dd268>

    speak即为绑定到对象的方法,这个方法不在对象的名称空间中,而是在类的名称空间中。

    绑定到对象的方法:

    1. 通过对象调用,会有一个自动传值的过程,即自动将当前对象传递给方法的第一个参数(self,一般都叫self,也可以写成别的名称);
    2. 使用类调用,则第一个参数需要手动传值。
    p = Person('Kitty', 18)
    p.speak()  # 通过对象调用
    # Kitty, 18
    
    Person.speak(p)  # 通过类调用
    # Kitty, 18

    2、类方法(@classmethod )

    类中使用 @classmethod 修饰的方法就是绑定到类的方法。这类方法专门为类定制。

    1. 通过类名调用绑定到类的方法时,会将类本身当做参数传给类方法的第一个参数。类方法默认有个 cls 参数。
    2. 通过对象也可以调用,只是默认传递的第一个参数还是这个对象对应的类。
    class Operate_database():
        host = '192.168.0.5'
        port = '3306'
        user = 'abc'
        password = '123456'
    
        @classmethod
        def connect(cls):  # 约定俗成第一个参数名为cls,也可以定义为其他参数名
            print(cls)
            print(cls.host + ':' + cls.port + ' ' + cls.user + '/' + cls.password)
    
    
    Operate_database.connect()
    # <class '__main__.Operate_database'>
    # 192.168.0.5:3306 abc/123456
    
    
    Operate_database().connect()  # 输出结果一致
    # <class '__main__.Operate_database'>
    # 192.168.0.5:3306 abc/123456

    3、静态方法(@staticmethod )

    在类内部使用 @staticmethod 修饰的方法即为非绑定的静态方法,这类方法和普通定义的函数没有区别,不与类或对象绑定,谁都可以调用,且没有自动传值的效果。

    import hashlib
    
    
    class Operate_database():
        def __init__(self, host, port, user, password):
            self.host = host
            self.port = port
            self.user = user
            self.password = password
    
        @staticmethod
        def get_passwrod(salt, password):
            m = hashlib.md5(salt.encode('utf-8'))  # 加盐处理
            m.update(password.encode('utf-8'))
            return m.hexdigest()
    
    
    hash_password = Operate_database.get_passwrod('lala', '123456')  # 通过类来调用
    print(hash_password)
    # f7a1cc409ed6f51058c2b4a94a7e1956
    
    p = Operate_database('192.168.0.5', '3306', 'abc', '123456')
    hash_password = p.get_passwrod(p.user, p.password)  # 也可以通过对象调用
    print(hash_password)
    # 0659c7992e268962384eb17fafe88364

    九、类的专有方法:

    • __init__ : 构造函数,在生成对象时调用
    • __del__ : 析构函数,释放对象时使用
    • __repr__ : 打印,转换
    • __setitem__ : 按照索引赋值
    • __getitem__: 按照索引获取值
    • __len__: 获得长度
    • __cmp__: 比较运算
    • __call__: 函数调用
    • __name__:模块名称,一段程序作为主线运行程序时其内置名称就是 __main__

    1、运算符重载

    • __add__: 加运算
    • __sub__: 减运算
    • __mul__: 乘运算
    • __truediv__: 除运算
    • __mod__: 求余运算
    • __pow__: 乘方

    对类的专有方法进行重载实例如下:

    class Vector:
       def __init__(self, a, b):
          self.a = a
          self.b = b
     
       def __str__(self):
          return 'Vector (%d, %d)' % (self.a, self.b)
       
       def __add__(self,other):
          return Vector(self.a + other.a, self.b + other.b)
     
    v1 = Vector(2,10)
    v2 = Vector(5,-2)
    print (v1 + v2)
    
    #Vector(7,8)
  • 相关阅读:
    linux软件安装方式
    docker 安装 jenkins touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
    [ERR] Node goodsleep.vip:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
    Linux 常用命令 服务器间scp 用户 export 创建文件、软连接
    redis 安装 集群 主从 哨兵 docker
    WPF密码框中禁止复制、粘贴
    Application 统计在线人数
    【转义字符】HTML 字符实体&lt; &gt: &amp;等
    SQL语句统计每天的数据
    正则表达式计算代码数
  • 原文地址:https://www.cnblogs.com/springsnow/p/11985145.html
Copyright © 2011-2022 走看看