6-1python语法基础-面向对象-类的定义属性和方法,类的作用域,类的封装继承多态,类的反射,单例模式
#######
面向对象学习什么?
1,类的定义
2,类的属性和方法
3,类的作用域和命名空间,
4,类的调用
5,类的静态属性,静态方法,
6,类的继承
7,类的封装,
8,类的多态,
9,反射的使用
10,单例模式,
11,类的传递参数,
12,类的魔术方法,
####
#######
类的定义
class Person: def __init__(self, name, age): self.name = name self.age = age def say_hello(self): print(self.name, "hello") p1 = Person("xiaoxiao", 20) print(p1.name) p1.say_hello()
print(p1.__dict__)
###
认知:
1,类的定义使用首字母大写,
2,类可以定义属性和方法,属性放到init方法里面定义,方法就是和函数一样的定义方法,
3,类的调用,先实例化一个类的对象,然后调用,
4,print(alex.__dict__) # 查看所有属性 ,返回一个字典,
5,方法定义,必须第一个参数是self,
####
深刻理解init方法,初始化方法,构造方法,发生了什么?
类在实例化的时候,会自动执行以下操作:
1,为对象在内存中分配空间--创建对象,这个是new方法,
2,为对象的属性设置初始值--初始化方法,这是初始化方法就是 __init__方法,这是对象的内置方法,初始化方法是专门来定义一个类具有哪些属性的方法!!!
####
深度理解self的含义
1,self本质是指的类的实例,谁调用这个self就是那个实例,名字不必须是self,但是约定俗成就是self
2,self只能在类的内部,self可以调用属性也能调用方法,
3,所以必须要有这个self,否则调用类的时候,我就不知道是谁调用的我,因为我的内存地址都是同一个,
#####
深度理解类的实例化和命名空间,内存空间,还有作用域的问题
class Person: country = "china" def __init__(self, name, age): self.name = name self.age = age def say_hello(self): print(self.name, "hello") p1 = Person("xiaoxiao", 20) p2 = Person("mingming", 20) print(id(p1.country),id(p2.country)) # 140342441825008 140342441825008 print(id(p1.say_hello),id(p2.say_hello)) # 140342459213696 140342459213696 p1.country = "usa" print(id(p1.country),id(p2.country)) # 140342459198960 140342441825008 del Person.country print(id(p1.country),id(p2.country)) # 删除之后再去访问这个类的静态属性,就报错了,
####
1,类新建了之后会有一个内存空间,
2,类每次实例化一个都会再开启一个内存空间,
3,为什么静态属性可以实例化对象调用?因为在自己的空间找不到,会去类里面找,这就是原理,
4,注意实例化对象调用修改了这个属性,不会更改类里面的空间的,会在自己实例化对象里面创建一个新的属性,他是没有权限修改类里面的属性的值的,
5,这样会有一个问题,类对象修改了这个静态属性,以后使用都不会变了,你要使用类的就要把自己创建的这个属性删除,del 类实例.静态变量,
######
继承的深刻理解:
class Animal: def __init__(self, name): self.name = name def eat(self): print('eat') def sleep(self): print('sleep') class Dog(Animal): def __init__(self, name, kind): # super().__init__(name) Animal.__init__(self,name) # 体会使用super继承和使用类继承的不同之处,super继承是不用写self的, self.kind = kind def eat(self): # super().eat() Animal.eat(self) print('dog eating') def sleep(self): print("sleeping ") dog1 = Dog("heihei","dog") print(dog1.__dict__) dog1.eat() dog1.sleep() print(Dog.__bases__) # 可以查看这个类继承了哪一个类 print(Animal.__bases__) # (<class 'object'>,) # 所有的类最终是继承了object类
###
1,继承有两种方式,
第一种是,完全的重写,直接覆盖就完了,比如sleep方法
第二种是,在父类基础上添加功能,比如eat方法,
这种又有两种写法,一种是super继承,一种是类名.方法名,这第二种继承是需要传入self的,
###
封装的体验,以及私有属性和私有方法
class Women: def __init__(self,name): self.name=name self.__age_private=18 self.age_public=19 def __str__(self): '''对类的描述''' return '这是一个女人类' def secret_public(self): print('名字是%s,年龄是%d'%(self.name,self.__age_private)) # # 所以私有属性外部不能访问,,但是内部可以访问, def __secret_private(self): # 私有方法 print('名字是%s,年龄是%d'%(self.name,self.__age_private)) w1 = Women("xiaoxiao") print(w1.name) print(w1) # 这是一个女人类 print(w1._Women__age_private) # 这种方式可以访问私有属性 print(w1._Women__secret_private()) # 这种方式可以访问私有属性
###
1,私有属性和私有方法,怎么定义:在定义属性或者方法的时候,在属性名或者方法名前面增加两个下划线,就是定义私有属性或者方法了,j记住是两个前面下划线
2,python中没有真正意义上的私有,#在日常开发中,不要使用这种方法去访问对象的属性和方法,但是可以调用到,
###
@property的使用
class DataSet(object): @property def method_with_property(self): ##含有@property return 15 def method_without_property(self): ##不含@property return 15 l = DataSet() print(l.method_with_property) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。 print(l.method_without_property()) #没有加@property , 必须使用正常的调用方法的形式,即在后面加()
认知:
1,python的@property是python的一种装饰器,是用来修饰方法的。
2,我们可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,
####
静态方法@staticmethod和类方法 @classmethod
class Goods: def func1(self): print('foo') @classmethod def func2(cls): return 123 @staticmethod def func3(): return 456 # print(Goods.func1()) # 这种就会报错,因为你类直接掉,缺少self参数 print(Goods.func2()) # 这种因为是传递的cls,所以可以直接调 print(Goods.func3()) # 这种和普通函数差不多,不传self,不传cls,
####
认知这个静态方法和类方法
1,把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
2,静态方法,不需要传递self了,也不需要传递cls了,
我还是不是能明白这几个方法的用途,我认为这个功能比较鸡肋,
反射的深刻理解
class A: name = "xiaoxiao" def show(self): print("这是一个普通方法") a = A() print(getattr(a, 'name')) ret = getattr(a, 'show') ret() setattr(a,"name","baibai") print(getattr(a, 'name')) # 注意点1: print(getattr(a, 'name2',"heihie")) # 如果找不到这个属性getattr会报错的,所以增加第三个参数,如果没有这个找到就会返回第三个,避免了报错 # 注意点2,一般都是这样用的,hasattr先判断一下, if hasattr(a, 'name'): print(getattr(a, 'name')) delattr(a,"name")
######
1,什么是反射,反射是一个很重要的概念,它可以把字符串映射到实例的变量或者实例的方法然后可以去执行调用、修改等操作。
2,有四个重要的方法,getattr,setattr,hasattr,delattr
3,应用场景:1,通过一个字符串获取到了属性的值,2,通过字符串拿到了函数地址,然后加括号就调用了,
####
内置的常用的类方法
class A: """ 描述类信息""" def func(self): pass def __str__(self): return "这是一个测试类" print(A.__doc__) #输出:类的描述信息 print(A.__dict__) # 类名调用这个方法,会返回所有的静态字段和方法 a = A() print(a) # 这是一个测试类
#####
单例模式---使用模块实现
class Singleton(object): def foo(self): pass singleton = Singleton()
###
将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象:from a import singleton
###
单例模式---使用装饰器实现
def Singleton(cls): _instance = {} def _singleton(*args, **kargs): if cls not in _instance: _instance[cls] = cls(*args, **kargs) return _instance[cls] return _singleton @Singleton class A(object): a = 1 def __init__(self, x=0): self.x = x a1 = A(2) a2 = A(3)
#####
单例模式---基于__new__方法实现(推荐使用,方便)
class A: _instance = None def __new__(cls, *args, **kwargs): if cls._instance: return cls._instance cls._instance = super().__new__(cls) # 这个就是初始化的时候,需要调用这个父类的new方法,记住需要传递cls return cls._instance a1 = A() a2 = A() print(id(a1)) print(id(a2))
###
1,单例模式:就是一个类只有一个实例,内存地址都是一样的,
2,我们知道,当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式
3,new方法创建对象,分配空间
####
#####
#####