## 属性的类型
- 属性可分为类属性和实例属性
- 实例属性可以通过在类中使用self定义,或者直接在类外部使用实例变量定义
1 class Person(object): 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 7 per1 = Person("Stanley", 22) 8 print(per1.name) # 输出:Stanley 9 per1.weight = "50kg" 10 print(per1.weight) # 输出:50kg
- 类属性则直接在类中定义
- 类属性通过类名访问,也可以通过实例访问
1 class Person(object): 2 class_name = "Person" 3 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 8 9 per1 = Person("Stanley", 22) 10 print(per1.class_name) # 输出:Person 11 12 print(Person.class_name) # 输出:Person
- 注意:
- 如果实例属性和类属性使用了相同的名字,则实例化后实例属性将覆盖类属性,实例将无法在访问该同名类属性,而通过类名访问类属性将不受影响
1 class Person(object): 2 name = "Person" 3 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 8 9 print(Person.name) # 输出:Person 10 11 per1 = Person("Stanley", 22) 12 print(per1.name) # 输出:Stanley 13 print(Person.name) # 输出:Person
## 方法的类型
- 在一个类中可以存在三种类型的方法
- 在类的定义中,以self(即实例本身)作为第一个参数的方法为实例方法
1 class Person(object): 2 3 def __init__(self, name, age): 4 self.name = name 5 self.age = age 6 7 # 这是一个实例方法,self为实例本身,作为第一个参数传入,通过实例调用 8 def eat(self): 9 print("I'm %s, I want to eat!" % self.name) 10 11 12 per1 = Person("Stanley", 22) 13 per1.eat() # 输出:I'm Stanley, I want to eat!
- 在类的内部定义,用修饰符@classmethod指定的方法是类方法
- 类方法会作用于整个类,该方法对类做出的改变会影响该类的所有实例
- 与实例方法类似,类方法的第一个参数是类本身,通常写作cls
class Person(object): count = 0 def __init__(self, name, age): self.name = name self.age = age Person.count += 1 # 每实例化一个对象,count加1 # 这是一个实例方法,self作为第一个参数传入,通过实例调用 def eat(self): print("I'm %s, I want to eat!" % self.name) @classmethod # 使用@classmethod修饰 def kids(cls): # 第一个参数为类本身,这是一个类方法 print("class %s has %d instance(es)." % (cls.__name__, Person.count)) per1 = Person("Stanley", 22) per2 = Person("Bob", 18) per3 = Person("Lily", 17) Person.kids() # 输出:class Person has 3 instance(es).
- 第三种方法类型称为静态方法
- 静态方法使用@staticmethod修饰,它不需要self参数或者cls参数
- 静态方法的存在不会影响类也不会影响类的实例,仅仅是为了代码的逻辑性
- 静态方法可以通过类名或者实例调用
1 class Person(object): 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 @staticmethod 7 def say_hi(): 8 print("I'm a static method. I say Hi.") 9 10 11 per1 = Person("Stanley", 22) 12 per1.say_hi() # 输出:I'm a static method. I say Hi. 13 Person.say_hi() # 输出:I'm a static method. I say Hi.
## 使用property对attribute进行访问和设置
- 对于一些语言比如Java来说,对于私有属性的访问需要使用setter和getter方法
- Python不需要,因为Python所有属性都是公开的,但是也可以编写setter和getter限制对属性的访问
1 class Person(object): 2 def __init__(self, name, age): 3 self.__name = name # 私有属性 4 self.age = age 5 6 def set_name(self, name): 7 self.__name = name 8 9 def get_name(self): 10 return self.__name 11 12 13 per1 = Person("Stanley", 22) 14 print(per1.get_name()) # 输出:Stanley 15 per1.set_name("Lily") # 修改属性值 16 print(per1.get_name()) # 输出:Lily 17 print(per1.__name) # 无法直接访问私有属性,AttributeError: 'Person' object has no attribute '__name'
- 以上写法达到了限制访问的目的
- 但更Pythonic的写法是使用property()
1 class Person(object): 2 def __init__(self, name, age): 3 self.__name = name 4 self.age = age 5 6 def set_name(self, name): 7 self.__name = name 8 9 def get_name(self): 10 return self.__name 11 12 # 使用property函数将getter和setter定义为了name属性 13 name = property(get_name, set_name) 14 15 16 per1 = Person("Stanley", 22) 17 print(per1.name) # 访问属性时自动调用getter方法,输出:Stanley 18 per1.name = "Lily" # 设置属性时自动调用setter方法 19 print(per1.name) # 输出:Lily 20 print(per1.get_name()) # 也可以显式的调用getter或者setter方法
- 还有一种方法进行访问限制,那么就是使用修饰符,并定义两个同名方法
1 class Person(object): 2 def __init__(self, name, age): 3 self.__name = name 4 self.age = age 5 6 @property # @property 用于指示getter方法 7 def name(self): # 两个同名函数 8 return self.__name 9 10 @name.setter # @name.setter 用于指示setter方法 11 def name(self, name): # 两个同名函数 12 if isinstance(name, str): 13 self.__name = name 14 else: 15 raise TypeError("Name must be string!") 16 17 18 per1 = Person("Stanley", 22) 19 print(per1.name) # 输出:Stanley 20 per1.name = "Lily" 21 print(per1.name) # 输出:Lily
- 使用了@property修饰的方法就变成了属性
1 import datetime 2 3 4 class Person(object): 5 def __init__(self, name, age): 6 self.__name = name 7 self.age = age 8 9 @property 10 def birth_year(self): 11 return datetime.datetime.now().year - self.age 12 13 14 per1 = Person("Stanley", 22) 15 print(per1.birth_year) # 输出:1996 16 per1.birth_year = 2000 # 没有指定setter属性(@birth_year.setter),所以无法从外部对它的值进行设置,这使得这个birth_year这个属性成为只读属性
本文参考:
[美]Bill Lubanovic 《Python语言及其应用》