首页 > python属性访问和方法调用是不是不一样

python属性访问和方法调用是不是不一样

我在知乎上看到篇有关如何学习python的文章,里面提到属性访问和方法调用是不一样的,但是并没有深入讲。百度好像没有太好的答案,所以上来问问!有人可以讲讲是怎么回事吗?感谢


考察下面这个简单的例子:

class Person(object):
    
    def __init__(self):
        self._name = None
    
    def get_name(self):  # 这是方法
        if not self._name:
            raise RuntimeError('no name')
        return self._name
    
    def set_name(self, name):  # 这还是方法
        if not name:
            raise ValueError('name should not be empty')
        self._name = name
    
    # 定义了名为 name 的属性
    name = property(get_name, set_name)  

我们可以使用方法或属性来操作:

>>> p = Person()
>>> p.name
...
RuntimeError: no name

可以看到用属性的方式访问,还是调用了 get_name() 方法,这和:

>>> p.get_name()
...
RuntimeError: no name

是一样的。同样,我们使用方法和属性两种方式操作:

>>> p.name = 'mike'
>>> p.get_name()
'mike'
>>> p.name
'mike'
>>> p.name = 'peter'
>>> p.name
'peter'
>>> p.name = ''
...
ValueError: name should not be empt

可以看到,实际上为 p.name 赋值时,调用了 set_name() 方法。


下面的文章写的非常好:

Python Attributes and Methods


首先,我们要明白,什么是属性,什么是方法。下面看一个例子:

# -*- coding:utf8 -*-
a = 1
b = 2

def 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时),这时候就会返回我们设置的默认值。
以上,手打,欢迎指正。

【热门文章】
【热门文章】