python访问函数属性 python函数访问全局变量

Python基础之查看Python库、函数和模块1.dir函数式可以查看对象的属性
使用方法很简单,举os类型为例,在Python命令窗口输入 dir(‘os’) 即可查看os模块的属性
打开cmd命令窗口:
2.如何查看对象某个属性的帮助文档:两种方法如下:
3.如何查看某个对象的详细:
3.如何查看某个对象的函数:
Python调用函数问题?content是个Response对象的属性 (有点类似变量),而decode是bytes的一个方法
方法在使用(调用/执行)的时候是需要加括号的,如果不加括号就会返回这个方法本身(类似函数指针), 而变量/成员字段/属性是不能加括号的(除非它实现了__call__()方法)
核心解密Python函数在(类与函数之间)和(类与类之间)互相调用 首先来看一个函数间的调用
类方法:
执行结果:
metaclass能有什么用处 , 先来个感性的认识:
1.1 在wiki上面,metaclass是这样定义的:In object-oriented programming,
a metaclass is a class whose instances are classes.
Just as an ordinary class defines the behavior of certain objects,
a metaclass defines the behavior of certain classes and their instances.
也就是说metaclass的实例化结果是类,而class实例化的结果是instance 。我是这么理解的:
metaclass是类似创建类的模板,所有的类都是通过他来create的(调用 new ),这使得你可以自由的控制
创建类的那个过程,实现你所需要的功能 。
当然你也可以用函数的方式(下文会讲)
4.1 用类的形式
4.1.1 类继承于type, 例如: class Meta(type):pass
4.1.2 将需要使用metaclass来构建class的类的 metaclass 属性(不需要显示声明,直接有的了)赋值为Meta(继承于type的类)
4.2 用函数的形式
4.2.1 构建一个函数,例如叫metaclass_new, 需要3个参数:name, bases, attrs,
name: 类的名字
bases: 基类,通常是tuple类型
attrs: dict类型,就是类的属性或者函数
4.2.2 将需要使用metaclass来构建class的类的 metaclass 属性(不需要显示声明,直接有的了)赋值为函数metaclas_new
5.1 basic
metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了type的 new 方法为这个类分配内存空间,创建
好了之后再调用type的 init 方法初始化(做一些赋值等) 。所以metaclass的所有magic其实就在于这个 new 方法里面了 。
说说这个方法: new (cls, name, bases, attrs)
cls: 将要创建的类,类似与self,但是self指向的是instance,而这里cls指向的是class
name: 类的名字 , 也就是我们通常用类名. name 获取的 。
bases: 基类
attrs: 属性的dict 。dict的内容可以是变量(类属性),也可以是函数(类方法) 。
所以在创建类的过程,我们可以在这个函数里面修改name,bases,attrs的值来自由的达到我们的功能 。这里常用的配合方法是
getattr和setattr(just an advice)
下面实现python中在一个类中调用另一个类的函数方法
或者下面来一个号理解的例子
执行结果:
先来介绍内部类与外部类是什么?
看源码解析:
内部类调用外部类的类属性和类方法
参考文献1
参考文献2
参考文献3
python属性访问和方法调用是不是不一样首先,我们要明白,什么是属性,什么是方法 。下面看一个例子:
# -*- coding:utf8 -*-a = 1b = 2def func():
print 'func'
class example(object):
first = 1 # 定义变量 first
second = “two”
def myfunc(self): # 定义函数
print "myfunc."
上面的简单例子中,a和b是属性么?不是,它们是全局变量(相对当前例子而言) 。func是方法么,不是 , 它是函数 。
attribute(属性)是class(类)中的成员变量,而method(方法)则是class(类)中的function(函数) 。也可以理解,属性就类变量,方法就是类函数 。那我们看看class example中的attribute 。
dir(eaxmple)
不用奇怪为何myfunc也在其中 , python一切皆为对象 , dir(object)会返回当前object的所有内建方法,属性等 。
类中的变量就是静态变量,类可以直接访问,而方法则必须要绑定instance(实例)才可以访问 。请记住Python是一门动态语言,任何实例都可以动态地添加或删除属性 。一个类定义了一个作用域,类实例也引入了一个作用域,这与对应类定义的作用域是不同的 。在类实例中查找属性的时候 , 首先在实例自己的作用域中查找,如果没有找到,则再去类定义的作用域中查找 。在对类实例属性进行赋值的时候,实际上会在类实例定义的作用域中添加一个属性或修改一个属性,但并不会影响到对应类中定义的同名属性 。
为了直观的感受实例访问属性和方法调用都做了什么,我们对代码进行了如下修改 。
class example(object):
first = 1 # 定义变量 first
second = "two"
def my_func(self): # 定义方法 my_func
print "This is my func."
def __getattribute__(self, *args, **kwargs):
print "__getattribute__ is called"
return object.__getattribute__(self, *args, **kwargs)def __getattr__(self, attrname):
print("__getattr__() is called ")
return attrname":This my exception deal."
def __setattr__(self, attrname, value):
print("__setattr__() is called")
return object.__setattr__(self, attrname, value)
首先,我们对类进行实例化 。
test = example()
我们先对属性进行访问
看来实例test访问属性通过了内建方法__getattribute__,那么我们再对访问类方法
我们发现内建方法__getattribute__再次被调用了 。所以,实例访问属性和调用方法,是没有区别的 。
拓展
我们又重写了__getattr__和__setattr__,那么这两个是干什么的呢 。
哦,原来对实例添加属性并赋值的时候,会调用__setattr__,而访问属性,还是老方法 。如果对没有的属性进行访问,就会抛出AttributeError,这时候,为了避免这种情况,__getattr__就派上了用处 。
首先访问属性four,在实例作用域并没有找到,再去对应类的作用域,依然未找到,解释器就会抛出AttributeError,这时候__getattr__就会调用(当程序抛出Attribute时),这时候就会返回我们设置的默认值 。
Python中处理属性的重要属性和函数是什么处理属性的重要属性和函数
1、特殊属性
__class__:对象所属类的引用(即obj.__class__和type(obj)的作用相同) 。Python中的某些特殊方法比如 __getattr__,只在对象的类中寻找 , 而不在实例中寻找 。__dict__:一个映射,存储对象或类的可写属性 。__slots__:类可以定义这个属性,限制实例有哪些属性 。
2、内置函数
dir([object]):列出对象的大多数属性 。getattr(object,name[,default]):从object对象中获取name字符串对应的属性 。获取的属性可能来自对象所属的类或超类 。hasattr(object,name):若object对象中存在指定的属性,或者能以某种方式(如继承)通过object对象获取指定的属性,返回True 。setattr(object,name,value):把object对象指定属性的值设为value,前提是object对象能接受那个值 。这个函数可能会创建一个新属性,或者覆盖现有的属性 。var([object]):返回object对象的__dict__属性 。
相关推荐:《Python视频教程》
3、特殊方法
__delattr__(self,name):只要使用del语句删除属性,就会调用这个方法 。__dir__(self):把对象传给dir函数时调用,列出属性 。__getattr__(self,name):仅当获取指定的属性失败,搜索过obj,Class和超类之后调用 。__getattribute__(self,name):尝试获取指定的属性时总会调用这个方法 。不过寻找的属性是特殊属性或特殊方法时除外 。为了防止无限递归,__getattribute__方法的实现要使用super().__getattribute__(obj,name) 。__setattr__(self,name,value):尝试设置指定的属性时总会调用这个方法 。点号和setattr内置函数会触发这个方法 。
相关推荐:
Python中的属性和特性是什么
如何正确地使用Python的属性和描述符关于@property装饰器
在Python中我们使用@property装饰器来把对函数的调用伪装成对属性的访问 。
那么为什么要这样做呢?因为@property让我们将自定义的代码同变量的访问/设定联系在了一起,同时为你的类保持一个简单的访问属性的接口 。
举个栗子,假如我们有一个需要表示电影的类:
1
2
3
4
5
6
7
8
class Movie(object):
def __init__(self, title, description, score, ticket):
self.title = title
self.description = description
self.score = scroe
self.ticket = ticket
你开始在项目的其他地方使用这个类 , 但是之后你意识到:如果不小心给电影打了负分怎么办?你觉得这是错误的行为,希望Movie类可以阻止这个错误 。你首先想到的办法是将Movie类修改为这样:
Python
1
2
3
4
5
6
7
8
class Movie(object):
def __init__(self, title, description, score, ticket):
self.title = title
self.description = description
self.ticket = ticket
if score0:
raise ValueError("Negative value not allowed:{}".format(score))
self.score = scroe
但这行不通 。因为其他部分的代码都是直接通过Movie.score来赋值的 。这个新修改的类只会在__init__方法中捕获错误的数据,但对于已经存在的类实例就无能为力了 。如果有人试着运行m.scrore= -100,那么谁也没法阻止 。那该怎么办?
Python的property解决了这个问题 。
我们可以这样做
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Movie(object):
def __init__(self, title, description, score):
self.title = title
self.description = description
【python访问函数属性 python函数访问全局变量】self.score = score
self.ticket = ticket
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score0:
raise ValueError("Negative value not allowed:{}".format(score))
self.__score = score
@score.deleter
def score(self):
raise AttributeError("Can not delete score")
这样在任何地方修改score都会检测它是否小于0 。
property的不足
对property来说,最大的缺点就是它们不能重复使用 。举个例子 , 假设你想为ticket字段也添加非负检查 。下面是修改过的新类:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Movie(object):
def __init__(self, title, description, score, ticket):
self.title = title
self.description = description
self.score = score
self.ticket = ticket
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score0:
raise ValueError("Negative value not allowed:{}".format(score))
self.__score = score
@score.deleter
def score(self):
raise AttributeError("Can not delete score")
@property
def ticket(self):
return self.__ticket
@ticket.setter
def ticket(self, ticket):
if ticket0:
raise ValueError("Negative value not allowed:{}".format(ticket))
self.__ticket = ticket
@ticket.deleter
def ticket(self):
raise AttributeError("Can not delete ticket")
可以看到代码增加了不少,但重复的逻辑也出现了不少 。虽然property可以让类从外部看起来接口整洁漂亮,但是却做不到内部同样整洁漂亮 。
描述符登场
什么是描述符?
一般来说,描述符是一个具有绑定行为的对象属性,其属性的访问被描述符协议方法覆写 。这些方法是__get__()、__set__()和__delete__(),一个对象中只要包含了这三个方法中的至少一个就称它为描述符 。
描述符有什么作用?
The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting witha.__dict__[‘x’], then type(a).__dict__[‘x’], and continuing through the base classes of type(a) excluding metaclasses. If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined.—–摘自官方文档
简单的说描述符会改变一个属性的基本的获取、设置和删除方式 。
先看如何用描述符来解决上面 property逻辑重复的问题 。
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Integer(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if value0:
raise ValueError("Negative value not allowed")
instance.__dict__[self.name] = value
class Movie(object):
score = Integer('score')
ticket = Integer('ticket')
因为描述符优先级高并且会改变默认的get、set行为,这样一来,当我们访问或者设置Movie().score的时候都会受到描述符Integer的限制 。
不过我们也总不能用下面这样的方式来创建实例 。
a = Movie()
a.score = 1
a.ticket = 2
a.title = ‘test’
a.descript = ‘…’
这样太生硬了 , 所以我们还缺一个构造函数 。
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Integer(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if value0:
raise ValueError('Negative value not allowed')
instance.__dict__[self.name] = value
class Movie(object):
score = Integer('score')
ticket = Integer('ticket')
def __init__(self, title, description, score, ticket):
self.title = title
self.description = description
self.score = score
self.ticket = ticket
这样在获取、设置和删除score和ticket的时候都会进入Integer的__get__、__set__,从而减少了重复的逻辑 。
现在虽然问题得到了解决,但是你可能会好奇这个描述符到底是如何工作的 。具体来说,在__init__函数里访问的是自己的self.score和self.ticket,怎么和类属性score和ticket关联起来的?
描述符如何工作
看官方的说明
If an object defines both __get__() and __set__(), it is considered a data descriptor. Descriptors that only define __get__() are called non-data descriptors (they are typically used for methods but other uses are possible).
Data and non-data descriptors differ in how overrides are calculated with respect to entries in an instance’s dictionary. If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence.
The important points to remember are:
descriptors are invoked by the __getattribute__() method
overriding __getattribute__() prevents automatic descriptor calls
object.__getattribute__() and type.__getattribute__() make different calls to __get__().
data descriptors always override instance dictionaries.
non-data descriptors may be overridden by instance dictionaries.
类调用__getattribute__()的时候大概是下面这样子:
1
2
3
4
5
6
7
def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
下面是摘自国外一篇博客上的内容 。
Given a Class “C” and an Instance “c” where “c = C(…)”, calling “c.name” means looking up an Attribute “name” on the Instance “c” like this:
Get the Class from Instance
Call the Class’s special method getattribute__. All objects have a default __getattribute
Inside getattribute
Get the Class’s mro as ClassParents
For each ClassParent in ClassParents
If the Attribute is in the ClassParent’s dict
If is a data descriptor
Return the result from calling the data descriptor’s special method __get__()
Break the for each (do not continue searching the same Attribute any further)
If the Attribute is in Instance’s dict
Return the value as it is (even if the value is a data descriptor)
For each ClassParent in ClassParents
If the Attribute is in the ClassParent’s dict
If is a non-data descriptor
Return the result from calling the non-data descriptor’s special method __get__()
If it is NOT a descriptor
Return the value
If Class has the special method getattr
Return the result from calling the Class’s special method__getattr__.
我对上面的理解是,访问一个实例的属性的时候是先遍历它和它的父类,寻找它们的__dict__里是否有同名的data descriptor如果有,就用这个data descriptor代理该属性,如果没有再寻找该实例自身的__dict__ , 如果有就返回 。任然没有再查找它和它父类里的non-data descriptor,最后查找是否有__getattr__
描述符的应用场景
python的property、classmethod修饰器本身也是一个描述符,甚至普通的函数也是描述符(non-data discriptor)
django model和SQLAlchemy里也有描述符的应用
Python
1
2
3
4
5
6
7
8
9
10
11
12
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return 'User %r' % self.username
后记
只有当确实需要在访问属性的时候完成一些额外的处理任务时,才应该使用property 。不然代码反而会变得更加啰嗦,而且这样会让程序变慢很多 。
关于python访问函数属性和python函数访问全局变量的介绍到此就结束了 , 不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。

    推荐阅读