Python之中,一切皆对象.

  本文分为4部分:

  1. 面向对象:初识

  2. 面向对象:进阶

  3. 面向对象:三大特性----继承,多态,封装

  4. 面向对象:反射

0. 楔子

面向过程和面向对象的是两种思路:

面向过程是流水线,闷着头一口气写下来就行;

面向对象,感觉自己像是个上帝,先构思好,然后再去写,这也是我们写程序时候要做到的.

例子如下:

#面向过程,函数:
def login():
pass
def regisgter():
pass def func1():
pass
def func2():
pass #面向对象,类:
class Account:
def login(self):
pass
def regisgter(self):
pass class Account:
def func1(self):
pass
def func2(self):
pass

  从上面的式子,我们很容易发现:

    1.类相当于函数的集合,能够让你的函数更加集中,不是那么散乱.

    2.用类的话有上帝视角. 倒也算不上哪个好哪个坏,无非是复杂的话用类好,简单的话用函数好.

1. 面向对象:初识

  1.1 什么是对象和类

  什么是对象?  人说,Python中,一切皆对象. 这么说似乎有些宽泛, 一切, 究竟包括什么呢?

  其实,这里的一切是指所有的变量. 在之前我们已经学习了字符串等数据类型,也学习了函数和内置函数,还学会了内置模块和第三方模块的调用. 那么,这些都是对象吗?是的,一切皆对象. 只要我们能够将其赋给变量,甚至连模块都可以赋给变量,那么还有什么不是变量呢?

  最近学到的一个经典例子:人狗大战. 这个例子可以生动形象的解释.

  如果我们需要进行人和狗进行战斗这样一个场景,我们需要的内容是:

  人的要素,比如生命值,攻击力,防御力,职业;狗的要素,生命值,攻击力,防御力,种类.

  创建完两个角色的属性后,我们需要让他们发生互动,也就是'fight'.

  但如果这时候,我们想要创建好几个人和狗怎么办呢? 很简单,我们只要把人和狗做成模子即可,就像活字印刷术,排完版之后蘸上墨水刷一下就好啦. 光想着这么多的东西,如果要是用函数的话,很容易没有条理的,尤其是创建人物和动物形象的时候.

  用函数做法如下:

def Person(name,hp,ad,sex):   # 模子
dic = {'name':name,'blood':hp,'attack':ad,'sex':sex} def fight(dog): # 攻击 属于人
# 狗掉血,就是人的攻击力
dog['blood'] -= dic['attack']
print('%s打了%s,%s掉了%s血' % (dic['name'], dog['name'], dog['name'], dic['attack']))
dic['fight'] = fight
return dic def Dog(name,hp,ad,kind):
dic = {'name': name, 'blood': hp, 'attack': ad, 'kind': kind} def bite(person): # 咬 属于狗
person['blood'] -= dic['attack']
print('%s咬了%s,%s掉了%s血' % (dic['name'], person['name'], person['name'], dic['attack'])) dic['bite'] = bite
return dic
# 互相打
smith = Person('smith',20,1,'不详')
print(smith)
hei = Dog('小黑',3000,10,'哈士奇')
print(hei)
smith['fight'](hei)
hei['bite'](smith)

  说实话,是不是感觉乱乱的?  

  这时候,救星来了! 我们用类可以轻松做到!!!

class Dog:
def __init__(self,name,blood,ad,kind):
self.name = name # 向对象的内存空间中添加属性
self.hp = blood # 可以通过self在类的内部完成
self.ad = ad
self.kind = kind def bite(self,person):
person.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad)) class Person:
def __init__(self,name,hp,ad,sex):
self.name = name
self.hp = hp
self.ad = ad
self.sex = sex def fight(self,dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血'%(self.name,dog.name,dog.name,self.ad))

  这样,两个模子已经刻好了,并且将动作也定义完了(此处就是方法),当我们想创建的时候,就可以轻松创建,如下:

hei = Dog('小黑',300,20,'哈士奇')
alex = Person('alex',20,1,'不详')
alex.fight(hei)
print(hei.hp)
hei.bite(alex)
print(alex.hp)

  这样,上面的就是创建类,下面的就是实例化对象并且进行方法的调用.(其中__init__是属性)

  类:具有相同方法和属性的一类事物

  对象:具有相同的属性值的实际存在的例子. 此处,对象仅指实例化的对象.是狭义的.

    广义的对象包括类.

  1.2 类的结构和类的操作

  类的结构基本如下:

class 类名:#切记,类名首字母大写,为了和系统内置的类区分开
def __init__():#可有可无,不是必须写的
pass
def 方法名():
pass

  查看类中变量的两种方法如下:

def 函数:
pass
class Dog:
pass
class Dog:
变量 = 1000
变量2 = 'abc'
# 变量3 = [(1,2),(3,4)] 查看类当中的变量,方法一
print(Dog.__dict__['变量'])
print(Dog.__dict__['变量2'])
print(Dog.__dict__['变量3'])
查看方法二(常用)
print(Dog.变量)
print(Dog.变量2)
print(Dog.变量3)

  其中,若用Dog.__dict__可查看Dog的全部属性,当然也可以用此方法查看实例化的对象等.

  调用类中静态变量的方法一致.

#续上列:
class Cat:
cat_of_producing = '猫舍'#理解为刷怪区吧,是静态变量
def __init__(self,name,hp):
self.name = name
self.hp = hp
def catch(self):
print('捕捉成功')
print(Cat.cat_of_producing)#此时就能调用静态变量
#类名可以调用动态方法,但一般不用.
#实例化对象也可以调用静态变量,能查能改.
#但改的话一般用类名调用.

  非常需要注意:::::::::::::::::::::::::::::::::::::

  注意,当编译完了的时候,class就出现了其内存空间.当进行实例化的时候,其实例化对象也产生了一个内存空间.切记.

 

实例化的过程 :
1.开辟了一块空间,创造了一个self变量来指向这块空间
2.调用init,自动传self参数,其他的参数都是按照顺序传进来的
3.执行init
4.将self自动返回给调用者

   PS:

  1.类名可以调用所有定义在类中的名字
  变量
  函数名
  2.对象名 可以调用所有定义在对象中的属性
  在init函数中和self相关的
  调用函数的,且调用函数的时候,会把当前的对象当做第一个参数传递给self

2. 面向对象:进阶

  2.0 回顾

    回顾上述内容,记得设置完属性和动作之后让他们进行互动.

class Monster:
# 先生成一个怪物的形象
def __init__(self, name, hp, attack, type):
self.name = name
self.hp = hp
self.attack = attack
self.type = type # 然后再生成一个怪物的动作
def fight(self, person):
person.hp -= self.attack
print('%s对%s造成%s点伤害,%s还剩%s点血' % (self.name, person.name, self.attack, person.name, person.hp)) class Hero:
# 同理,先生成一个英雄的形象
def __init__(self, name, hp, attack, sex):
self.name = name
self.hp = hp
self.attack = attack
self.type = type # 然后再生成一个怪物的动作
def fight(self, monster):
monster.hp -= self.attack
print('%s对%s造成%s点伤害,%s还剩%s点血' % (self.name, monster.name, self.attack, monster.name, monster.hp)) # 对人物和怪兽进行实例化
arthur = Hero('King_Arthur', 50, 20, 'male')
siren1 = Monster('海妖1号', 200, 10, 'siren')
#经过千辛万苦,我们的亚瑟王最终和海妖战斗在一起,并且各砍一刀
arthur.fight(siren1)#King_Arthur对海妖1号造成20点伤害,海妖1号还剩180点血
siren1.fight(arthur)#海妖1号对King_Arthur造成10点伤害,King_Arthur还剩40点血
#天呐,看来我们的亚瑟王如果不逃走的话将会命丧海妖之手,但是,,,,,,这跟我有什么关系呢哈哈哈哈哈 #为了增加游戏的趣味性,我们可以再加上武器系统,比如再建一个class Weapon,然后通过动作进行武器装备,还可以加上防御力和
# 闪避等属性,可操作性太多了.

    为了纪念这场差点把亚瑟王杀死的旷世大战,我准备把这个小游戏命名为世纪之战.

    记得,只要上面的世纪之战吃透,简单的写一个小小的自娱自乐的游戏至少是没问题哒.

  2.1 内存空间

  2.2 私有化(正常来说应当放到封装,但因为一些特殊原因放于此)

  2.3 类的特殊成员(前面有两道下划线的内置方法)

  

  2.1 内存空间

    内存空间:一般是指主存储器空间(物理地址空间)或系统为一个用户程序分配内存空间。

    内存地址:内存地址是内存当中存储数据的一个标识,并不是数据本身,通过内存地址可以找到内存当中存储的数据。由4位或8位16进制表示.

  2.2 私有化

    在前面加__即可,表明只有这个方法是由某类私有的.别的是调用不了的.

  2.3 类的特殊成员

    用到的时候可参考:https://www.jianshu.com/p/bf3166d8faf0

             https://www.cnblogs.com/pyxiaomangshe/p/7927540.html

    之前的方法已经能够解决日常的90%了,我们需要解决的10%可以从内置方法中找到答案.

    内置方法又被称为双下方法,魔术方法.都是python的对象内部自带的,并且都不需要我们自己去调用它.

    2.3.1 __str__和__repr__

class Course:
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period
# def __str__(self):#
# """
# 打印这个对象的时候自动触发__str__
# :return:
# """
# return '%s,%s,%s'%(self.name,self.price,self.period)
# def __repr__(self):#备胎(str没有的时候才用repr)
# """
# 打印这个对象的时候自动触发__str__
# :return:
# """
# return '%s,%s,%s'%(self.name,self.price,self.period) python = Course('python',25000,'6 mouths')
print(type(python))
# print('course:%s'%python)
# print(f'course:{python}')

    如果str存在,repr也存在,那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__,而repr(obj)和%r格式化字符串,都会调用__repr__ ;
    如果str不存在,repr存在,那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__.
    如果str存在,repr不存在,那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__.
    repr(obj)和%r格式化字符串,都会打印出内存地址.

class Course:
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period
def __repr__(self):#备胎(str没有的时候才用repr)
"""
打印这个对象的时候自动触发__str__
:return:
"""
return '%s,%s,%s'%(self.name,self.price,self.period)
# def __str__(self):
# return self.name class Python(Course):
pass
def __repr__(self):
return '%s--%s--%s' % (self.name, self.price, self.period)
# def __str__(self):
# return '全栈开发:'+self.name python = Python('python',25000,'6mouths')
print(python)
#放开Courese和Python的str,显示为:全栈开发:python
#放开Courese的str和Python的repr,显示为:python
#放开Courese的repr和Python的str,显示为:全栈开发:python
#放开Courese和Python的repr,显示为:python--25000--6mouths
    有了repr或者str在打印对象的时候 就不会显示用户不关心的内存地址了.
    增强了用户的体验 在程序开发的过程中,如果我们需要频繁打印对象中的属性,需要从类的外部做复杂的拼接,
  实际上是一种麻烦.
    如果这个拼接工作在类的内部已经完成了,打印对象的时候直接就能显示.

    2.3.2 __new__和__del__

    __new__ 构造方法 生产对象的时候用的 - 单例模式
    __del__ 析构方法 在删除一个对象之前用的 - 归还操作系统资源

    实例化一个Foo的对象,先开辟一块儿空间,使用的是Foo这个类内部的__new__.
    如果我们的Foo类中是没有__new__方法的,调用object类的__new__方法了

    在使用self之前,都还有一个生产self的过程,就是在内存中开辟一块属于这个对象的空间,并且在这个空间中存放一个类指针,以上就是__new__做的所有事情.

#__new__的实例:
class Foo(object):
def __new__(cls, *args, **kwargs): # cls永远不能使self参数,因为self在之后才被创建
obj = object.__new__(cls) # self是在这里被创造出来的
print('new : ',obj)
return obj
def __init__(self):
print('init',self)
Foo()
#关于__del__的一些解释
#在所有的代码都执行完毕之后,所有的值都会被python解释器回收

  #python解释器清理内存

  #1.我们主动删除 del obj
  #2.python解释器周期性删除
  #3.在程序结束之前 所有的内容都需要清空

 
#__del__的实例1:
import time
class A:
def __init__(self,name,age):
self.name = name
self.age = age
def __del__(self):
#只和del obj语法有关系,在执行del obj之前会来执行一下__del__中的内容
print('执行我了') a = A('gh',84)
# print(a.name)
# print(a.age)
# del a print(a)#执行完后自动清理
#__del__的实例2:
import time
class A:
def __init__(self,path):
self.f = open(path,'w')
def __del__(self):
'''归还一些操作系统的资源的时候使用'''
'''包括文件\网络\数据库连接'''
self.f.close() a = A('userinfo')
time.sleep(1)

    PS:拓展:单例模式

      设计模式 - 单例模式
      一个类 有且只能有一个实例

      保证一个类无论 被实例化多少次,只开辟一次空间,始终使用的是同一块内存地址

class A:pass
a1 = A()
a2 = A()
print(a1)
print(a2) class A:
__flag = None
def __new__(cls, *args, **kwargs):
if cls.__flag is None:
cls.__flag = object.__new__(cls)
return cls.__flag def __init__(self,name=None,age=None):
self.name = name
if age:
self.age = age a1 = A('alex',84)
print(a1)
a2 = A('alex',83)
print(a2)
a3 = A('alex')
print(a3)
print(a1.age)#结果为83,说明最后一次覆盖掉了

    2.3.3 __call__

#__call__
#源码里用比较多 Flask web框架
#对象()自动触发__call__中的内容
class A:
def call(self):
print('in call')
def __call__(self, *args, **kwargs):#自动调用__call__
print('in __call__') # A()()
obj = A()
obj()
obj.call()
转载自:https://segmentfault.com/q/1010000006113393?_ea=1020343(好吧,表示现在看的还不是太懂)
用一句话描述是,
Python 的 __call__ 方法可以让类的实例具有类似于函数的行为,通常用于定义和初始化一些带有上下文的函数。
既然说是妙处,那不得不提及 Python 世界中的那几个经典实现了。
一个例子来源于 bottle 框架源码的 cached_property(被我改动了一些细节,但用法基本是一样的),为了在逻辑上构成一个封闭的整体,我们把一个实例当作函数来使用:
class CachedProperty(object):
_cache = {} def __call__(self, fn):
@property
@functools.wraps(fn)
def wrapped(self):
k = '%s:%s' % (id(self), fn.__name__)
v = CachedProperty._cache.get(k)
if v is None:
v = fn(self)
CachedProperty._cache[k] = v
return v return wrapped cached_property = CachedProperty()
使用的时候可以直接替换掉内置的 property 来缓存动态属性:
class DB(object):
def __init__(self, ...):
.... @cached_property
def conn(self):
return create_connection(...) db = DB()
db.conn # 创建连接并缓存
还有个更复杂但非常实用的例子,Pipline,把函数封装成支持管道操作的运算过程:
class Pipe(object):
def __init__(self, fn):
self.fn = fn def __ror__(self, other):
return self.fn(other) def __call__(self, *args, **kwargs):
op = Pipe(lambda x: self.fn(x, *args, **kwargs))
return op
可以像这样调用: @Pipe
def sort(data, cmp=None, key=None, reverse=False):
return sorted(data, cmp=cmp, key=None, reverse=reverse) [{'score': 1}, {'score': 3}, {'score': 2}] | sort(key=lambda x: x['score'])
可以看出,类 Pipe 被当作一个装饰器使用,所以 sort 函数的原始定义被传递给 Pipe.__init__,构造出一个 Pipe 实例,所以被装饰过的 sort 函数,也就是我们后面使用的那个,实际上是一个 Pipe 类的实例,只是因为它有 __call__ 方法,所以可以作为函数来使用。 这种用法在写一些 ORM 框架以及有大量细粒度行为的库时有奇效。

    2.3.4 __enter__,__exit__与with的完美结合

    自动识别__enter__和__exit__
    判定__enter__执行为开始,__exit__为结束
    应用场景应当有很多:比如

执行语句体:
class File:
def __enter__(self):
print('start')
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit') with File():
print('wahaha')#相当于装饰器,输出顺序是
#start
#wahaha
#exit
写入文件:
class myopen:
def __init__(self,path,mode = 'r'):
self.path = path
self.mode = mode
def __enter__(self):
print('start')
self.f = open(self.path,mode=self.mode)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
print('exit') with myopen('userinfo','a')as f:
f.write('hello,world')
用pickle模块写入文件:
import pickle
class MypickleDump:
def __init__(self,path,mode='ab'):
self.path = path
self.mode = mode
def __enter__(self):
self.f = open(self.path,self.mode)
return self
def dump(self,obj):
pickle.dump(obj,self.f)
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close() with MypickleDump('pickle_file')as pickle_obj:
pickle_obj.dump({1,2,3})

    第三种写入文件,请比较异同:

class MypickleDump:
def __init__(self,path,mode = 'ab'):
self.path = path
self.mode = mode def __enter__(self):
self.f = open(self.path,self.mode)
return self def dump(self,obj):
pickle.dump(obj,self.f) def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close() with MypickleDump('pickle_file') as obj:
obj.dump({1,2,3,4}) with MypickelLoad('pickle_file') as obj:
for i in obj.loaditer():
print(i)

    在一个函数的前后添加功能
    利用使用 装饰器函数中的内容

    with语句 就是和 __enter__,__exit__完美结合,请注意使用哦.

    

    ############################

      划    重    点

    ############################

    基础:
     __new__
     __del__
     __call__
    重点:
     __str__
     __repr__
     __enter__
     __exit__

3. 面向对象:继承,多态,封装

  初入对象,感觉的确挺有意思,凡事都是那么简单的感觉,上帝视角,随意调用人物属性,随意设置任务动作,那滋味简直不要太爽!!!

  然而,记得一个公式:痛苦==有益,爽==有害.一旦只沉迷于这种感觉,很容易不思进取,因为再往下就会感觉有些难度了.

图中虚线代表实例关系,实线表示继承关系,从这个图中得出几点:

  1. list、str、dict、tuple、type都继承了object,所以object是最顶层的基类

  2. type是本身的对象(实例),object、list、str、dict、tuple都是type的对象,所以type创建了所有的对象

  3. 综合1、2可知,一切皆对象的同时又继承了object类,这就是python的灵活之处,Python的面向对象更加彻底.

  其实,object也是继承元类(metaclass)得来的.

PS:(转载自王sir)
关于抽象类的理解:
1.抽象类的意义是?或者说为什么要有抽象类?
抽象类是对多个类中共同方法的抽取,但是子类又有不同的实现,父类只能抽取出方法的名字,而不明确方法的具体实现.
这种只规定子类拥有哪些方法,而不明确具体实现的父类,就应该定义为抽象类.
抽象类只用来规范子类应该具有哪些行为,而不明确具体的动作. 2.抽象类的特点是?
抽象类和普通类的最主要区别在于:
1.抽象类继承的()中写的是metaclass=ABCMeta
2.在类体中有用@abstractmethod修饰的方法(需要子类重写的方法) 3.抽象类中是否可以有非抽象方法?
可以. 4.抽象类中的抽象方法是否可以有方法体?
可以. 5.抽象类中是否可以有__init__方法?为什么?
可以,因为抽象类中也可以有实例属性供子类继承.
而实例属性必须在父类中初始化,子类对象才能继承. 抽象类的__init__方法不能手动调用,只能是子类创建对象时自动调用的.

4. 面向对象:反射

  首先,要明确一点的是,反射的格式:a.b <====> getattr(a,'b') 诸如此类,这是核心概念!!!!!

    所有的a,b都可以变成getattr(a,'b')
    用字符串数据类型的变量名 来获取实际的变量值
    用字符串数据类型的变量名 找到这个变量对应的内存地址

  4.1 两个内置函数

    issubclass

# class A:pass
# class B(A):pass
# class C(A):pass
# print(issubclass(B,A))
# print(issubclass(C,A))
# print(issubclass(B,C))#只针对类
# print(isinstance(B,A))#只针对对象与类

    isinstance

# a = 1
# ret1 = type(a) is int
# print(ret1)
# ret2 = isinstance(a,int)
# ret3 = isinstance(a,object)
# print(ret2)
# print(ret3)

    小结:

    两个内置函数
      isinstance()判断对象与类是否有继承关系
      type()判断对象与类是否有关系(只承认实例化对象的那个类,不承认继承关系)
      issubclass()判断类与类是否有继承关系

  4.2 一个套餐,4个函数

    内置函数:
    getattr
    hasattr
    setattr
    delattr

    4.2.1 hasattr()

      用途:hasattr#判断是否找到对象,判断True 或者 False

        格式:hasattr(a,'b'),返回True或者False. 常与getattr()连用,判断是否可以调用,避免报错.

    4.2.2 getattr()

      用途:getattr#找到对象对应的内存地址,调用字符串作为属性名

      格式:getattr(a,'b'),等同于a.b

if hasattr(s,'choose_goods'):   # 判断s对象有没有choose_goods
func = getattr(s,'choose_goods') # 使用s找到choose_goods对应的内存地址
print(func)
func()

        PS:若想调用变量a或b,但只能输入'a'或'b'.

a = 1
b = 2
getattr(modules[__name__],'变量名')#这个一定要牢记!!!

    4.2.3 setattr()

      用途:用于添加,有三个变量.

      格式:setattr(x, 'y', v) is equivalent to ``x.y = v''#官方解释

setattr(alex,'wahaha',wahaha)
print(alex.__dict__)
alex.wahaha(alex)

     4.2.4 delattr()

      用途:用于删除

      格式:delattr(x, 'y') is equivalent to ``del x.y''#官方解释

delattr()
print(smith.__dict__)
delattr(smith,'name') # del smith.name
print(smith.__dict__)

  4.3 四种反射情况

    4.3.1 使用对象反射

      obj.属性名

      obj.方法名()

# 1.使用对象反射(先列出类)
# class Manager: # 管理员用户
# def __init__(self,name):
# self.name = name
# def create_course(self): # 创建课程
# print('in Manager create_course')
#
# def create_student(self): # 给学生创建账号
# print('in Manager create_student')
#
# def show_courses(self): # 查看所有课程
# print('in Manager show_courses')
#
# def show_students(self): # 查看所有学生
# print('in Manager show_students')
# 不用反射
# alex = Manager('alex')
# operate_lst = ['创建课程','创建学生账号','查看所有课程','查看所有学生']
# for index,opt in enumerate(operate_lst,1):
# print(index,opt)
# num = input('请输入您要做的操作 :')
# if num.isdigit():
# num = int(num)
# if num == 1:
# alex.create_course()
# elif num == 2:
# alex.create_student()
# elif num == 3:
# alex.show_courses()
# elif num == 4:
# alex.show_students()
# 使用反射
# alex = Manager('alex')
# operate_lst = [('创建课程','create_course'),('创建学生账号','create_student'),
# ('查看所有课程','show_courses'),('查看所有学生','show_students')]
# for index,opt in enumerate(operate_lst,1):
# print(index,opt[0])
# num = input('请输入您要做的操作 :')
# if num.isdigit():
# num = int(num)
# if hasattr(alex,operate_lst[num-1][1]):
# getattr(alex,operate_lst[num-1][1])()

    4.3.2 使用模块反射   

import time
time.time() 调用函数和方法 地址+()
def func():
print(1) func()
a = func
a()
# 反射模块中的方法
import re
# ret = re.findall('\d+','2985urowhn0857023u9t4')
# print(ret)
# 'findall'
# getattr(re,'findall') # re.findall
# ret = getattr(re,'findall')('\d','wuhfa0y80aujeiagu')
# print(ret) # def func(a,b):
# return a+b # wahaha = func
# ret = wahaha(1,2)
# print(ret)

    4.3.3 使用类反射

      cls.静态变量名
      cls.类方法名()
      cls.静态方法名()

# 两种方式
# 对象名.属性名 / 对象名.方法名() 可以直接使用对象的方法和属性
# 当我们只有字符串数据类型的内容的时候
# getattr(对象名,'方法名')()
# getattr(对象名,'属性名')

    4.3.4 反射当前文件

# 反射本文件中的内容 :只要是出现在全局变量中的名字都可以通过getattr(modules[__name__],字符串数据类型的名字)
from sys import modules
# print(modules) # DICT KEY是模块的名字,value就是这个模块对应的文件地址 # import re
# print(re) # <module 're' from 'D:\\python3\\lib\\re.py'>
# print(modules['re'])
# 选课系统
# 're': <module 're' from 'D:\\python3\\lib\\re.py'>
# print(re.findall)
# print(modules['re'].findall) # a = 1
# b = 2
# while True:
# name = input('变量名 :')
# print(__name__)
# print(getattr(modules[__name__],name)) # '__main__': <module '__main__' from 'D:/PyCharmProject/s20/day23/5.反射.py'>
# print(a,b)
# print(modules['__main__'].a)
# print(modules['__main__'].b)
#
# print(getattr(modules['__main__'], 'a'))
# print(getattr(modules['__main__'], 'b'))

    4.3.5 总结

# hasattr和getattr
# 只要是a.b这种结构,都可以使用反射
# 用对象\类\模块反射,都只有以下场景
# 这种结构有两种场景
# a.b b是属性或者变量值
# getattr(a,'b') == a.b
# a.b() b是函数或者方法
# a.b()
# getattr(a,'b')()
# a.b(arg1,arg2)
# getattr(a,'b')(arg1,arg2)
# a.b(*args,**kwargs)
# getattr(a,'b')(*args,**kwargs)
# 如果是本文件中的内容,不符合a.b这种结构
# 直接调用func()
# getattr(sys.modules[__name__],'func')()
# 直接使用类名 Person()
# getattr(sys.modules[__name__],'Person')()
# 直接使用变量名 print(a)
# getattr(sys.modules[__name__],'a')
# 所有的getattr都应该和hasattr一起使用
# if hasattr():
getattr()
# setattr 只用来修改或者添加属性\变量,不能用来处理函数或者是其他方法
# a.b = value
# setattr(a,'b',value) # delattr 只用来删除 属性\变量
# del a.b 删除属性 相当于删除了a对象当中的b属性
# delattr(a,'b')

魔力Python——对象的更多相关文章

  1. python征程3.0(python对象)

    1.python使用对象模型来存储数据.构造任何类型的值都是一个对象.”尽管python被当成一种面向对象的脚本的编程语言“,但你完全能够写出不使用任何类和实例的脚本. python对象都拥有三个特性 ...

  2. python 对象

    python 对象 在python中,对象就是为C中的结构体在堆上申请的一块内存,一般来说,对象是不能被静态初始化的,并且不能再栈空间上生存.本文主要对Python的基本数据类型做简单的介绍. PyO ...

  3. Python 对象的引用计数和拷贝

    Python 对象的引用计数和拷贝 Python是一种面向对象的语言,包括变量.函数.类.模块等等一切皆对象. 在python中,每个对象有以下三个属性: 1.id,每个对象都有一个唯一的身份标识自己 ...

  4. Python对象(译)

    这是一篇我翻译的文章,确实觉得原文写的非常好,简洁清晰 原文链接:http://effbot.org/zone/python-objects.htm ------------------------- ...

  5. 《Python核心编程》 第四章 Python对象- 课后习题

    练习 4-1. Python对象.与所有Python对象有关的三个属性是什么?请简单的描述一下. 答:身份.类型和值: 身份:每一个对象都有一个唯一的身份标识自己,可以用id()得到.  类型:对象的 ...

  6. Python对象体系揭秘

    Guido用C语言创造了Python,在Python的世界中一切皆为对象. 一.C视角中的Python对象 让我们一起追溯到源头,Python由C语言实现,且向外提供了C的API http://doc ...

  7. 【2】python核心编程 第四章-python对象

    1.python对象 所有的Python 对像都拥有三个特性:身份,类型和值. 身份: 每一个对象都有一个唯一的身份标识自己,任何对象的身份可以使用内建函数id()来得到. 这个值可以被认为是该对象的 ...

  8. python学习笔记:python对象

    一.python对象 python使用对象模型来存储数据,构造任何类型的值都是一个对象.所有的python对象都拥有三个特性:身份.类型和值. 身份:每个对象都有一个唯一的身份标识自己,对象的身份可以 ...

  9. Python对象类型及其运算

    Python对象类型及其运算 基本要点: 程序中储存的所有数据都是对象(可变对象:值可以修改 不可变对象:值不可修改) 每个对象都有一个身份.一个类型.一个值 例: >>> a1 = ...

随机推荐

  1. 网页真机调试之Browsersync简介

    以前的调试方式 修改完项目文件(html.js.css等)后保存,在浏览器刷新页面查看修改后的效果 本地开启一个 tomcat 服务,修改文件后保存刷新页面,移动端或其他 pc 则需要输入 ip + ...

  2. Django Admin初识

    一.网站后台的作用 网站后台通常是相对于动态网站而言,即网站建设是基于数据库驱动的网站.网站后台,有时也称为网站管理后台,是指用于管理网站前台的一些列操作,如:产品.企业 信息的增加.更新.删除等.通 ...

  3. Python实例之抓取HTML中的数据并保存为TXT

    本实例实现了抓取捧腹网中存储于html中的笑话数据(非JSON数据) 通过浏览器相关工具发现捧腹网笑话页面的数据存储在HTML页面而非json数据中,因此可以直接使用soup.select()方法来抓 ...

  4. return,break,continue三者区别

    详解:http://www.cnblogs.com/yangdabao/p/6172210.html return:直接结束这个方法,后面所有代码不再执行,不管循坏外,还是循环内,全部停止,直接返回 ...

  5. 百度ip定位城市接口调用

    http://lbsyun.baidu.com/index.php?title=webapi/ip-api require 'rubygems' require 'json' print ARGV p ...

  6. Golang之接口

  7. Adventure 魔幻历险

    发售年份 1979 平台 VCS 开发商 雅达利(Atari) 类型 冒险 https://www.youtube.com/watch?v=YS-HYWRdb2g

  8. 2019年3月更新 技术分享 WPF基本界面制作

    1.制作流程1.在vs中建立一个wpf程序2.建立一个主页面(.cs)(注:C#程序每一个页面都由两个文件构成一个xaml一个cs,一个前端文件一个后台文件)3.在主页面中添加按钮,按钮中嵌入图片,这 ...

  9. 阅读ug949-vivado-design-methodology笔记

    阅读ug949-vivado-design-methodology笔记 xilinx更加推荐使用同步复位 怎样去设计时钟使能信号

  10. 申请Let's Encrypt永久免费SSL证书

    Let's Encrypt简介 Let's Encrypt作为一个公共且免费SSL的项目逐渐被广大用户传播和使用,是由Mozilla.Cisco.Akamai.IdenTrust.EFF等组织人员发起 ...