(一)面向对象编程
看到这个名字我不知道你会不会有疑惑,编程就编程呗,咋还欺负单身狗呢?非得找个对象像吗?非也。在程序员的眼里,万物皆对象。
那么对象是什么呢?简单地说,对象是一个具体存在的事物,占据时空位置。面向对象意思就是,python这门编程语言,的关注点是对象。它把所有东西都看作是对象。例如:一个标量是一个对象,一个变量是一个对象……。面向对象的 还有c++,Java等
与面向对象不同的是面向过程:这样的编程语言是更注重解决问题的过程。也就是解决问题的先后顺序。第一步,第二步……。其中C语言就是代表。
举个例子!一个古老的例子。
用两种思想解决:把大象装进冰箱里。
感觉是不是极为不一样,我们用代码实现以下。而且要注意的是,面向对象和面向过程是一种思维,一种解决问题的编程思维。
- 面向过程
# 面向过程
# 冰箱有四个格子
fridge = [None,None,None,None]
elephant = "elephant"
fridge[0] = elephant
print(fridge) # ['elephant', None, None, None]
- 面向对象(里面有部分代码是下面会讲到的)
# 创建冰箱类
class Fridge():
def __init__(self) -> None:
self.storage = [None,None,None,None] # 冰箱有四个内存
# 实现放东西进去的函数
def put(self,x):
for i in range(len(self.storage)):
if (i == len(self.storage)-1) and (self.storage[i] !=None):
print("冰箱满咯")
break
if self.storage[i] == None:
self.storage[i] = x
break
print(self.storage)
# 面向对象
fridge = Fridge() # 创建一个冰箱对象
elephant = "elephant" # 创建大象对象
fridge.put(elephant) # ['elephant', None, None, None]
最终的输出结果是一样的,可是两种思想极为不同。第一种符合逻辑思维,第二种更像是现实世界我们的做法。
第一种方法它的整体是紧密相连的,即高耦合,没有明确的分工。这在大型的项目中其实是不太好的,如果以后的代码要改,你得从上往下看代码,估计你得找半天。
第二种做法,也有一定的局限性,他需要首先将冰箱的所有属性和功能都定义好,如果没有这个方法,就没法实现。但是加功能也是方便的,有利于代码的维护。
这便是面向对象和面向过程了。
(二)类 class
理解完上面那些,我们可得好好看一下面向对象具体的工作流程是怎么样的。也就是理解一下上面看不懂的代码是啥。
我们先说一下,面向对象的过程:创建类=>创建实例对象=>调用方法实现需求=>类和对象维护
(1)从上面的代码中我们看到了创建冰箱类,那么类是什么?
简单地讲,类就是一类事物,例如:人类,鸟类,动物,植物,微生物。这些都不是具体的事物,所以类不是对象。上面说过对象是要具体的实物。
想必你大概知道类是啥东西了吧?它是一类事物属性特征和功能的集合。
举个例子!
- 人类:
属性:名字,一个脑袋,四肢,有衣服,等
功能:吃、喝、拉、撒、走、跑、蹦、爬……
那么怎么用代码操作呢?
# 定义人类
class person():
# 属性特征
name=""
head = 1
limb = 4
clothes = True
# 功能:
def eat(self):
print("i can eat!")
def run(self):
print("i can run!")
(2)如何创建一个实例对象呢?
我们知道了人类是个啥意思。那么李四和人类的关系呢?李四叫做对象,因为他是一个具体的人,它属于人类。在python里面,我们可以把李四叫做是人类的一个实例对象。一个特殊的人。
lisi = person() # 这个过程叫做实例化,把抽象的人转变为具体的人的过程。
lisi.name = "lisi"
(3)理解 => 实践
通过这样的解释,估计大家对类和实例对象都有了深刻的理解。如果还不够深刻,那就再看一遍。
类定义的代码格式:
类名一般是大写开头的。
class 类名(参数列表):
# 属性和功能
类里面的变量:类变量和实例变量
类变量:不需要实例就可以直接使用,相当于绑定在类上,而不是绑定在实例上。但是,类变量也可以在实例中调用。所有类别实例之间可以共享的值。一般不使用。
实例变量:绑定在实例上,无法通过类访问得到
通过代码来理解类变量和实例变量的区别,访问变量和函数的方法:实例.变量、实例.方法()
class Person():
# 这个是类变量
head = 1
# 注意这里的参数self,这是专门用来指向实例对象的,私人定制哦。
# 而且类里面的方法(类里面的函数都叫做方法)的第一个参数必须是self
# 使用这个函数来设置参数。
def set_attr(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
# 类里面的函数叫做方法
# 他和函数唯一的区别就是,必须要有参数,且第一个参数是self,原因是为了绑定实例对象的一些属性嘛
def eat(self):
print("i can eat!")
def run(self):
print("i can run!")
# 中文也能做变量名哦,但是绝对不要使用,这里只是个例子
张三 = Person() # 实例化
print(Person.head) # 1
print(张三.head) # 1
张三.head = 2
print(Person.head) # 1 注意,这里是不会改变的哈
print(张三.head) # 2
张三.set_attr("张三","男",18)
print(张三.name,张三.sex,张三.age) # 张三 男 18
print(Person.name) # AttributeError: type object 'Person' has no attribute 'name'
好了理解完,类变量和实例变量的区别之后,我发现一个小问题,我们写了一个函数来给实例赋值,调用set_attr我感觉还是太麻烦了。能不能在我实例化的时候就设置好了呢?
答案是python提供了这样的方法,叫做构造函数,我们有时候也叫初始化函数。
构造函数:在我们初始化实例的时候,它会自动调用构造函数,主要适用于帮我们完成一些变量和函数的初始化。这个函数的名字叫做 __init__()
于是上面的代码又可以写成这样:
class Person():
# 构造函数
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("i can eat!")
def run(self):
print("i can run!")
# 注意了哦,这里面现在必须根据__init__函数里面的参数列表进行传参哦,否则会报错。
张三 = Person("zhangsan","man",19) # 实例化
print(张三.name,张三.sex,张三.age) # 张三 男 19
继承:也就是说,类可以继承一个类,被继承的类叫做父类,继承的类叫做子类。怎么理解呢?动物是一个类,人类是一个类,但是人类属于动物。
子类可以使用父类的方法,继承的方法就是在列表参数里加上父类的类名。
直接上代码!
class animal():
def sleep(self):
print("i am sleepy!")
# 继承
class Person(animal):
# 这个是类变量
head = 1
# 构造函数
def __init__(self,name):
self.name = name
def eat(self):
print("i can eat!")
zhangsan = Person("zhangsan")
zhangsan.eat()
zhangsan.sleep()
多继承:可能一个事务并不只是一类,可能属于很多类。橘猫属于猫,属于猫科动物,属于动物,属于生物。
class creatures():
a = 3
class animal():
a = 1
class cat(animal,creatures):
a = 2
c = cat()
print(c.a) # 2 就近原则,先在自己的作用域找,找不到,就根据参数列表按顺序找
class creatures():
a = 3
class animal():
a = 1
class cat(animal,creatures):
b = 2
c = cat()
print(c.a) # 1 cat里面没有a,根据参数列表在animal里面找到了。
现在进入下一个话题:方法重写:
啥意思嘞,就是说,有时候父类有一个方法,我觉得不满足我的需求,我想重新写过。这时候python给出了解决方案:方法重写。
补充一个小知识点:所有的类都默认继承自object。里面有一个str()方法用来打印实例对象的信息的。我们现在重写这个方法!
class animal():
def __init__(self,name,sex) -> None:
self.name = name
self.sex = sex
a=animal("猫","母")
# 我们直接print(实例变量),python会自动调用__str__方法
print(a) # <__main__.animal object at 0x0000025A8460E5C0> 显示的内容看不懂,重写该方法
class animal():
def __init__(self,name,sex) -> None:
self.name = name
self.sex = sex
def __str__(self) -> str:
return "Animal, name:{},sex:{}".format(self.name,self.sex)
a=animal("猫","母")
print(a)
还有一个没说到的知识点就是supper(),supper()是一个类,简单来讲,它可以用于调用父类中的方法。这样的说法是不严谨的。
了解更多:
【1】https://blog.csdn.net/wanzew/article/details/106993425
【2】https://www.runoob.com/w3cnote/python-super-detail-intro.html
class A():
def __init__(self,name,sex) -> None:
self.name = name
self.sex = sex
print("A")
def a(self):
print("a")
class B(A):
def __init__(self,name,sex) -> None:
super().__init__(name,sex)
print("B")
def a(self):
print("b")
b = B("123",1)
print(b.sex)
b.a()
最后一个小知识点:私有变量
1、单下划线开头的变量:
变量前的单下划线表示表面上私有 ;
但是其实这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
class Dog(object):
_colour = '黑色'
age = 2
dog = Dog()
print(dog._colour) # 对象点属性的时候虽然不会自动提示,但是你硬写上去也能打印出来
2、双下划线开头的变量:
双下划线开头的变量是类里面的私有变量,只能在类的内部访问,在外部是不允许访问的和修改的
class Dog(object):
_colour = '黑色'
__age = 2
dog = Dog()
print(dog.__age) # 结果报错 AttributeError: 'Dog' object has no attribute '__age'
但是可以使用方法去间接的获取和修改
class Dog(object):
_colour = '黑色'
__age = 2
def get_age(self): return self.__age
def set_age(self, age):
self.__age = age
dog = Dog() print(dog.get_age())
dog.set_age(6) print(dog.get_age())
其实不用间接获取也能获取到,python只是把私有变量的名字给修改了
class Dog(object):
_colour = '黑色'
__age = 2
def get_age(self): return self.__age
def set_age(self, age):
self.__age = age
dog = Dog()
print(dog._Dog__age) # 使用 _类名 + 变量名 当作属性去访问依然能访问到
所以,python里面没有真正意义上的私有变量
人类的单词应该是Human,我不应该用Person的,但是……,好吧,我懒得改了,摆烂了,将就着看嘛。码字超累的!