Python 面向对象

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


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容

  • 一、面向对象,这个对象到底是什么? 这个对象不是python中的实例,python中我们把一个类的实例也叫做对象,...
    youngkun阅读 915评论 0 2
  • 一、面向对象思想 1.面向对象思想设计 基于哲学观点:万物皆对象举例说明:案例一:我想吃大盘鸡面向过程 ...
    hollow_02f9阅读 1,617评论 0 0
  • 本节课纲 类和对象 类的定义 self参数 初始化方法init() _str_()方法 面向对象vs面向过程 私有...
    郭_扬阅读 4,927评论 0 7
  • 1.1.类和对象 1.1.1.万物皆对象 分类是人们认识世界的一个很自然的过程,在日常生活中会不自觉地将对象进行分...
    Rolle_Wang阅读 716评论 0 0
  • 走吧 少年 去看北方 带上 你的梦想 向阳而行 在激情澎湃年的岁月里,我婉转的回眸,而你已远行 你轻盈...
    眷恋的乡愁阅读 398评论 0 2