美文网首页工作生活
Python 面向对象

Python 面向对象

作者: 前行的乌龟 | 来源:发表于2019-07-02 00:31 被阅读0次

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 有importfrom 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 本身的理解,理解了这其中的区别非常有助于我们接下来的学习

  • 方法 - 传统的 对象.方法,定义在 class 里
  • 函数 - 不用对象直接就行用的,不用 class 就能定义
  • 区别 - 依靠于对象

呵呵,大家要是熟悉的话一看就懂,但是刚从 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不一样
  1. 成员变量 - 构造函数中写出来一个就是一个成员变量
class A(object):

    def __init__(self, name,age):
        self.name = name
        self.age = age
  1. 类变量 - 在类的内部,但是在构造函数之外写的,和 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修改类变量的值,那么所有对象的类变量的值都会改变,注意这点
  1. 访问控制符 - 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是能.出来的

  1. 属性限制 -

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种修饰方法的装饰器:

  1. @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

  1. @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
  1. @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种方法都可以的~


相关文章

网友评论

    本文标题:Python 面向对象

    本文链接:https://www.haomeiwen.com/subject/wynbcctx.html