文章目录

  • 类继承方法重复:
  • 多继承调用顺序问题
  • 类属性
  • 类方法
  • 实例属性
  • 实例方法
  • 静态方法
  • 类对象和实例对象可调用的范围
  • property属性
  • 应用场景
  • property方法四个参数
  • 有关访问限制
  • 一些魔法属性
  • doc
  • module
  • class
  • init
  • call
  • dict
  • str
  • getitem、setitem、delitem
  • getslice、setslice、delslice
  • new
  • 接口



类继承方法重复:

  • ClassExample|ClassName.__dict__ 以字典形式返回类或类实例的属性
  • ClassExample.__class__ 返回实例的创建对象类、
  • ClassName.__mro__ 存在继承时,返回该类执行时super方法调用类对象的顺序

如果子类中也有__init__方法,则会覆盖,需要在子类中的__init__方法引入父类的__inti__方法。

class Height():
    def __init__(self,height):
        self.heigth = height
        print('Height has executed')

class Weight():
    def __init__(self,weight):
        self.weight = weight
        print('Weight has executed')

class Person(Height,Weight):
    def __init__(self,name):
        self.name = name
        print('Person has executed!')

m = Person('小明')

#继承的父类:[Height,Weight]的__init__方法没有调用,被子类覆盖了。
# out:Person has executed!


class Person(Height,Weight):
    def __init__(self,name,height,weight):
        self.name = name
        Height.__init__(self,height)
        Weight.__init__(self,weight)
        print('Person has executed!')

m = Person('小明',178,'30kg')
print(m.__class__)
print(m.__dict__)
print(Person.__mro__)
# 在子类初始化方法__init__中引入父类该方法
#out: Height has executed
#out: Weight has executed
#out: Person has executed!
#out: <class '__main__.Person'>
#out: {'name': '小明', 'heigth': 178, 'weight': '30kg'}
#out: (<class '__main__.Person'>, <class '__main__.Height'>, <class '__main__.Weight'>, <class 'object'>)

多继承调用顺序问题

如果类C,类B都继承了类A,而类D继承了类B和类C,这样通过父类名字引入父类的属性,类B和类C都会调用类A,这样就会浪费许多资源,使用super方法引入继承类的属性,就可以有效避免这点。
super方法:使用了c3算法,保证每一个类只调用一次,计算的类调用顺序

python __方法名 python方法名重复_python

class Parent():
    def __init__(self,name,*args,**kwargs):     #为避免多继承报错,使用不定长参数,接受参数
        self.name = name
        print('Parent has executed!')

class Son1(Parent):
    def __init__(self,name,age,*args,**kwargs):
        self.age = age
        super().__init__(name,*args,**kwargs)
        print('Son1 has executed!')

class Son2(Parent):
    def __init__(self,name,weight,*args,**kwargs):
        self.weight = weight
        super().__init__(name, *args, **kwargs)
        print('Son2 has executed!')

class GrandSon(Son1,Son2):
    def __init__(self,name,age,weight):
        print('GrandSon has executde!')
        super().__init__(name,age,weight)

if __name__ == '__main__':
    m = GrandSon('小明',25,178)
    print(GrandSon.__mro__)

#out: GrandSon has executde!
#out: Parent has executed!
#out: Son2 has executed!
#out: Son1 has executed!
#Parent类只调用了一次。
#out: (<class '__main__.GrandSon'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)

super方法里面也可以传入类名,我们将上面的类Grandson改写下,如下输入super传入类名‘Son2’,便从__mro__元组的Son2的下一个类开始继承调用:

class GrandSon(Son1,Son2):
    def __init__(self,name,age,weight):
        print('GrandSon has executde!')
        super(Son2,self).__init__(name,age,weight)
if __name__ == '__main__':
    m = GrandSon('小明',25,178)
    print(GrandSon.__mro__)
    print(m.__dict__)
#out: GrandSon has executde!
#out: Parent has executed!
#out: (<class '__main__.GrandSon'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class  '__main__.Parent'>, <class 'object'>)
# 只调用了Son2后面的类Parent,所以只有name属性
#out: {'name': '小明'}

类属性

直接在类里面定义变量,即为类的属性,如下示例的cls_var


类方法

使用@classmethod装饰器创建,至少有一个cls参数(也可以是别的名字)


实例属性

__init__(self)魔法方法中传入的变量属性,如下示例的self.name


实例方法

定义实例方法,至少有一个self参数(也可以是别的名字)
比如如下示例的cls_exp_fun(self)


静态方法

其实就是一个普通函数,和类对象实例对象无关,可以使用@staticmethod装饰器创建。其作用表现为该方法只针对该类调用。(如果类A要调用函数名为test的函数,类B也要调用函数名为test的函数,而这个两个函数的方法是不一样的,如果test只是一个独立的函数,写两次则会覆盖,都指向为一个test函数,将test创建为类的静态方法就可以避免这点)

类对象和实例对象可调用的范围

  • 类对象可以调用类属性、类方法及静态方法;
  • 类的实例都可以调用,包括类属性,类方法,实例属性,实例方法,静态方法,实例方法可有其特有的属性,其他与类对象共用。
class Test():
    cls_var = '类属性:cls_var'
    def __init__(self,name):
        self.name = '实例变量name:{}'.format(name)

    def cls_exp_fun(self):
        '''定义实例方法,至少有一个self参数(也可以是别的名字)'''
        print('这是一个实例方法:cls_exp_cun')

    @classmethod
    def cls_fun(cls,name):
        '''定义类方法,至少有一个cls参数(也可以是别的名字)'''
        print('这是一个类方法:cls_fun')
        cls.name = name

    @staticmethod
    def static_fun():
        '''定义静态方法,无默认参数'''
        print('这是一个静态方法:static_fun')


if __name__ == '__main__':
    m = Test('小叔本')
    # 调用实例方法
    m.cls_exp_fun()
    # 实例调用类方法,该方法会创建类name属性
    m.cls_fun('实例调用类方法')
    # 调用类方法,类属性name被修改
    Test.cls_fun('类属性:name')
    # 实例调用静态方法
    m.static_fun()
    # 类也可以调用静态方法
    Test.static_fun()
    # 实例的'__class__'属性执行创建实例类对象,可以通过该指向修改类的一些属性,比如下面修改类的name属性。
    m.__class__.name = '修改类的属性name'
    # 我们再查看下类与实例的属性
    print(m.__dict__,'\n',Test.__dict__)

print输出:
这是一个实例方法:cls_exp_cun
这是一个类方法:cls_fun
这是一个类方法:cls_fun
这是一个静态方法:static_fun
这是一个静态方法:static_fun
{‘name’: ‘实例变量name:小叔本’}
{‘module’: ‘main’, ‘cls_var’: ‘类属性:cls_var’, ‘init’: <function Test.init at 0x00000251B4F1A048>, ‘cls_exp_fun’: <function Test.cls_exp_fun at 0x00000251B4F1A0D0>, ‘cls_fun’: <classmethod object at 0x00000251ADF1B860>, ‘static_fun’: <staticmethod object at 0x00000251ADF1B7F0>, ‘dict’: <attribute ‘dict’ of ‘Test’ objects>, ‘weakref’: <attribute ‘weakref’ of ‘Test’ objects>, ‘doc’: None, ‘name’: ‘修改类的属性name’}
实力调用类属性:cls_var


property属性

应用场景

  • 实际上我们也可以使用函数返回,使用property会使得代码更为清晰,另一方面,使用函数时,我们往往需要了解函数相关参数,直接使用property可以避免这点。
  • Python的property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回。
  • property属性的两种方式:
  • 装饰器:在方法上应用装饰器
  • 类属性:在类中定义值为property对象的类属性
class Sale():
    '''
    python3中默认继承object类,py3具有@xxx.setter,@xxx.deleter方法,这两种装饰器在py2中使用不了。
    '''
    def __init__(self):
        self.__numb = 888

    @property
    def num(self):
        print('@property')
        return  self.__numb

    @num.setter
    def num(self,value):    #需要传入value参数
        print('@price.setter')
        self.__numb = value

    @num.deleter
    def num(self):
        print('@price.deleter')
        del self.__numb


if __name__ == '__main__':
    m = Sale()
    m.num           # 自动调用property装饰的num函数
    print(m.num)
    m.num = 999      # 自动调用num.setter装饰的num函数
    print(m.num)
    del m.num       # 自动调用num.deleter装饰的num函数
    #print(m.num)
    m._Sale__numb	#可以通过这种方式访问类的私有属性

out:
@property
@property
888
@price.setter
@property
999
@price.deleter

property方法四个参数

  • 第一个参数是方法名,调用对象.属性时自动触发执行方法
  • 第二个参数是方法名,调用对象.属性=xxx时自动触发执行方法
  • 第三个是方法名,调用del 对象.属性时自动触发执行方法
  • 第四个参数是字符串,调用对象.属性.__doc__,此参数是改属性的描述。
class Sale():
   '''
   python3中默认继承object类,py3具有@xxx.setter,@xxx.deleter方法
   '''
   def __init__(self):
       self.numb = 888

   def num(self):
       print('@property')
       return  self.numb

   def set_num(self,value):    #需要传入value参数
       print('@price.setter')
       self.numb = value

   def del_num(self):
       print('@price.deleter')
       del self.numb

   num_var = property(num,set_num,del_num,'description...')


if __name__ == '__main__':
   m = Sale()
   m.num_var           # 自动调用num函数
   m.num_var  = 20      # 自动调用set_num函数
   del m.num_var       # 自动调用del_num.deleter
   m.num_var.__doc__

有关访问限制

python并没有对属性和方法的访问权限进行限制。为了保证类内部的某些属性或方法不被外部所访问,可以在属性或方法前面添加单下划线、双下划线,或首尾双下划线

  • 首尾双下划线表示定义特殊的方法,一般是系统定义名字,如__init__()。
  • 以单下划线开头的表示protected(保护)类型的成员,只允许类本身和子类进行访问,但不能使用“from module import *”语句导入。
  • 双下划线表示private(私有)类型成员,只允许定义该方法的类本身进行访问,而且也不能通过类的实例进行访问,但是可以通过“类的实例名._类名__xxx”进行访问。

一些魔法属性

doc

__doc__:类的描述信息

module

__module__:当前操作的对象在哪个模块

class

__class__:当前操作的对象的类是什么

class Cls():
'''类的描述信息'''
	def func(self):
		pass
print(Cls.__doc__)
print(Cls.__module__)
m = Cls()
print(m.__class__)

init

__init__:初始化方法,通过类创建对象,自动触发执行

call

__call__:类的描述信息,对象后面加括号,触发执行。

class Cls():
	def __init__(self):
		pass
	def __call__(self,*args,**kwargs):
		print('__call__')
m = Cls()
m()	#触发执行__call__函数

dict

__dict__:类或对象中的所有属性,类的实例属性属于对象,类中的类属性和方法属于类。

str

__str__:如果定义了一个__str__方法,在print时,默认输出该方法的返回值。

class Cls():
	def __str__(slef):
		return '__str__'
m = Cls()
print(m)

getitem、setitem、delitem

__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据。

class Cls():
	def __init__(slef):
		self.dic = {'name':'张三'}
		
	def __getitem__(self,key):
		return self.dic[key]
	
	def __setitem__(self,key,value):
		self.dic[key] = value

	def __delitem__(self,key):
		del self.dic[key]
m = Cls()
result = m['name']
m['age'] = 25
del m['age']

getslice、setslice、delslice

__getslice__、__setslice__、__delslice__:该三个方法用于分片操作,如列表

class Cls():
	def __init__(slef):
		self.ls = [1,3,5,9,10]
		
	def __getslice__(self,start,end):
		return self.ls[start:end]
	
	def __setslice__(self,start,end,sequence):
		self.ls[start:end] = sequence

	def __delslice__(self,start,end):
		del self.ls[start:end]
m = Cls()
result = m[-1:1]	#自动触发__getslice__
m[0:2] = [33,44,55,66]	#自动触发__setslice__,复制列表长度大于切片长度,实际赋值m[0:4]
del m[0:1]		#自动触发__delslice__

new

__new__:为类申请一块内存空间
在一个类定义中,如果没有重写(覆盖)__new__方法,类实例化会默认执行父类的__new__的方法,如果父类中没有该方法,则追溯执行类的基类object的__new__方法;
__init__方法是在类__new__方法返回内存空间后才执行。如果__new__方法在类定义时被重写而没有返回,__init__方法不会被调用,实例的对象返回是None。

class A(object):
	def __init__(self,value):
		self.num = value
		print('---->执行__init__方法')
		
	def __new__(cls,*args,**kwargs):
		'''申请返回一块内存地址'''
		print('---->执行__new__方法')
		position = super(cls,A).__new__(cls)
		return position	    # 如果没有return返回,__init__方法不会被调用
		
if __name__ == '__main__':
	m = A(10)
	print(m)		# 如果重写的__new__方法没有return,m返回是None
	print('num:{}'.format(m.num))
'''
执行顺序:
__new__申请一块内存地址 --> __init__方法承接__new__返回的内存地址执行 --> 返回实例对象m
'''

代码执行打印如下:

python __方法名 python方法名重复_python_02

接口

若干抽象方法的集合,类似于scala的抽象类;
作用:限制实现接口的类必须按照接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现;

from abc import ABCMeta,abstractclassmethod

class EatSomething(metaclass=ABCMeta):
	# 使用了该装饰,其他类继承该方法,重写调用方式必须与该方法一致(函数参数);
    @abstractclassmethod   
    def eat(self,item):
        pass

class Bob(EatSomething):
	# 重写,调用方法与抽象方法一致
    def eat(self,item):   
        print(f"Bob吃了{item}")

class Alice(EatSomething):
    def eat(self,item):
        print(f"Alice吃了{item}")

if __name__ == "__main__":
    p = Bob()
    p.eat("apple")