首页 > 编程语言 >Python基础 - 面向对象

Python基础 - 面向对象

时间:2022-10-12 16:04:31浏览次数:38  
标签:__ .__ show Python self 基础 value 面向对象 def

面向对象基础入门, 理解概念为主, 其妙用需要很长时间去领悟哦.

引入

Python 既是面向过程, 也能面向对象.

初学来理解为啥要面向对象, 不太可能, 用处呢, 是在工程项目中, 代码优化, 封装等.. 才会真正理解哦.

面对对象3大特点:封装 继承 多态
面对对象的一个关键性观念在于,将数据及对数据的操作封装在一起,组合成一个相互依存,不可分割的整体.
不同对象间,通过消息机制来通信或者同步;对于同类型对象(instance)进行分类, 抽象后,得出共同特征而形成了类
面对对象程序设计关键在于如何合理地定义这些类并且组织多个类之间的关系

创建类时用变量形式表示对象特征的成员成为数据成员(attribute); 用函数形式表示对象行为的成员称为**成员方法(method)

类的定义与使用

class Car:
def info(self):
print('This is a car.')
car = Car()
car.info()
This is a car.
isinstance(car, Car)  # 是否是某类的实例
True
isinstance(car, str)
False
type(car)  # 是一个对象类型
__main__.Car
33

数据成员与成员方法

Python 中并没有对私有成员提供严格的访问保护机制,通过一种特殊的方式"对象名.__类名__xxx"也可以在外部访问

私有成员与方法

class A:
def __init__(self, value1=0, value2=0): # 构造方法
self._value1 = value1
self.__value2 = value2 # 私有属性

def set_value(self, value1, value2): # 公有方法
"""给私有属性传值"""
self._value1 = value1 # 在类的内部,可以直接访问私有成员
self._value2 = value2

def show(self):
"""间接给外部访问私有成员"""
print(self._value1)
print(self.__value2)

a1 = A()
a1._value1  # 在类外部可以直接访问非私有成员
0
a1.__value2  # 在类外部不可以直接访问私有成员
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-11-286155ff3344> in <module>
----> 1 a.__value2 # 在类外部不可以直接访问私有成员


AttributeError: 'A' object has no attribute '__value2'
a1.show()  # 但可以通过间接方法去访问,不过这有些不可控
0
0
a1._A__value2  # Python 的大BUG, 根本不存在私有的,不存在的
0
a1._A__Value2 = 'cj'  # 于是,什么私有啥的,就轻松被改掉了
a1._A__Value2
'cj'
a1._A__value2  # 但是为什么第二次查看就没了???
0
a2 = A()
a2._A__value2
0

哦,我好像知道单例模式能干嘛了,就是改掉一个东西,所以东西都要跟着变呢 重写new方法

# 单例模式测试
class A:

__instance = None # 定义一个类属性

def __new__(cls): # 类方法是cls,实例方法是self
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance

def __init__(self, value1=0, value2=0): # 构造方法
self._value1 = value1
self.__value2 = value2 # 私有属性

def set_value(self, value1, value2): # 公有方法
"""给私有属性传值"""
self._value1 = value1 # 在类的内部,可以直接访问私有成员
self._value2 = value2

def show(self):
"""间接给外部访问私有成员"""
print(self._value1)
print(self.__value2)

a1 = A()
a2 = A()
a3 = A()
print(a1._value1, a2._value1)  # 正常访问实例属性值
0 0
a1._value1 = 'CJ'  # 改变a1的共有实例属性
print(a1._value1, a2._value1, a3._value1)  # 厉害了,a2 a3也跟着变了, 有点像飞机大战,给100架飞机(对象)改颜色,厉害了
CJ CJ CJ
print(dir(A), end=' ')  #  dir(obj) 查看对象成员
['_A__instance', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'set_value', 'show'] 
print(dir(a1), end = ' ')
['_A__instance', '_A__value2', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_value1', 'set_value', 'show'] 
  • _ xxx,保护成员,只有类, 子类可以访问这些成员数据,当然外部也可以,但不建议
  • 一或多个下划线的成员**不能 from module import* ** 除非指定__ all __ = [data1, data2 ]说明可以被导入
  • __ xxx__ 系统定义的特殊成员
  • __ xxx 为私有成员,只有在类内部能访问也不能继承,但可以内部定义方法,间接访问
  • Python其实并不存在私有成员, 在外部可通过对象名._ 类名__ xxx这样的特殊形式访问

数据成员

  • 类数据成员(类属性 类方法) 对象数据成员(实例对象属性 实例对象方法)
  • 同一个类的不同对象(实例)的数据成员(属性,方法)互不影响(除非单例模式)
  • 类的数据成员(类属性, 类方法)是该类所有对象共享的,一般不在任何一个成员方法中定义
  • 主程序中(类外部),对象数据成员属于实例,只能通过对象名访问; 类数据属于类,可以通过类名或对象名访问

利用类数据成员的共享性, 可是实时获得该类的对象数量, 并且可以控制类创建的对象最大数量

class Demo(object):
total = 0 # class attribute
def __new__(cls, *args, **kwargs):
if cls.total >= 3:
raise Exception("You can only creat up to 3 objects.") # 自定义异常
else:
return object.__new__(cls) # 在范围内则不重写object的__new__方法

def __init__(self):
Demo.total += 1 # 类去访问类属性,作用于所有的实例对象

t1 = Demo()
t1  # 实例化对象,返回的是一个地址
<__main__.Demo at 0xb1b789c978>
t2 = Demo()
t3 = Demo()
t4 = Demo()  # 超出了3个(condtion),会被__new__方法限制
---------------------------------------------------------------------------

Exception Traceback (most recent call last)

<ipython-input-4-44c1d26c9790> in <module>
----> 1 t4 = Demo() # 超出了3个(condtion),会被__new__方法限制


<ipython-input-1-c52d2c3e245b> in __new__(cls, *args, **kwargs)
3 def __new__(cls, *args, **kwargs):
4 if cls.total >= 3:
----> 5 raise Exception("You can only creat up to 3 objects.") # 自定义异常
6 else:
7 return object.__new__(cls) # 在范围内则不重写object的__new__方法


Exception: You can only creat up to 3 objects.
x = 10
if x > 20:
raise Exception("this is a wrong message created by myself") # raise 好像我还不会用呢

成员方法 类方法 静态方法

在面对对象程序设计中,函数和方法是有本质区别的.方法一般指与特定实例绑定的函数, 通过对象调用方法时, 对象本身将会被作为第一个参数自动传递过去,普通函数则不具备这个特点.例如,内置函数sorted()必须要指明要排序的对象, 而对象的sort()方法则不需要, 默认是对当前序列进行排序.

class Demo:
pass

t = Demo()
t
<__main__.Demo at 0xb1b20c6358>
def test(self, v):
"""动态增加类属性"""
self.value = v
t.test = test  # 动态增加普通函数 看不懂这段代码???
t.test
<function __main__.test(self, v)>
t.test(t, 3) # 需要我self传递参数 ???
print(t.value)
3

看不懂下面这段代码

import types

t.test = types.MethodType(test, t) # 动态增加绑定的方法
t.test
<bound method test of <__main__.Demo object at 0x000000B1B20C6358>>
t.test(5)  # 不需要为self 传递参数
print(t.value)
5
  • Python类成员方法大致可分为:**公有方法, 私有方法, 静态方法, 类方法
  • 公有, 私有方法指属于对象的实例方法,私有方法一般以两个或多个下划线开头,它们都可以访问属于类和对象的成员
  • 公有方法通过对象名直接调用,而私有方法只能在其他实例方法中通过前缀self进行调用,或在外部通过特殊形式调用(对象名._ 类__xxx)
  • Python还支持大量特殊方法__ xxx___,往往与某个运算符或内置函数相对应
  • 所有实例方法(私有, 公有, 抽象, 特殊, 类方法等),都必须至少有一个名为self的参数,必须是第一个形参代表当前对象
  • 内部访问类成员需要self,外部则不需要, 在外部通过对象名调用公有方法时,需要显式为该方法的self,传递一个对象名, 用来指定访问哪个对象的成员(反恐精英,人在人里不是人,是self, 人在枪里是才是人,是形参)
  • 静态方法和类方法都可以通过类名和对象名调用,但不能直接访问属于哪个对象的成员,只能访问属于类的成员
  • 它们不属于任何实例不会绑定到任何实例,与实例方法相比,能够减少很多开销
  • 类方法以cls作为第一个参数表示该类自身,在调用时不需要要为其传值,静态方法可以不接受任何参数
class Root:
__total = 0
def __init__(self, v): # 构造方法
self.__value = v
Root.__total += 1 # 给类属性传值
self.x = 0

def show(self): # 普通实例方法,以self作为第一个参数
print('self.__value:', self.__value)
print('Root.__total:', Root.__total)

@classmethod # 修饰器,声明类方法
def class_show_total(cls): # 类方法以cls作为第一个参数
print(cls.__total)

@staticmethod # 修饰器,声明静态方法
def static_show_total(): # 静态方法,可以没有参数
print(Root.__total)
a1 = Root(666)
a1.show()
self.__value: 666
Root.__total: 3
a1.class_show_total()  # 通过实例对象来调用类方法
3
r.static_show_total()  # 通过实例对象调用静态方法
3
r2 = Root(999)
Root.class_show_total()  # 通过类名调用类方法
1
Root.static_show_total()  # 通过类名调用静态方法
1
Root.show()   # 通过类名不能调用实例方法
---------------------------------------------------------------------------

TypeError Traceback (most recent call last)

<ipython-input-52-c0fdb99b2d01> in <module>
----> 1 Root.show() # 通过类名钓友实例方法,失败


TypeError: show() missing 1 required positional argument: 'self'
Root.show(r2)   # 通过 类名.实例方法名(对象) 来进行调用
self.__value: 999
Root.__total: 1

实例对象可以访问实例属性 实例方法 类属性 类方法 静态方法; 类名可以访问类方法 类属性 静态方法, 不能直接访问实例方法 实例属性

Root.x  # 通过类名不能直接访问实例属性
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-55-5e11f75167b2> in <module>
----> 1 Root.x # 通过类名不能直接访问实例属性


AttributeError: type object 'Root' has no attribute 'x'

属性 property

属性(property) 是一种特殊形式的成员方法,结合了公开数据成员和成员方法的优点, 既可以像成员方法那样对值进行必要的检查,又可以像数据成员一样灵活访问
Python3x中, 如果设置属性为只读则无法修改其值,也无法为对象增加与属性同名的新成员,也无法删除对象属性(不能增, 改, 删)

class Test:
def __init__(self, value):
self.__value = value # 私有数据成员

@property # 修饰器, 定义属性,提供对私有数据成员的访问
def value(self):
return self.__value # 只读属性,无法增, 改, 删
t = Test(666)
t.value # 只读属性
666
t.value = 999  # 不允许修改值
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-62-cb004e267824> in <module>
----> 1 t.value = 999 # 允许修改值


AttributeError: can't set attribute
del t.value  # 不允许删除值
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-63-ec615fe9a488> in <module>
----> 1 del t.value # 不允许删除值


AttributeError: can't delete attribute
t.value
666

将其改成,可读,可修改,不可以删除

class Test:
def __init__(self, value):
self.__value = value

def __get(self):
"""读取私有数据成员的值"""
return self.__value

def __set(self, v):
"""修改私有数据成员的值"""
self.__value = v

value = property(__get, __set) # 可读可改, 指定相应的读写方法

def show(self):
print(self.__value)

t = Test(666)
t.__value  # 不能直接访问私有属性
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-66-e41fedfc61d4> in <module>
----> 1 t.__value


AttributeError: 'Test' object has no attribute '__value'
t.show()  # 可通过间接方法的方式来访问
666
t.__get()  # 不可以访问私有方法
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-69-d63121715559> in <module>
----> 1 t.__get()


AttributeError: 'Test' object has no attribute '__get'
t.value = 'cj'  # property,这里允许修改属性值
t.show()  # 对应的私有变量也得到了修改
cj
del t.value  # 不允许删除属性
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-72-cd1108188511> in <module>
----> 1 del t.value


AttributeError: can't delete attribute

将私有属性设置为可读, 可修改, 可删除

class Test:
def __init__(self, value):
self.value = value

def __get(self):
"""访问私有数据成员"""
return self.__value

def __set(self, v):
"""修改私有数据成员"""
self.__value = v

def __del(self):
"""删除私有数据成员"""
del self.__value

value = property(__get, __set, __del) # 可读, 可写, 可删除的属性

def show(self):
print(self.__value)

t = Test(999)
t.show()  # 间接访问私有成员的方法
999
t.value  # 可读
999
t.value = 'cj'  # 可改
t.value
'cj'
del t.value  # 可删除
t.value
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-78-02db3359037c> in <module>
1 del t.value # 可删除
----> 2 t.value


<ipython-input-73-674abf9bc7e5> in __get(self)
5 def __get(self):
6 """访问私有数据成员"""
----> 7 return self.__value
8
9 def __set(self, v):


AttributeError: 'Test' object has no attribute '_Test__value'
t.show()  # 对象值都删除了,还访问个毛毛呀
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-79-845e971b547d> in <module>
----> 1 t.show() # 对象值都删除了,还访问个毛毛呀


<ipython-input-73-674abf9bc7e5> in show(self)
18
19 def show(self):
---> 20 print(self.__value)
21
22 t = Test(999)


AttributeError: 'Test' object has no attribute '_Test__value'

继承 多态

子类/派生类可以继承父类的所有公有成员,不能继承其私有成员
可用super().方法(), 或者基类名.方法名() 实现子类的追加,而不覆盖基类的数据成员

要求:设计Person类, 并根据Person派生Teacher类,并分别创建Person类与Teacher类的对象

# 基类:
class Person:
def __init__(self, name=' ', age=20, sex='man'):
"""通过调用方法进行初始化,可实现对参数更好地控制"""
self.set_name(name)
self.set_age(age)
self.set_sex(sex)

def set_name(self, name):
"""校验name必须是string"""
if not isinstance(name, str): # 如果,name 不是 str的实例(非字符串,报错)
raise Exception("name must be a string.")
self.__name = name

def set_age(self, age):
"""校验age必须是integer"""
if type(age) != int:
raise Exception("age must be an integer.")
self.__age = age

def set_sex(self, sex):
"""校验sex必须是man or woman"""
if sex not in ('man', 'woman'):
raise Exception("sex must be 'man' or 'woman'")
self.__sex = sex

def show(self):
print(self.__name, self.__age, self.__sex, sep='\n') # 换行输出


# 派生类
class Teacher(Person): # 继承 Person类
def __init__(self, name='', age=22, sex='man', department='Computer'):

super().__init__(name, age, sex) # 给子类用父类的方法,同时实现子类的追加 department属性
# Person.__init__(self, name, sex) 这是第二种写法
self.set_department(department)

def set_department(self, department):
"""校验department必须为string"""
if type(department) != str: # 等同于 mot isinstance(department, str)
raise Exception("department must be a string.")

self.__department = department

def show(self):
super().show() # 不覆盖父类,并在其之上append
print(self.__department)


if __name__ == '__main__':
# 创建父类对象
cj = Person("cj", 22, 'man')
cj.show()
print('==' * 10)

# 创建子类对象
cj1 = Teacher('cj1', 23, 'man', 'Math')
cj1.show()
# 调用继承的方法修改年龄
print("==" * 10)
cj1.set_age(24)
cj1.show()
cj
22
man
====================
cj1
23
man
Math
====================
cj1
24
man
Math
type(22)
int

多继承时,D(A,B,C),重名时会从左到右搜索,使用第一个匹配成功的成员

多态

多态(polymorphism)指基类的同一个方法,在不同派生类对象中具有不同的表现和行为 龙生九子,子子皆不同

# 在子类中重写父类方法,实现多态
class Animal:
"基类"
def show(self):
print('I am an animal.')


class Cat(Animal):
def show(self):
"""重写(覆盖)了父类的show方法"""
print('I am a cat.')


class Tiger(Animal):
def show(self):
"""重写(覆盖)了父类的show方法"""
print('I am a tiger.')


class Test(Animal):
pass

x = [i() for i in (Animal, Cat, Tiger, Test)] # 列表推导式,对象,有点意思

for i in x:
i.show()
I am an animal.
I am a cat.
I am a tiger.
I am an animal.

特殊方法与运算符重载

目前我的水平,除了用__init__(), __ new__(), __ del__(),__ mro__()其余的好像也暂时搁着吧先

小结

  • 面对对象程序设计的关键是如何合理定义类并组织多个类之间的关系
  • Python 是面向对象的解释性高级动态编程语言,完全支持面向对象的基本功能和全部特性,如封装, 继承, 多态
  • __ xxx表示私有成员, __ xxx __ 表示特殊方法
  • 类外部不能直接访问私有成员,可通过类内部定义访问方法或者通过对象名._ 类名__ 私有成员名 来访问
  • 函数和方法这两个概念有本质区别(传参self)
  • 所有实例方法必须以self作为第一个参数
  • 属性property是一种特殊形式的成员方法,结合了公开数据成员和成员方法两者的优点
  • 如要做派生类/子类中调用基类方法,可使用内置函数super().方法名() 或者通过基类名.方法名()的形式
  • 多态是指基类的同一个方法在不同的派生类中,具有不同的表现和行为
  • Python 类的特殊方法与特定的内置函数或运算符相对应, **在自定义类中实现了某个特殊方法,就支持了某个运算符和内置函数

耐心和恒心, 总会获得回报的.



标签:__,.__,show,Python,self,基础,value,面向对象,def
From: https://blog.51cto.com/u_14195239/5751018

相关文章

  • 【AI白身境】学AI必备的python基础
    今天是新专栏《AI白身境》的第三篇,所谓白身,就是什么都不会,还没有进入角色。上一篇给大家介绍了如何正确使用Linux,如何利用shell,vim,git这三大神器。相信大家也掌握的差不多了......
  • 【AI白身境】只会用Python?g++,CMake和Makefile了解一下
    今天是新专栏《AI白身境》的第六篇,所谓白身,就是什么都不会,还没有进入角色。对于大部分小白来说,因为python用的太爽,以致于或许都没有听说过CMake。python是脚本语言,而当前大......
  • 【Python进阶】带你使用Matplotlib进行可视化
    欢迎来到专栏《Python进阶》。在这个专栏中,我们会讲述Python的各种进阶操作,包括Python对文件、数据的处理,Python各种好用的库如NumPy、Scipy、Matplotlib、Pandas的使用等等......
  • Python全栈工程师之从网页搭建入门到Flask全栈项目实战(1) - ES6标准入门和Flex布局
    1.简述1.什么是ES6?ES6,全称ECMAScript6.0,是JavaScript的下一个版本标准,2015年6月份发版。ES6的主要目的是为了解决ES5的先天不足。2.了解ES和JS之间的关系ES=......
  • 面向对象(上)01
    面向对象(上)01Java面向对象学习的三条主线:(第4-6章)1.Java类和类的成员:属性,方法,构造器;代码块,内部类.1.面向对象的三大特征:封装性,继承性,多态......
  • 【caffe解读】 caffe从数学公式到代码实现2-基础函数类
    文章首发于微信公众号《与有三学AI》​接着上一篇,本篇就开始读layers下面的cpp,先看一下layers下面都有哪些cpp。absval_layer.cppaccuracy_layer.cppargmax_layer.cppbas......
  • Python3.7之后使用协程进行并发编程更加容易
    [本文出自天外归云的博客园]在python3.7之后,async和await关键字的使用变得更加容易。async和await总是成对出现,async定义协程任务,await等待协程任务完成。代码如下:imp......
  • python 运行错误收集
    目录global全局声明错误global全局声明错误SyntaxError:name'is_login'isusedpriortoglobaldeclaration解决办法:globalis_login放在ifis_login:的上面is_l......
  • redis基础系列~单线程与多线程
    纯内存KV操作redis的操作都是在内存实现的,众所周知,在计算机的世界中,CPU的速度是远大于内存的速度的,同时内存的速度也是远大于硬盘的速度,所以非常快.所以内存的大小......
  • 视频直播源码,python实现列表插入、查找、删除
    视频直播源码,python实现列表插入、查找、删除#列表的插入、查找、删除实现 classTestArray:  def__init__(self,capacity)->None:    #由于python的lis......