当前位置:首页 > Python教程 > python技巧

python 类的成员

类变量和实例变量

class Test:
    num = 1  # 直接写在类里面的变量,和函数同级,这是类变量
    
    def __init__(self):
        self.number = 2  # 绑定在实例 self 上的变量,是实例变量。

@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")  # 通过类访问


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()

@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 

其他类成员

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 算是 type 的实例,所以才能使用 '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)创建的, cls 是当前正在实例化的类。

也就是说,在 __init__() 执行之前,__new__() 已经对当前类执行并且返回了一个实例对象给 __init__(), 如果 __new__() 没有返回值,则 __init__()根本不会执行。

如果一个类没有写 __new__() 方法,则会调用它父类的 __new__ 来生成实例并返回给当前类的 __init__ 方法。如果一个类写了 __new__ 方法,那么你可以自由选择任意一个的其他的新式类(必定要是新式类,因为所有新式类都是object的后代)的 __new__() 方法来制造实例。

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'} 

类的类

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 = namedef 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)

元类 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 objclass 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)# `People` 这个类本身就是 Meta 元类的实例,它是调用 `Meta.__new__()`, `Meta.__init__()` 方法后返回的一个实例 # `People()` 会尝试调用 Meta 元类的 `Meta.__call__` 方法,元类没有的方法,则向上查找父类的父类... # 然后完成赋值:`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)

封装、继承、多态

# 类变量:修改、增加、删除 # 实例变量:增加、删除、修改 # 析构函数 __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.ownerdel car.regionprint(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)

抽象类和抽象方法

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.hourclass 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()}')

【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!

相关教程推荐

其他课程推荐