面向对象编程

在python中,所有的数据类型都被视为对象,也可以自定义对象。自定义对象数据类型就是面向对象中的类(Class)的概念。

类的定义

概念:
1、类:用来描述具有相同属性和方法的对象的集合。类定义了集合中每个对象共有的属性和方法。对象是类的实例。
2、类变量(属性):类变量在整个实例化的对象中是公用的。类变量定义在类中,且在方法之外。类变量通常不作为实例变量使用。类变量也叫属性。
3、数据成员:类变量或实例变量用于处理类及实例对象的相关数据。
4、方法重写:如果从父类继承的方法不能满足子类的需求,就可以对其进行修改,这个过程为方法的覆盖,也叫方法的重写。
5、实例变量:定义在方法中的变量只作用于当前实例的类。
6、多态:对不同类的对象使用相同的操作。
7、封装:对外部世界隐藏对象的工作细节。
8、继承:
9、实例化:创建一个类的实例、类的具体对象。
10、方法:类中定义的函数。
11、对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

>>> class MyClass(object):        #类名:MyClass ,object表示如果没有父类就写object
	i=12							# 属性:i
	def f(self):                    # 方法:f
		return 'hello world'


类定义的语法格式:
class ClassName(object):



。。。。。。

类名通常都是大写开头的单词,(object)表示该类是从哪个类继承下来的,通常如果没有合适的继承类,就使用object类,只是所有类最终都会继承的类。

类的使用

>>> class MyClass(object):
	i=123
	def f(self):
		return 'hello world'

   
>>> use_class=MyClass()
>>> print('')

>>> print(f"调用类的属性:{use_class.i}")
调用类的属性:123
>>> print(f"调用类的方法:{use_class.f()}")
调用类的方法:hello world

对于类中定义方法的要求:在类中定义方法时,第一个参数必须是self。除第一个参数外,类的方法和普通函数没有差别,
类中调用方法的要求:实例变量上调用即可,除了self不用传外,其他参数均正常传入。

类对象支持两种操作,属性引用和实例化。
属性引用: obj.name obj代表类对象,name代表属性
实例化: obj=ClassName()

类的构造方法

>>> class MyClass(object):
	i=123
	def __init__(self ,name):
		self.name=name
	def f(self):
		return 'hello '+self.name

	
>>> use_class=MyClass()
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    use_class=MyClass()
TypeError: __init__() missing 1 required positional argument: 'name'
>>> use_class=MyClass('zhangsan')
>>> print(f"调用类的属性:{use_class.i}")
调用类的属性:123
>>> print(f"调用类的方法:{use_class.f()}")
调用类的方法:hello zhangsan

在Python中,init()方法是一个特殊方法,在对象实例化时会被调用。init()的意思是初始化,是initialization的简写。在定义类时,若不显式的定义一个__init__()方法,则程序默认调用一个无参的__init__()方法。比如下面两段代码的使用效果时一样的。
代码一:

>>> class DefaultInit(object):
	def __init__(self):
		print('类实例化时执行我,我是__init__()方法。')
	def show(self):
		print("我是类中定义的方法,需要通过实例化对象调用。")

		
>>> 
>>> test=DefaultInit()
类实例化时执行我,我是__init__()方法。
>>> print('类实例化结束')
类实例化结束
>>> test.show()
我是类中定义的方法,需要通过实例化对象调用。

代码二:

>>> class DefaultInit(object):
	def show(self):
		print('我是类中定义的方法,需要通过实例化对象调用。')

		
>>> test=DefaultInit()
>>> print('类实例化结束')
类实例化结束
>>> test.show()
我是类中定义的方法,需要通过实例化对象调用。

总结:一个类中可定义多个构造方法,但实例化类时只实例化最后的构造方法,即最后的构造方法会覆盖前面的构造方法。并且需要根据最后一个构造方法的形式进行实例化。建议一个类中只定义一个构造方法。

类的访问权限

>>> class Student(object):
	def __init__(self,name,score):
		self.name=name
		self.score=score
	def info(self):
		print(f'学生:{self.name} 分数:{self.score}')

		
>>> stu=Student("zhangsan",90)
>>> stu()
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    stu()
TypeError: 'Student' object is not callable
>>> stu.info()      #访问类实例化后的方法
学生:zhangsan 分数:90
>>> stu.name="李四"  #修改类中的属性
>>> stu.score=86
>>> stu.info()
学生:李四 分数:86

如上所示,类中定义的非构造方法可以调用构造方法实例变量的属性,调用的方法为self.实例变量属性名,如代码中的self.name和self.score,可以在类的外部修改类的内部属性(相当于变量赋值)。
要让内部属性不被外部访问,可以在属性名称前加两个下划线__.在python中,实例的变量名如果以__开头,就会变成私有变量,只能内部访问,外部不能访问。例如:

>>> class Student(object):
	def __init__(self,name,score):
		self.__name=name
		self.__score=score
	def info(self):
		print(f'学生:{self.__name} 分数:{self.__score}')

		
>>> stu=Student('小名',60)
>>> print(f"修改前的分数:{stu.__score}")
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    print(f"修改前的分数:{stu.__score}")
AttributeError: 'Student' object has no attribute '__score'

从示例中我们可以看出已经无法从外部访问实例变量的属性__score了,这样可以确保外部代码不能随意修改对象内部的状态,通过访问限制的保护,代码更加安全。
私有变量的访问,可以通过get_attrs()方法。
私有变量的修改,可以通过set_attrs()方法。

class Student(object):
    def __init__(self,name,score):
        self.__name=name    #定义私有属性
        self.__score=score  #定义私有属性



    def info(self):
        print(f"学生:{self.__name};分数:{self.__score}")

    def get_score(self):        #访问私有变量
        return self.__score
    def set_score(self,score):  #修改私有变量,变量检查,避免传入无效参数
        if score in range(0,100):
            self.__score=score
        else:
            print("请输入0到100之内的数字")

stu=Student("张三",98)
stu.info()
print(f'修改前的分数:{stu.get_score()}')
stu.set_score(70)
print(f'修改后的分数:{stu.get_score()}')
stu.info()
stu.set_score(-50)
stu.info()

>>> 
 RESTART: C:/Users/86186/AppData/Local/Programs/Python/Python37/siyoubianliang.py 
学生:张三;分数:98
修改前的分数:98
修改后的分数:70
学生:张三;分数:70
请输入0100之内的数字
学生:张三;分数:70
>>> 

通过私有变量和对应的set方法可以帮助我们参数检查,避免传入无效的参数。
私有方法:以两个下划线开头的方法即为私有方法,该方法不能在类外使用。
私有方法的调用:self.private_methods

继承

继承是实现方法重用的方法之一。
子类继承基类(父类、超类)。
继承的定义如下:
class DerivedClassName(BaseClassName):

.
.

python 中,继承有以下特点:
(1)继承中,基类的构造方法__init__()方法不会被自动调用,需要在子类的构造方法中专门调用。
(2)在调用基类的方法时需要加上基类的类名前缀,并带上self参数变量。区别于在类中调用普通函数时不需要带self参数。
(3)在python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中挨个查找。

>>> class Animal(object):       #定义父类、基类、超类
	def run(self):              #父类中的方法
		print("Animal is running...")  

		
>>> class Dog(Animal):         #定义子类Dog继承父类Animal
	pass

>>> class Cat(Animal):         #定义子类Cat继承父类Animal
	pass

>>> dog=Dog()                  #实例化类
>>> dog.run()                  #通过子类的继承调用
Animal is running...
>>> cat=Cat()
>>> cat.run()
Animal is running...

子类不能继承父类的私有方法,也不能调用父类的私有方法。

class Homan(object):
    def __init__(self,name,sex):
        print("人类是从猿类进化而来。")
        self.__name=name
        self.__sex=sex
    def dingyi(self):
        
        print(f'人类有个共同的名字:{self.__name}')
        print(f"人类的性别是:{self.__sex}")

class Man(Homan):
    def first(self):
        print("男人有jj")

class WoMan(Homan):
    def first(self):
        print("女人有长腿")
Ren=Homan("未来战士","男或女")
Ren.dingyi()     #调用父类的私有方法
print("*"*30)
s2=Man(2,3)        
s2.first()       #调用子类的方法,父类定义的私有变量不能调用,也不能继承
人类是从猿类进化而来。
人类有个共同的名字:未来战士
人类的性别是:男或女
******************************
人类是从猿类进化而来。
男人有jj

继承可以一级一级的继承下来,就好比从爷爷到爸爸再到儿子的关系,所有的类最终都可以追溯到根部object,这些继承关系看上去就像一颗倒着的树。

多重继承

一个子类可以有多个父类,同时获得多个父类的所有非私有功能。
格式:
class DeribedClassName(Base1,Base2,Base3…)

.
.

多态

当子类和父类拥有同名的方法时,子类的方法会覆盖父类的方法,在代码运行是总是会调用子类的方法,称为多态。
多态即根据对象(或类)的不同而表现出不同的行为。
唯一可以毁掉多态的是使用函数显式的检查类型,如tpye()、isinstance()等函数。如果有可能,就尽量避免使用这些毁掉多态的方法。

封装

封装是全局作用域中其他区域影藏多余信息的原则。
封装并不等同于多态,多态可以让用户对不知道类(或对象类型)的对象进行方法调用,而封装可以不用关心对象是如何构建的,直接使用即可。

>>> class Student(object):
	def __init__(self,name,score):
		self.name=name
		self.score=score

>>> std=Student('xiaozhi',90)
>>> def info(std):
	print(f"学生:{std.name}分数:{std.score}")

	
>>> info(std)
学生:xiaozhi分数:90

由输出结果看,可以通过函数调用类并得到结果。

>>> class Student(object):
	def __init__(self,name,score):
		self.name=name
		self.score=score
	def info(self):
		print(f"学生:{std.name}分数:{std.score}")

		
>>> std=Student('xiaozhi',90)
>>> std.info()
学生:xiaozhi分数:90

直接将方法info()封装在了Student()类中。
这样一来,我们从外部看Student类,只需要知道创建实例需要给出name和score,如何输出是在Student类的内部定义实现,这些数据和逻辑被“封装”起来了,调用很容易,但却不知道内部细节的实现。
封装的另一个好处是可以给Student类增加新方法,比如我们在类的访问权限中所讲述的get_score()方法和set_score()方法。使用这些方法时,无须知道内部实现细节,直接调用既可以。

获取对象信息

type()函数
用type()基本类型都可以判断。

>>> type(123)
<class 'int'>
>>> type(None)
<class 'NoneType'>
>>> type(abs)
<class 'builtin_function_or_method'>

isinstance()函数
通过isinstance()判断class的数据类型确定class的继承关系。

>>> isinstance([1,2,3],(list,tuple))
True

dir()
dir()可以活的一个对象的所有属性和方法。dir()函数返回一个字符串的list。

>>> dir(123)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>> dir("abc")
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

类的专有方法

str()

>>> class Student(object):
	def __init__(self,name):
		self.name=name
		
	def info(self):
		return(f"学生:{std.name}")

	
>>> print(Student('xiaoli'))
<__main__.Student object at 0x0000011A1B1BBF48>
>>> class Student(object):
	def __init__(self,name):
		self.name=name
		
	def __str__(self):
		return(f"学生:{std.name}")

	
>>> print(Student('xiaoli'))
学生:xiaozhi

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值