• python 类的成员及继承


    1. @staticmethod 静态方法

    静态方法不能访问实例变量和类变量,除了身处类里面,可以通过类和实例调用以外,它其实和类没有什么关系。如果想要用它访问实例变量或类变量,需要把实例和类传递给函数。

    class People(object):
        def __init__(self,name):
            self.name = name
    
        @staticmethod       # 静态方法,不能访问实例变量和类变量,和类实际没啥关系,除了把它放到类里面,然后通过类来调用它。
        def getname(sex):
            print('XX is a %s' %(sex))
    
    people = People('LaoWang')
    people.getname('man')  # 通过实例访问
    PeoPle.getname("girl") # 通过类访问

    2. classmethod 类方法

    类方法只能访问类变量,不能访问实例变量。想要访问实例变量,需要手动传递实例给函数。

    class People(object):
        age = 30
    
        def __init__(self,name):
            self.name = name
    
        @classmethod   # 类方法,只能访问类变量,不能访问实例变量,如果要访问实例变量,需要手动传入实例。
        def getage(cls):
            print('age is %s' % cls.age)
    
    people = People('LaoWang')
    people.getage()

    3. @property 属性方法

    属性方法,把一个方法变成属性,调用时不加括号即可完成调用,就像调用一个属性一样。

    class People(object):
        age = 30
    
        def __init__(self,name):
            self.name = name
    
        @property     # 属性方法,把一个方法变成属性。调用时不用加括号。
        def eat(self):
            print('%s is eating.' %self.name)
    
    people = People('LaoWang')
    people.eat                     # 调用属性方法。不加括号

    属性方法的修改和删除:

    class People(object):
        age = 30
    
        def __init__(self,name):
            self.name = name
    
        @property     # 属性方法,把一个方法变成属性。调用时不用加括号。
        def eat(self):
            print('%s is eating.' %self.name)
        @eat.setter   # 属性的修改
        def eat(self,food):
            print('This is eat setter: %s' %food)
        @eat.deleter  # 属性的删除
        def eat(self):
            print('eat has been deleted.')
    
    people = People('LaoWang')
    
    people.eat                     # 调用属性方法。不加括号
    people.eat = 'suger'          # 调用eat.setter
    del people.eat                 # 调用eat.deleter

     4. 其他类成员:

    class T(object):
        '''this is doc'''
        def __new__(cls, *args, **kwargs):
            print('this is new func')
            return super().__new__(cls)
    
        def __init__(self,name):
            self.name = name
    
        def getname(self):
            print(self.name)
    
        def __getitem__(self, item):
            print('getitem:',item)
    
        def __setitem__(self, key, value):
            print('setitem:',key,value)
    
        def __delitem__(self, key):
            print('delitem:',key)
    
        def __call__(self, *args, **kwargs):
            print('this is call, you should add bracket')
    
        def __str__(self):
            return 'you are print obj'
    
        def __del__(self):
            print('When obj is been destroyed,this func would execution automatically.')
    
    
    t=T('Wang')       # # T是一个类,它是由type创建的(type是所有类的类,它可以创建类对象,然后类对象可以创建实例)。而type里面定义了一个__call__函数,所以才能使用 'T()'
    print(T.__doc__)  # 打印类的文档注释
    print(t.__module__)# 打印对象所处的模块名
    print(t.__class__) # 打印对象的类
    print(t.__dict__)  # 打印对象的变量
    print(T.__dict__)  # 打印类的变量
    print(t)           # 打印对象,打印__str__方法的返回值(没有str方法,则打印对象的内存地址)
    t()         # 对象直接加括号,调用__call__方法
    val = t['1']  # __getitem__
    t['1'] = 1    # __setitem__
    del t['1']    # __delitem__
    del t         # __del__

     __new__()方法

    我们常说 __init__(self) 是构造方法,其实是不准确的,__init__(self) 中的 'self' ,其实就是一个实例,这个实例对象,是先由 __new__(cls)创建的。也就是说,在 __init__() 执行之前,__new__() 已经执行并且返回了一个实例对象给 __init__(), 如果 __new__() 没有返回值,则 __init__() 根本不会执行。

    可以看这篇博客以及博客的留言:[Python] Python 之 __new__() 方法与实例化 - iFantasticMe - 博客园 (cnblogs.com)

    class A(object):
        def __new__(cls, *args, **kwargs):
            print('cls is ',cls)
            # 调用父类的__new__(),返回一个实例对象; 因为父类 object 的此方法只接受一个参数,所以只传递一个cls
            self = super(A, cls).__new__(cls)
            self.x = 'XXX'  # 给实例对象设置一个 x属性
            return self  # __new__必须返回一个实例,否则对象会是 NoneType;如果没有返回值,则__init__不会被调用执行
    
        def __init__(self):
            self.y = 'YYY'
    
    # B继承A,会默认调用父类A的__new__()生成一个实例,这个实例自带一个 x属性
    class B(A):
        def __init__(self,name):
            self.z = name
    
    a = A()
    b = B('ZZZ')
    print(b.__dict__)  # {'x': 'XXX', 'z': 'ZZZ'}

    5. 类的类

    python中万物皆对象。类其实也是一个对象。在python中类可以创建实例,那么类本身又是谁创建的呢,答案是type

    num = type(1)
    string = type('my')
    dictionary = type({1:'1'})
    print(num,string,dictionary)
    # <class 'int'> <class 'str'> <class 'dict'>
    print(num.__class__,string.__class__,dictionary.__class__)
    # <class 'type'> <class 'type'> <class 'type'>

    从上面的例子可以看出,数字、字符串、字典,它们的类型都是由不同的类创建的。而这些类再往上追溯,它们又都是由 type 类创建的。所以说,type就是所有类的类。

    我们常见的 object,也是 type 的一个实例:

    object和type的关系:object是type的实例,object是type的基类(type继承自object)

    print(isinstance(object,type))  # True

    通过type创建类:

    # class A(object):
    #     a = 5
    #     def abc(self,name):
    #         self.name = name
    #     def getname(self):
    #         print(self.name)
    
    #  使用type创建一个类,和上面的类一模一样
    def init(self, name):
        self.name = name
    def getname(self):
        print(self.name)
    A = type('A',(object,),{'a':5,'__init__':init,'getname':getname})
    # type第一个参数:类名
    # type第二个参数:当前类的基类
    # type第三个参数:类的成员
    
    aa = A('Wang')
    aa.getname()
    print(aa.a)

    6. 元类 metaclass

    元类就是用来造类的类,type也是一个元类,只不过它是python内建的元类,是所有类的类。我们也可以自己创建一个元类,用来动态的创建类。

    class MyType(type):                     # 创建元类,父类需要传入type
        def __new__(cls,name,bases,attrs):   # 第一步,元类的操作都在__new__中完成,第一个参数是将创建的类。name,将要创建的类。bases,将要创建的类的父类。attrs,类的方法和属性的字典
            print("Mytype __new__",name,bases,attrs,sep=' / ')
            print('cls',cls)
            return type.__new__(cls, name,bases,attrs) # 如果返回一个已经存在的实例或者不返回任何值,则init不会被调用
    
        def __init__(self,*args,**kwargs):  # 第二步,init
            print("Mytype __init__",*args,**kwargs)
    
        def __call__(self, *args, **kwargs):  # 第三步,创建的类实例化时才执行。类实例化时需要加括号对吧,这个括号就是__call__方法赋予的。
            print("Mytype __call__", *args, **kwargs)
            obj = self.__new__(self)          # Foo类的new方法
            print("obj.... ",obj,*args, **kwargs)
            print(self)
            self.__init__(obj,*args, **kwargs)
            return obj
    
    print('-------------------------------------')
    
    class Foo(object,metaclass=MyType):
        def __new__(cls, *args, **kwargs):
            print("Foo __new__",cls, *args, **kwargs)
            return object.__new__(cls)
    
        def __init__(self,name):
            self.name = name
            print("Foo __init__")
    
        def getname(self):
            print('name is ',self.name)
    
    print(isinstance(Foo,MyType))  # Foo类,是 MyType 的一个实例
    f = Foo("Wang")
    print("f",f)
    print("fname",f.name)

    例子:使用元类来创建类,并动态的给所创建的所有类添加一个属性:类名 = 'Hello, '+类名

    class Meta(type):      # 元类
        def __new__(cls, name,bases,attrs):  # name:类名, bases:基类, attrs:类的所有方法属性的字典。
            attrs[name] = 'Hello, %s' % name
            print(attrs)
            return type.__new__(cls,name,bases,attrs)
    
    class People(object,metaclass=Meta): # 使用元类来定制类,People类是object和Meta的实例
        age = 22
    
    peo = People()
    print(peo.People)

     因为python是一门解释性语言,所以按照从上往下顺序执行

    class Meta --> Meta类里面的方法和属性 --> class People --> People里面的方法和属性 --> 注意:此时将People里面的方法和属性传递给元类,执行元类的__new__方法、__init__方法(此例子中没重写) --> peo=People() 实例化 --> 元类的__call__方法(此例子中没重写) --> print(peo.People)

     使用元类作为单例模式:__call__()

    class Singleton(type):
        def __init__(self, *args, **kwargs):
            self.__instance = None
            super().__init__(*args, **kwargs)
    
        # __call__可以让类的实例像函数一样,直接使用()调用,譬如有个实例:a,a() 会直接调用 __call__() 函数
        def __call__(self, *args, **kwargs):
            print('__call__ is called.')
            if self.__instance is None:
                self.__instance = super().__call__(*args, **kwargs)
                return self.__instance
            else:
                return self.__instance
    
    class Spam(metaclass=Singleton):  # Spam 是 Singleton 的实例
        def __init__(self):
            print('Creating Spam')
    
    # Spam 是 Singleton的一个实例
    a = Spam()  # Spam实例化时调用了 Singleton 的 __call__(),所以产生一个实例
    b = Spam()  # 第二次调用,__call__() 直接返回同一个实例
    
    print(a is b)

    7. 其他封装、继承、多态

    # 类变量:修改、增加、删除
    # 实例变量:增加、删除、修改
    
    # 析构函数 __del__
    # 私有变量、私有方法:前面加 __
    
    class Car():
        region = 'China'                 # 类变量,公有变量,每个实例化的对象都可以访问
        def __init__(self,brand,price):  # 构造方法,实例化
            self.brand = brand
            self.price = price
            self.__mile = 100              # 私有变量,只能内部访问,无法通过实例化的对象进行外部访问
        def __modifyMiles(self,mile):    # 私有方法,只能内部调用
            self.__mile += mile
        def getMiles(self):
            return self.__mile
        def __del__(self):              # 析构方法,销毁对象时自动执行的方法(如程序运行结束、主动删除对象)
            # print('destroy obj.')
            pass
        @staticmethod  # @staticmethod是把函数嵌入到类中的一种方式,函数属于类,但是和类没有什么直接关系
        def car_run(obj):  # 接受一个对象作为参数,调用这个参数的方法
            obj.run()
    
    car = Car('奔驰',300000)
    car.getMiles()
    car.owner = 'LaoWang'  # 实例化的对象也可以在外面直接添加变量
    print(car.region)
    car.region = 'Beijing' # 相当于重新声明了一个实例化变量
    print(car.owner,car.region) # 当类变量和实例化变量同时存在,首先访问实例变量
    del car.owner
    del car.region
    print(Car.region)
    
    class CC():
        pass
    
    class EleCar(Car,CC):  # 多继承,子类继承父类Car,CC;子类不能直接调用父类的私有变量和私有方法,可以调用父类的调用了私有方法的方法
        def __init__(self,brand,price,battery): # 要写父类的参数
            # 三种继承方法,推荐最后一种
            # Car.__init__(self,brand,price)
            # super(EleCar,self).__init__(brand,price)
            super().__init__(brand,price)    # 继承父类,初始化父类的属性(只初始化一个父类,按继承的顺序从左到右查找(广度优先),遇到的第一个带有__init__方法的父类停止)。不管多少个父类,只写一遍即可。
            self.battery = battery
        def run(self):
            print('%s is running.' % self.brand)
    
    class Bike(Car):
        def __init__(self,brand,price):
            super().__init__(brand,price)
        def run(self):
            print('%s is running.' % self.brand)
    
    bike = Bike('永久',300)
    bike.run()
    
    print('--------')
    ec = EleCar('宝马',300000,'asdf')
    # print(ec.getMiles())
    ec.run()
    
    print('多态:一个接口,多种实现')
    Car.car_run(ec)
    Car.car_run(bike)

    8. 抽象类和抽象方法

    from abc import ABCMeta, abstractmethod  # 导入抽象类和抽象方法
    
    class Employee(metaclass=ABCMeta):   # 定义抽象类,抽象类不能被实例化,只能被继承!
        def __init__(self,name):
            self.name = name
    
        @abstractmethod             # 抽象方法,子类必须实现此方法!
        def get_salary(self):
            pass
    
    
    class Manager(Employee):   # 子类
        def __init__(self,name):
            super().__init__(name)
    
        def get_salary(self):     # 实现抽象类的抽象方法
            return 15000
    
    
    class Developer(Employee):
        def __init__(self,name,hour=0):
            self.name = name
            self.hour = hour
        def get_salary(self):
            return 200*self.hour
    
    
    class Factory():  # 工厂模式
        @staticmethod
        def create(type,*args,**kwargs):
            return type(*args,**kwargs)
    
    M = Factory.create(Manager,'zhongtao')
    D = Factory.create(Developer,'zhangsan',160)
    print(f'{M.name} salary: {M.get_salary()}')
    print(f'{D.name} salary: {D.get_salary()}')
  • 相关阅读:
    [loj2706]文本编辑器
    [atAGC053C]Random Card Game
    [atAGC056E]Cheese
    [cf1615G]Maximum Adjacent Pairs
    [cf739D]Recover a functional graph
    [uoj693]地铁规划
    [atAGC053E]More Peaks More Fun
    [atAGC056B]Range Argmax
    [atAGC056F]Degree Sequence in DFS Order
    SceneGrabber NET 视频批量自动截图软件使用技巧
  • 原文地址:https://www.cnblogs.com/wztshine/p/11848214.html
Copyright © 2020-2023  润新知