魔力Python——对象
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. 面向对象:继承,多态,封装
初入对象,感觉的确挺有意思,凡事都是那么简单的感觉,上帝视角,随意调用人物属性,随意设置任务动作,那滋味简直不要太爽!!!
然而,记得一个公式:痛苦==有益,爽==有害.一旦只沉迷于这种感觉,很容易不思进取,因为再往下就会感觉有些难度了.
图中虚线代表实例关系,实线表示继承关系,从这个图中得出几点:
list、str、dict、tuple、type都继承了object,所以object是最顶层的基类
type是本身的对象(实例),object、list、str、dict、tuple都是type的对象,所以type创建了所有的对象
综合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——对象的更多相关文章
- python征程3.0(python对象)
1.python使用对象模型来存储数据.构造任何类型的值都是一个对象.”尽管python被当成一种面向对象的脚本的编程语言“,但你完全能够写出不使用任何类和实例的脚本. python对象都拥有三个特性 ...
- python 对象
python 对象 在python中,对象就是为C中的结构体在堆上申请的一块内存,一般来说,对象是不能被静态初始化的,并且不能再栈空间上生存.本文主要对Python的基本数据类型做简单的介绍. PyO ...
- Python 对象的引用计数和拷贝
Python 对象的引用计数和拷贝 Python是一种面向对象的语言,包括变量.函数.类.模块等等一切皆对象. 在python中,每个对象有以下三个属性: 1.id,每个对象都有一个唯一的身份标识自己 ...
- Python对象(译)
这是一篇我翻译的文章,确实觉得原文写的非常好,简洁清晰 原文链接:http://effbot.org/zone/python-objects.htm ------------------------- ...
- 《Python核心编程》 第四章 Python对象- 课后习题
练习 4-1. Python对象.与所有Python对象有关的三个属性是什么?请简单的描述一下. 答:身份.类型和值: 身份:每一个对象都有一个唯一的身份标识自己,可以用id()得到. 类型:对象的 ...
- Python对象体系揭秘
Guido用C语言创造了Python,在Python的世界中一切皆为对象. 一.C视角中的Python对象 让我们一起追溯到源头,Python由C语言实现,且向外提供了C的API http://doc ...
- 【2】python核心编程 第四章-python对象
1.python对象 所有的Python 对像都拥有三个特性:身份,类型和值. 身份: 每一个对象都有一个唯一的身份标识自己,任何对象的身份可以使用内建函数id()来得到. 这个值可以被认为是该对象的 ...
- python学习笔记:python对象
一.python对象 python使用对象模型来存储数据,构造任何类型的值都是一个对象.所有的python对象都拥有三个特性:身份.类型和值. 身份:每个对象都有一个唯一的身份标识自己,对象的身份可以 ...
- Python对象类型及其运算
Python对象类型及其运算 基本要点: 程序中储存的所有数据都是对象(可变对象:值可以修改 不可变对象:值不可修改) 每个对象都有一个身份.一个类型.一个值 例: >>> a1 = ...
随机推荐
- Mybatis:resultMap的使用总结
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中. resultMap包含的元素: <!--column不做限制,可以为任意 ...
- 1-Two Sum @LeetCode
1-Two Sum 题目 思路 题目中得到的信息有: 都是整数,并且可正可负,也可一个值包含多个: 只有一个正确的结果. 方法一: 最直接的思路就是两重循环遍历,时间复杂度是O(n^2),这样肯定不行 ...
- IMPALA部署和架构(一)
IMPALA部署和架构(一) 一,概要 因公司业务需求,需要一个查询引擎满足快速查询TB级别的数据,所以我们找到了presto和impala,presto在前面讲过今天只说impala,impala ...
- JS 实现Table相同行的单元格自动合并示例代码
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD ...
- c# BackgroundWorker初试
/* * Created by SharpDevelop. * User: Administrator * Date: 2017/7/31 * Time: 16:18 * * To change th ...
- [转]Linux中python3.6+ipython+Jupyter Notebook环境
python3.6安装 下载python安装包,这里下载的最新的3.6.1版本 https://www.python.org/ftp/python/3.6.1/ 将安装包上传到服务器并解压 tar z ...
- django 防止xss攻击标记为安全的二种方法
str='<a href="/page?page=1">1</a>' 一,在前端模板语言中实现,只须用到帮助函数safe.如: {{ str|safe }} ...
- webpack打包vue -->简易讲解
### 1. 测试环境: 推荐这篇文章:讲的很细致 https://www.cnblogs.com/lhweb15/p/5660609.html 1. webpack.config.js自行安装 { ...
- 利用Clang(Python接口)来解析C++
1 背景说明 最近希望利用开源库来解析C++头文件,并做一些自动翻译.自动注释之类的工作.经过两天的调研,发现clang最有希望满足需求.clang提供了三套接口来共外部使用,liblang最适合作为 ...
- 安卓APP环境搭建
https://www.cocos.com/creator 下载2.0.8 安装的时候选择原生环境 下载SDK:http://tools.android-studio.org/index.php/sd ...