python 面向对象部分较 java 变化有些大,单独拿出来,方便查阅
创建对象和继承
class Person(object):
def speak(self, message):
print(message)
python 里 object 是所有类的父类,python 类若是不需要继承,则必须写(object)
,这个()
就是表示父类
自然继承的也是写在()
里面的:B 继承 A
class A(object):
def speak(self):
print("A")
class B(A):
def speak(self):
print("B")
蛋疼的导包问题
python 有import
,from import
2种导包的方式,但是这2种方式导出来的包在使用上有差别
-
import
导入,因为是导入库整体,需要加上库名,Person.Person() 才行
import Person
person = Person.Person()
person.speak("AAA")
-
from import
导入,不用加库名,操作上和 java 一样,* 表示导入所有
from Person import *
person = Person()
person.speak("AAA")
一般问题不大的话,推荐 `from xxx import * 这种方式,在 API 使用上贴合传统
2个概念:函数 和 方法
函数
和 方法
在代码中其实是2个有区别的概念,这点在 java 中没能体现出来,所以从 java 上收的朋友们会混淆这2个概念,但是在 pyhton 中函数和方法的区别清清楚楚的表现出来了,甚至重要到了我们对代码和 python 本身的理解,理解了这其中的区别非常有助于我们接下来的学习
呵呵,大家要是熟悉的话一看就懂,但是刚从 java 那过来的小伙伴们有点懵,是的我刚看 python 这样调方法的时候也是有点毛不找头脑
其实大家看看函数
和 方法
的定义差不多就能明白
# 这是函数,直接在 .py 文件里兴义就能用
def method1(name):
print(name)
# 函数的使用,不用对象就能使用
method1("函数")
# 这是方法,java 中我们常用的思路
class A(object):
def speak(self):
print("A")
# 方法的使用不能离开对象
a = A()
a.speak()
我们刚接触 Python 的 print
就是个函数,我们不用对象.
这类函数叫 python 的内建函数
,是依托于各种各样的 python 库提供给我们的
python 所有类的基类是 object
,里面定义了许多以 __xx__
规范命名的方法,这些方法被称为魔术方法/特殊方法
,负责的基本都是诸如 java 中的 toString
,equse
,hasCode
这类类的基本方法,python 中这些 特殊方法
干的也基本是这个活,只不过被起了个特殊的名字,有自己的命名规范,最主要的是 python 的 内建函数
大多数跑起来就是调用对象的这些 特殊方法
,比如说 print
函数调用的就是对象的 __str__
方法
self
突一说 self
大家应该会摸不着头脑吧,其实上面已经出现过 self
了,就在方法里
# 就是这个 self
def speak(self):
print("A")
python 有个特性就是要求所有方法的第一个参数必须传入 self
,可以把 self
看成 java 的 this
,其实本质也是代指当前对象本身,这是 python 自身的特性,有关于方法的后续,在 2.7版本中,不写 self
是会报错的,在 3.7 版本中虽然不会报错了,但是编译器一直会提醒你要加上 self
self
不是不能换个名字,你直接写 this
都可以运行,但是长久以来 self
变成了 python 规范的一部分,大家还要不要改名字的好8
我们看个例子:
class A(object):
def speak(self, name):
print(name)
a = A()
a.speak("汪汪")
我们正常调用一个对象的方法,看参数,我们只要传给 name
这个参数机型了,self
我们没给吧,这是因为系统会替我们给这个参数的,这涉及到 python 中方法到底如何运行的
python 会把 a.speak("汪汪")
翻译成 A.speak(a, "汪汪")
,这样的话大家就明白了,python 中函数
才是最基础的,方法最终都是会变换成函数
去执行的,self
这个的意义就是把具体的对象带着,要不函数
缺参数
ok 了概念说的差不多了,后面参照 java 类的定义挨个说了
构造函数和成员变量
__init__
就是 python 的构造函数了,一看就是 object 的特殊方法
class A(object):
def __init__(self, name):
self.name = name
print("A:" + name + "...")
def speak(self, name):
print(name)
class C(A):
def __init__(self, name, age):
A.__init__(self, name)
self.age = age
print("C:" + age + "...")
c = C("NBA", "CAB")
print(c.name)
上面这个例子写的很全面了
- 首先基类
A
用__init__
实现构造函数 - 然后在
__init__
里面,用self.xx
写多少就是表示类A
有多少个属性,如上面有一个name
属性 - 然后子类
C
通过父类class.__init__(self,参数...)
的方式实现父类构造方法,这里不用super
的,但是python 本身支持super
,只是super
不能用在这里
哈哈,是不是被 python 蛋疼的写法惊到了,后面还有更惊讶的
最后我们运行下上面的
A:NBA...
C:CAB...
NBA
super
上面既然说到了 super
那么就来说说吧,关于 super
python 其实和 java 一样,只不过 python 这里super
变成了内建函数
了
class A(object):
def speak(self, name):
print("A speak...")
class C(A):
def speak(self, name):
# super 方式1
super(C, self).speak(name)
# super 方式2
A.speak(self,name)
print("C speak...")
super
这里哟个问题,super(子类class,self).speak("XX")
这是 2.7版本的写法,3.7版本是super().speak("XX")
,但是坑爹的是 3.7版本的总是出错
另外我们直接用系统的函数方式也可以,效果一样父类class.speak(self,name)
类变量和成员变量
这又是 python 区别与 java 的地方了
-
成员变量 - 就是在
__init__
构造方法中self.
的变量了 -
类变量 - 类变量在概念上了
static
很像,属于类的而不是对象的,但是 python 中不一样的是值的修改和static
不一样
- 成员变量 - 构造函数中写出来一个就是一个成员变量
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
- 类变量 - 在类的内部,但是在构造函数之外写的,和 java 的成员变量声明方式一样,但是必须给初始值,也就是初始化
class A(object):
song = 10
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, name):
print("A speak...")
a1 = A("A1", "A11")
a2 = A("A2", "A22")
a1.song = "new_one"
print(a1.song)
print(a2.song)
A.song = "new_one"
print(a1.song)
print(a2.song)
new_one
10
new_one
new_one
- 修改一个对象的
类变量
,发现只有这个对象的类变量
值变了 - 但是使用
class
修改类变量
的值,那么所有对象的类变量
的值都会改变,注意这点
-
访问控制符 - python 实际上都是
public
的,没有private
这个概念,但是我们都是从java
过来的,所以 python 兼顾下提供了一个不算是办法的办法__xx
的命名方式
class A(object):
song = 10
def __init__(self, name, age, duck):
self.name = name
self.age = age
self.__duck = duck
a1 = A("A1", "A11", "duck1")
比如 new 一个 A
的对象出来,我们.
一下,看看能不能看到duck
这个属性,看不到那就是用不了了,也就是 = private
了
看到了没有,
__xx
的确 = private
,但是我们要说的是这只是一种取巧的方式,python 提供dir()
函数可以看到一个对象中的所有属性,这里我们看一下print(dir(a1))
不知道大家注意没有
_A_duck
这个属性,python 给加了__xx
的属性改了个名,我说怎么.
不到呢,原来是这样啊
然后我试了试,发现这个_A_duck
虽然不能.
出来,但是我们前行拼接代码还是能拿到值的,可能是我这得 IED 处理的吧,早先_A_duck
是能.
出来的
- 属性限制 -
python 是一种动态语言,不用编译,直接运行 python 文件,这说明啥,我们所有在代码中的操作有可能改变 python 文件,这在 java 中是不可想象的,举个例子
我们在 python 中动态给对象价格属性进去
class A(object):
song = 10
def __init__(self, name, age, duck):
self.name = name
self.age = age
self.__duck = duck
def speak(self, name):
print("A speak...")
a1 = A("A1", "A11", "duck1")
a1.aa = "33"
print(a1.aa)
➜ Test python Test.py
33
看到没,java 过来的同学需要习惯下,这叫扩展属性,在 kotlin 中实现起来还是要几行代码的
var News.name: String
get() = name
set(value) {
name = value
}
没想到 python 真是太简洁了,直接写就行,然后有的时候有朋友就不喜欢这样了,python 也提供了相关的手段:__slots__
__slots__
是个集合,除了写在__slots__
里面的属性,其他的属性都不能动态添加了
class A(object):
song = 10
__slots__ = ( "name", "age", "__duck")
def __init__(self, name, age, duck):
self.name = name
self.age = age
self.__duck = duck
def speak(self, name):
print("A speak...")
这时候你再动态添加属性是会报错的
但是__slots__
也有个问题,那就是一旦写了__slots__
类属性就变成只读的了,不能再赋值了,大家可以自己试下,类属性即便写在__slots__
里也没用
方法装饰器
python 有3种修饰方法的装饰器:
- @staticmethod - 静态方法装饰器
- @classmethod - 类方法装饰器
- @property - 把方法变为属性使用
-
@属性名.setter - 设置属性,配合
@property
使用
@staticmethod
python 支持部分静态概念,期中只支持方法级别,用@staticmethod
修饰方法即可,python 的静态方法不用写self
因为没有对象参与期中,但是要注意啊类属性
静态方法不能使用,这是和 java 区别的地方
class A(object):
song = 10
@staticmethod
def tom(x, y):
return x + y
def __init__(self, name, age, duck):
self.name = name
self.age = age
self.__duck = duck
@classmethod
也可以叫类方法
,同类属性
一个意思,操作也一样,不过区别的是第一个参数命名是cls
其实和self
一样,叫什么名字都可以,叫self
是因为设计到对象调用,叫cls
表示类
class A(object):
song = 10
@staticmethod
def tom(x, y):
return x + y
@classmethod
def tom_class(cls, name):
return name
def __init__(self, name, age, duck):
self.name = name
self.age = age
self.__duck = duck
print(a1.tom_class("AA"))
print(A.tom_class("AA"))
➜ Test python Test.py
AA
AA
@property
加了这个装饰器后,方法就能像属性一样使用,不用在加()
了,不过@property
修饰的方法不能有参数cls
除外并且不能赋值,想要有参数就需要@属性名.setter
了,@property
和@属性名.setter
更多的时候当做 get/set 来用
class A(object):
song = 10
def __init__(self, name, age, duck):
self.name = name
self.age = age
self.__duck = duck
@staticmethod
def tom(x, y):
return x + y
@classmethod
def tom_class(cls, name):
return name
@property
def duck(self):
return self.__duck
@duck.setter
def duck(self, value):
self.__duck = value
a1 = A("A1", "A11", "duck1")
print(a1.duck)
a1.duck = 30
print(str(a1.duck))
➜ Test python Test.py
duck1
30
类型转换
python 除了基本数据类型的转换之外,没有提供诸如:子类转换为父类
的方式,但是我们依然可以实现部分这个目的,比如按照父类的方法去执行
现在有2个类
class A(object):
def __init__(self, name, ):
self.name = name
def speak(self, name):
print("A speak...")
class C(A):
def __init__(self, name, age):
A.__init__(self, name)
self.age = age
def speak(self, name):
super(C, self).speak(name)
print("C speak...")
实现这个目的有2个思路:
- python 里方法也是对象,所以可以把子类对象的方法指向父类对象的相关方法
c1 = C("name2", "age2")
a1 = A("name1")
c1.speak = a1.speak
c1.speak("DD")
- 另一个就是指定以父类来执行某个方法
c1 = C("name2", "age2")
a1 = A("name1")
A.speak(c1, "DD")
c1.speak("DD")
这2种方法都可以的~