对于(类)class有下列概念即定义:

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,素以Dog也是一个Animal。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

一.类与对象:

1.1 类的定义

1.2 类的创建

1.3 类的属性与方法

1.1 类的定义:

类是用来描述具有相同属性和方法的对象的集合。(对象是类的实例)

举个例子:

“人类” 可以被看作一个,然后用“人类”这个类定义出每个具体的人——你、我、他等作为其对象。类还拥有属性和功能,属性即类本身的一些特性,如人类有名字、身高和体重等属性,而具体值则会根据每个人的不同;功能则是类所能实现的行为,如人类拥有吃饭、走路和睡觉等功能。具体的形式如下(伪代码):

class 人类: 
     名字 = '未命名' # 成员变量 
  def 说话(内容): # 成员函数 
     print 内容 # 成员变量赋初始值 
某人 = 人类() # 定义一个人类对象某人 
某人.名字 = "路人甲" 
某人.说话 ('大家好') # 路人甲说话 
#输出:
>>> 大家好!

1.2 类的创建:

现在我们将上述用来说明类定义的例子,用代码打出来(即创建一个类)

class Person:
    name = "OC"
    def speak(self):
        print("蓝名不存在的")
p = Person()
print(p.name)
p.speak()
#输出
>>>OC
>>>蓝名不存在的

显然我们在class板块定义了一个类Person,然后我们又用 p = Person() ,创建该类。

1.3 类的属性与方法:

属性:是指类或对象的一些特征。(例如,学生的姓名,年龄,性别,班级......)

类的专有方法(双下划线)

__init__  构造函数,在生成对象时调用,(进行初始化操作)

__del__   析构函数,释放对象时使用

__repr__ 打印,转换

__setitem__按照索引赋值

__getitem__按照索引获取值

__len__获得长度

__cmp__比较运算

__call__函数调用

__add__加运算

__sub__减运算

__mul__乘运算

__div__除运算

__mod__求余运算

__pow__乘方

 例如:注意下方代码中的self中,在age前面加了一个“_”表是私有成员,即在类的外部不可以被直接访问

那么在类的外部怎么访问私有方法呢???

class A():  
    def __init__(self):  
        self.__name='python' #私有变量,翻译成 self._A__name='python'  
    def __say(self): #私有方法,翻译成 def _A__say(self)  
        print self.__name #翻译成 self._A__name  
      
a=A()  

#print a.__name #访问私有属性,报错!AttributeError: A instance has no attribute '__name'  

print a.__dict__ #查询出实例a的属性的集合  
print a._A__name #这样,就可以访问私有变量了  

#a.__say()#调用私有方法,报错。AttributeError: A instance has no attribute '__say'  

print dir(a)#获取实例的所有属性和方法  
a._A__say() #这样,就可以调用私有方法了 

#输出
{'_A__name': 'python'}
python
['_A__name', '_A__say', '__doc__', '__init__', '__module__']
python

请注意下面的几点:(归纳一下)

Python并没有真正的私有化支持,但可用下划线得到伪私有。   尽量避免定义以下划线开头的变量!
(1)_xxx      "单下划线 " 开始的成员变量叫做保护变量,意思是只有类实例和子类实例能访问到这些变量,
需通过类提供的接口进行访问;不能用'from module import *'导入
(2)__xxx    类中的私有变量/方法名 (Python的函数也是对象,所以成员方法称为成员变量也行得通。),
" 双下划线 " 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
(3)__xxx__ 系统定义名字,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。

class Person:
    def __init__(self,name,age):
        self.name = name  #公有成员
        self._age = age #私有成员
    def speak(self):
        print(self.name+"什么时候才能蓝名哇")
p = Person("lcx",19)
p.speak()
输出:
>>>lcx什么时候才能蓝名哇

其他方法就不一一例举啦,自己去试试喽,使用方法与上述用法大致相同。

二.继承

2.1 super的使用

子类可以继承父类所有的公有属性和公有方法 (记住这句话就好)

emmmmmm直接举例子吧。

题目:写一个父类Person(),写一个子类Caiji(),父类中有两个函数,一个函数叫ask()询问TL这个人的年龄,一个函数叫cf()用来打印出TL的cf分值,然后用子类super父类,间接用父类的方法。

class Person:
    def __init__(self,name,age,score):
        self.name = name
        self.age = age
        self.score = score
    def ask(self):
        #第一个注意点:int类型要转为str,要不然会wa
        print(self.name+"的年龄为"+str(self.age))
    def cf(self):
        print(self.name+"的codeforces分数"+str(self.score))

class Caiji(Person):
    def __init__(self,name,age,score):
        #super后的()不要漏!!!
        super().__init__(name,age,score)

p = Caiji('TL',19,1200)
p.ask()
p.cf()

以上有两个注意点,已经标出。

使用super的核心代码如下:

 def __init__(self,name,age,score):
        super().__init__(name,age,score)

#super后的()不要漏掉!!!

 2.2 重写方法

对于父类只要是不符合子类的逻辑,就可以将它重写(你可以把它理解成为覆盖)

class Person:
   pass
class Caiji(Person):
    def __init__(self,name,age,score):
        super().__init__(name,age,score)
    def ask(self):
        print(self.name)

这样就重写了ask()方法。

(不难自己理解就好)

三.多态:

这个小编说的不错,我引用一下哈~~~

首先python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。以下是维基百科中对鸭子类型得论述:

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。从静态类型语言转向动态类型语言的用户通常试图添加一些静态的(在运行之前的)类型检查,从而影响了鸭子类型的益处和可伸缩性,并约束了语言的动态特性。

毫无疑问在python中对象也是一块内存,内存中除了包含属性、方法之外,还包含了对象得类型,我们通过引用来访问对象,比如a=A(),首先python创建一个对象A,然后声明一个变量a,再将变量a与对象A联系起来。变量a是没有类型得,它的类型取决于其关联的对象。a=A()时,a是一个A类型的引用,我们可以说a是A类型的,如果再将a赋值3,a=3,此时a就是一个整型的引用,但python并不是弱类型语言,在python中'2'+3会报错,而在php中'2'+3会得到5。可以这么理解,在python中变量类似与c中的指针,和c不同的是python中的变量可以指向任何类型,虽然这么说不太准确,但是理解起来容易点。

因此,在python运行过程中,参数被传递过来之前并不知道参数的类型,虽然python中的方法也是后期绑定,但是和java中多态的后期绑定却是不同的,java中的后期绑定至少知道对象的类型,而python中就不知道参数的类型。

然后来举个例子吧:

class Bird:
    def move(self, field):
        print('鸟在%s上自由地飞翔' % field)
class Dog:
    def move(self, field):
        print('狗在%s里飞快的奔跑' % field)
# x变量被赋值为Bird对象
x = Bird()
# 调用x变量的move()方法
x.move('天空')
# x变量被赋值为Dog对象
x = Dog()
# 调用x变量的move()方法
x.move('草地')

#鸟在天空上自由地飞翔
#狗在草地里飞快的奔跑

 上述code中有两个类——Dog(),Bird(),它们都调用move()这个函数。x 变量开始被赋值为 Bird 对象,因此当 x 变量执行 move() 方法时,它会表现出鸟类的飞翔行为。接下来 x 变量被赋值为 Dog 对象,因此当 x 变量执行 move() 方法时,它会表现出狗的奔跑行为。

四.重载:

在python中重载可以分为操作符重载或函数重载。

4.1 函数重载:

可以表现为有两个同名函数,当时因为其中的参数不同(参数个数,参数名称),在创建实例对象的时候,可以根据传入的参数来控制自己使用的函数。

python的方法重载有些特殊,在python中,如下的代码并不能实现方法重载:

def Aa():
    pass
def Aa(a):
    print(1)
def Aa(a, b):
    print(2)
# 这里想调用Aa的无参数版本,但是解释器会报错,提示找不到Aa方法
Aa()
#TypeError: Aa() missing 2 required positional arguments: 'a' and 'b'

为什么会出现这种违法静态语言直觉的结果?因为,在python中,方法也是attribute,方法名就是Key,所以每个方法名只能有一个方法体,以上代码中,当Aa被定义了多次,每一次新的定义都会覆盖之前的定义,所以,可以在dir()中看到,Aa最终指向的函数体是Aa(a,b),但解释器发现调用Aa时却缺少两个参数,所以会报错。

举个例子吧:

在Java中,方法重载有针对两个场景:

  1. 参数类型不同
  2. 参数个数不同

而Python无法在语法层面上针对第一种情况实现重载,但支持对第二种情况的重载,对应的语法就是默认参数,所以,要实现以上的重载,在pytho中应该这么写:

def Aa(a=1, b=1):
    print(2)
# 无参数版本
Aa()
# 一个参数版本
Aa(1)
# 两个参数版本
Aa(1, 2)

上面的这一个code反正不会wa!

4.2 操作符重载:

看这里,我也不太懂2333(欢迎留言!!!)


ojbk,差不多了,就这么点内容。