1. 程式人生 > >python __slots__和@property

python __slots__和@property

前面瞭解了python的面向物件的基本方式https://blog.csdn.net/qq_21294095/article/details/85118247

心中有挺多的疑問,而解決這些疑問就需要用到python更強大的功能了


一,動態繫結這個事兒太隨意了,怎麼限制?

__slots__屬性可以用來限制動態繫結可以繫結的屬性,哪怕是在類內部,也要遵守這個規定。

class Animal(object):
    __slots__ = ('name', 'age')

    def __init__(self, name, legs):
        self.name = name
        self.legs = legs

animal = Animal('佩奇',4)
print(animal.legs)

Output:
AttributeError: 'Animal' object has no attribute 'legs'

可以看到,因為初始化的時候綁定了__slots__沒有指定的屬性legs,所以出錯。

需要注意:

__slots__會被子類繼承過去,但是子類自己的__slots__沒有做限制,所以父類的__slots__對子類就起不了作用。

class Animal(object):
    __slots__ = ('name', 'age')

    def __init__(self, name):
        self.name = name

class Dog(Animal):
    pass

dog = Dog('八公')
dog.legs = 4
print(dog.legs)

Output:
4

需要在子類也指定__slots__, 然後子類的屬性限定就是父類的並上自己的__slots__

class Animal(object):
    __slots__ = ('name', 'age')

    def __init__(self, name):
        self.name = name

class Dog(Animal):
    __slots__ = ('size')
    pass

dog = Dog('八公')
dog.legs = 4
print(dog.legs)

Output:
AttributeError: 'Dog' object has no attribute 'legs'

二,python中的setter和getter

給類建立了屬性之後,用封裝的思想,那麼就需要提供setter和getter方法。python可以想常規的那樣提供這兩個方法:

class Animal(object):

    def getName(self):
        return self.name

    def setName(self, name):
        if isinstance(name, str): #這裡簡單模擬一下設定值的時候的限制 只有是str才可以設定
            self.name = name
        else:
            self.name = '預設名稱'

animal = Animal()

animal.setName(300)
print(animal.getName())
animal.setName('三毛')
print(animal.getName())

Output:
預設名稱
三毛

其實沒什麼問題,就是呼叫的時候有些麻煩。而python是個追求簡單完美的語言,那麼麻煩就不能允許。於是python就提供了一個裝飾器@property來避免這個麻煩

class Animal(object):

    @property
    def getName(self):
        return self.name

    @getName.setter
    def setName(self, name):
        if isinstance(name, str): #這裡簡單模擬一下設定值的時候的限制 只有是str才可以設定
            self.name = name
        else:
            self.name = '預設名稱'

animal = Animal()

animal.setName = 300
print(animal.getName)
animal.setName = '三毛'
print(animal.getName)

Output:
預設名稱
三毛

這裡只做了簡單的修改,可以看到,setter和getter兩個方法名都被裝飾器變成了屬性,並且由於是裝飾器,所以原有的功能都保留了下來。看到這裡,你肯定會說,這有什麼用?感覺程式碼變得更難以理解了。不急,繼續修改下去:

class Animal(object):

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        if isinstance(name, str): #這裡簡單模擬一下設定值的時候的限制 只有是str才可以設定
            self.__name = name
        else:
            self.__name = '預設名稱'

animal = Animal()

animal.name = 300
print(animal.name)
animal.name = '三毛'
print(animal.name)

Output:
預設名稱
三毛

怎麼樣?這下程式碼是不是特別清晰,然而實際上就是把setter和getter方法過載,這樣就有一樣的函式名,接著把真正需要的屬性__私有化,(當然這個私有化前文說過,你有辦法去訪問)而已。如果直接上這段程式碼,會體會不到@property到底做了哪些事情,那麼它做了哪些事情?

  1. @property 把getter方法變成屬性 並且建立了另一個裝飾器:@屬性.setter
  2. @屬性.setter 把setter方法變成屬性