zoukankan      html  css  js  c++  java
  • python 面向对象编程

    所有方法的第一个参数必须是 self,self 表示类是实例本身,类似于 c++ 中的 this 指针。当然我们也可以讲 self 写成其它名字:

    1 class MyClass(object):
    2     i = 123
    3     def f(this):#self写成this也是正确的
    4         return 'hello'
    5 
    6 gel = MyClass()
    7 print(gel.i)
    8 print(gel.f())
    View Code

    构造函数

    行为基本和 c++ 中的构造函数类似,但当有多个构造函数时,只能调用最后一个构造函数,否则会报错:

     1 #!/usr/bin/python3
     2 
     3 class gel(object):
     4     def __init__(self):
     5         print("构造函数1")
     6     def __init__(self, cnt):
     7         print(cnt)
     8 
     9 # a = gel()#如果定义了多个构造函数,则只能调用最后一个,否则会报错
    10 a = gel(1)
    View Code

    注意:一个类中可以定义多个构造方法,但实例化类时只实例化最后的构造方法,即后面的构造方法会覆盖前面的构造方法,并且需要根据最后一个构造方法的形式进行实例化。因此通常一个类中只定义一个构造函数

    类的访问权限

    在 python 中,类成员变量名如果以 __ 开头,就会编程私有变或私有方法,只能在类内部访问,外部不能访问

    继承

    在继承中,基类的构造方法(__init__() 方法)不会被自动调用,需要在子类的构造方法中专门调用

    在调用基类的方法时需要加上基类的类名前缀,并带上 self 参数变量。区别于在类中调用普通函数时不需要带 self 参数

    在 python 中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找

    代码:

     1 #!/usr/bin/python3
     2 
     3 class Animal(object):
     4     def run(self):
     5         print('Animal is running...')
     6 
     7 class Dog(Animal):
     8     pass
     9 
    10 class Cat(Animal):
    11     pass
    12 
    13 dog = Dog()
    14 dog.run()
    15 
    16 cat = Cat()
    17 cat.run()
    18 
    19 # 输出:
    20 # Animal is running...
    21 # Animal is running...
    View Code

    注意:派生类中也不能调用基类的私有方法

    多态

    python 的多态不同于 c++ 中需要通过虚函数来实现。当子类和父类存在相同的方法时,运行代码时总是自动调用对应对象的版本:

     1 #!/usr/bin/python3
     2 
     3 class Animal(object):
     4     def run(self):
     5         # pass
     6         print('Animal is running...')
     7 
     8 class Dog(Animal):
     9     # pass
    10     def run(self):
    11         print('Dog is running...')
    12 
    13 class Cat(Animal):
    14     # pass
    15     def run(self):
    16         print('Cat is running...')
    17 
    18 dog = Dog()
    19 dog.run()
    20 
    21 cat = Cat()
    22 cat.run()
    23 
    24 animal = Animal()
    25 animal.run()
    26 
    27 # 输出:
    28 # Dog is running...
    29 # Cat is running...
    30 # Animal is running...
    View Code

    多重继承

    多重继承的类定义:

    class DerivedClassName(Base1, Base2, Base3):
      pass

    需要注意圆括号中父类的顺序,若父类中有相同的方法名,在子类使用时未指定,python 会从左到有搜索。

    调用对应方法时,若方法在子类中未找到,则从左到右查找父类中是否包含该方法

    代码:

     1 #!/usr/bin/python3
     2 
     3 class Animal(object):
     4     pass
     5 
     6 #大类
     7 class Mammal(Animal):
     8     pass
     9 
    10 class Bird(Animal):
    11     pass
    12 
    13 
    14 class Runnable(object):
    15     def run(self):
    16         print('running...')
    17 
    18 class Flyable(object):
    19     def fly(self):
    20         print('Flying...')
    21 
    22 class Dog(Mammal, Runnable):
    23     pass
    24 
    25 class Bat(Mammal, Flyable):
    26     pass
    View Code

    类的专有方法

    形如 __xxx__ 变量或函数名在 python 中是有特殊用途的

    除了前面的构造函数 __init__ 外还有:

    __str__ 和 __repr__

    类似于c++中重载<<运算符,将类对象按给定的格式转化成字符串

     1 class Test(object):
     2     def __init__(self, value='hello, world!'):
     3         self.data = value
     4 
     5 >>> t = Test()
     6 >>> t
     7 <__main__.Test at 0x7fa91c307190>
     8 >>> print t
     9 <__main__.Test object at 0x7fa91c307190>
    10 
    11 # 看到了么?上面打印类对象并不是很友好,显示的是对象的内存地址
    12 # 下面我们重构下该类的__repr__以及__str__,看看它们俩有啥区别
    13 
    14 # 重构__repr__
    15 class TestRepr(Test):
    16     def __repr__(self):
    17         return 'TestRepr(%s)' % self.data
    18 
    19 >>> tr = TestRepr()
    20 >>> tr
    21 TestRepr(hello, world!)
    22 >>> print tr
    23 TestRepr(hello, world!)
    24 
    25 # 重构__repr__方法后,不管直接输出对象还是通过print打印的信息都按我们__repr__方法中定义的格式进行显示了
    26 
    27 # 重构__str__
    28 calss TestStr(Test):
    29     def __str__(self):
    30         return '[Value: %s]' % self.data
    31 
    32 >>> ts = TestStr()
    33 >>> ts
    34 <__main__.TestStr at 0x7fa91c314e50>
    35 >>> print ts
    36 [Value: hello, world!]
    37 
    38 # 你会发现,直接输出对象ts时并没有按我们__str__方法中定义的格式进行输出,而用print输出的信息却改变了
    View Code

    这部分代码摘自:https://blog.csdn.net/luckytanggu/article/details/53649156

    通常__str__() 和 __repr__() 的代码是一样的,所以可以写成:

     1 #!/usr/bin/python3
     2 
     3 class Student(object):
     4     def __init__(self, name):
     5         self.name = name
     6 
     7     def __str__(self):
     8         return '学生名称:%s' % self.name
     9 
    10     __repr__ = __str__
    11 
    12 st = Student('xiao004')
    13 print(st)
    14 # 输出:
    15 # 学生名称:xiao004
    View Code

    __iter__

    如果想将一个类用于 for...int 循环,类似于 list 或 tuple 一样,就必须实现一个 __iter__() 方法。该方法返回一个迭代对象,python 的 for 循环会不断调用迭代对象的 __next__() 方法,获得循环的下一个值,知道遇到 StopIteration 错误时退出循环:

     1 #!/usr/bin/python3
     2 
     3 class Fib(object):
     4     def __init__(self):
     5         self.a, self.b = 0, 1
     6 
     7     def __iter__(self):
     8         return self#实例本身就是迭代对象,故返回自己
     9 
    10     def __next__(self):
    11         self.a, self.b = self.b, self.a + self.b
    12         if self.a > 100:
    13             raise StopIteration();#引发一个异常
    14         return self.a
    15 
    16 for n in Fib():
    17     print(n)
    18 # 输出:
    19 # 1
    20 # 1
    21 # 2
    22 # 3
    23 # 5
    24 # 8
    25 # 13
    26 # 21
    27 # 34
    28 # 55
    29 # 89
    View Code

    __getitem__

    上面定义的 Fib 虽然能作用于 for 循环,和 list 有点像,但不能和 list 一样用下标取元素。要像 list 一样按照下标取出元素,需要实现 __getitem__() 方法:

     1 #!/usr/bin/python3
     2 
     3 class Fib(object):
     4     def __init__(self):
     5         self.a, self.b = 0, 1
     6 
     7     def __getitem__(self, n):
     8         a, b = 1, 1
     9         for x in range(n):
    10             a, b = b, a + b
    11         return a
    12 
    13     def __iter__(self):
    14         return self#实例本身就是迭代对象,故返回自己
    15 
    16     def __next__(self):
    17         self.a, self.b = self.b, self.a + self.b
    18         if self.a > 100:
    19             raise StopIteration();#引发一个异常
    20         return self.a
    21 
    22 fib = Fib()
    23 print(fib[3])#3
    24 # for i in fib:
    25 #     print(i)
    View Code

    __getattr__

    正常情况下,调用类的方法或属性时,如果类的方法或属性不存在就会报错。当实现了 __getattr__() 方法会动态返回一个属性.:

     1 class Studet(object):
     2     def __init__(self):
     3         self.name = 'xiao004'
     4 
     5     def __getattr__(self, attr):
     6         if attr == 'score':
     7             return 95
     8 
     9 st = Studet()
    10 print(st.score)#st并没有score属性,动态返回一个属性
    11 # 输出:
    12 # 95
    View Code

    当调用不存在的属性 score 时,python 解释器会调用 __getattr__(self,‘score’) 尝试获得属性。

    注意:只有在没有找到属性的情况下才调用__getattr__。此外,如果我们调用一个不存在且 __getattr__ 中也没处理的属性,仍然会报错

    __call__

    Python中的函数是一级对象。这意味着Python中的函数的引用可以作为输入传递到其他的函数/方法中,并在其中被执行。 
    而Python中类的实例(对象)可以被当做函数对待。也就是说,我们可以将它们作为输入传递到其他的函数/方法中并调用他们,正如我们调用一个正常的函数那样。而类中__call__()函数的意义正在于此。为了将一个类实例当做函数调用,我们需要在类中实现__call__()方法。也就是我们要在类中实现如下方法:def __call__(self, *args)。这个方法接受一定数量的变量作为输入。 
    假设x是X类的一个实例。那么调用x.__call__(1,2)等同于调用x(1,2)。这个实例本身在这里相当于一个函数。

    这段描述摘自:https://blog.csdn.net/yaokai_assultmaster/article/details/70256621

    即:实现了 __call__() 函数后能将实例本身当成一个函数使用

    代码:

     1 class Student(object):
     2     def __init__(self, name):
     3         self.name = name
     4 
     5     def __call__(self):
     6         print('名称:%s' % self.name)
     7 
     8 stu = Student('xiao004')
     9 stu()#实现了__call__()函数后能将实例本身当成一个函数使用
    10 # 输出:
    11 # 名称:xiao004
    View Code

    问题

    双下划线开头的实例变量一定不能从外部访问么?

    答:不是。不能从类外直接访问双下划线开头的变量是因为 python 解释器对外改变了双下划线开头的变量的名称

    如:

     1 class Student(object):
     2     def __init__(self, name, score):
     3         self.__name = name
     4         self.__score = score
     5 
     6     def info(self):
     7         print('学生:%s; 分是: %s' % (self.__name, self.__score))
     8 
     9 stu = Student('xiao004', 100)
    10 # print(stu.__score)#错误,__score是私有变量
    11 print(stu._Student__score)
    View Code

    在此列中不能直接访问 __score 是因为 python 解释器对外把 __score 变量改成了 _Student__score,所以我们能在类外用过 _Student__score 访问 __score 变量

  • 相关阅读:
    javaweb请求编码 url编码 响应编码 乱码问题 post编码 get请求编码 中文乱码问题 GET POST参数乱码问题 url乱码问题 get post请求乱码 字符编码
    windows查看端口占用 windows端口占用 查找端口占用程序 强制结束端口占用 查看某个端口被占用的解决方法 如何查看Windows下端口占用情况
    javaWeb项目中的路径格式 请求url地址 客户端路径 服务端路径 url-pattern 路径 获取资源路径 地址 url
    ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段
    HttpServletResponse ServletResponse 返回响应 设置响应头设置响应正文体 重定向 常用方法 如何重定向 响应编码 响应乱码
    Servlet主要相关类核心类 容器调用的过程浅析 servlet解读 怎么调用 Servlet是什么 工作机制
    linq查询语句转mongodb
    winddows rabbitmq安装与配置
    Redis For Windows安装及密码
    出现,视图必须派生自 WebViewPage 或 WebViewPage错误解决方法
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/8833819.html
Copyright © 2011-2022 走看看